mediatek: update to latest kernel patchset from v4.13-rc
authorJohn Crispin <john@phrozen.org>
Fri, 18 Aug 2017 16:11:52 +0000 (18:11 +0200)
committerJohn Crispin <john@phrozen.org>
Fri, 18 Aug 2017 16:41:41 +0000 (18:41 +0200)
Signed-off-by: Muciri Gatimu <muciri@openmesh.com>
Signed-off-by: Shashidhar Lakkavalli <shashidhar.lakkavalli@openmesh.com>
Signed-off-by: John Crispin <john@phrozen.org>
119 files changed:
target/linux/mediatek/base-files/etc/board.d/02_network
target/linux/mediatek/base-files/etc/config/mtkhnat [new file with mode: 0644]
target/linux/mediatek/base-files/etc/init.d/mtkhnat [new file with mode: 0755]
target/linux/mediatek/base-files/etc/uci-defaults/99-firewall [new file with mode: 0755]
target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps [new file with mode: 0755]
target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow [new file with mode: 0644]
target/linux/mediatek/base-files/lib/upgrade/platform.sh
target/linux/mediatek/base-files/sbin/mtkhnat [new file with mode: 0755]
target/linux/mediatek/config-4.9
target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi
target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi [new file with mode: 0644]
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts
target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts
target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts [new file with mode: 0644]
target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/Makefile [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h [new file with mode: 0644]
target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c [new file with mode: 0644]
target/linux/mediatek/image/32.mk
target/linux/mediatek/modules.mk [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch [deleted file]
target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch [deleted file]
target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch [deleted file]
target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch [deleted file]
target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch [deleted file]
target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch [deleted file]
target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch [deleted file]
target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch [deleted file]
target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch [deleted file]
target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch [deleted file]
target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch [deleted file]
target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch [deleted file]
target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch [deleted file]
target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch [deleted file]
target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch [deleted file]
target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch [deleted file]
target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0059-eth-fixes.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch [deleted file]
target/linux/mediatek/patches-4.9/0083-mfd-led3.patch [deleted file]
target/linux/mediatek/patches-4.9/0085-pmic-led0.patch [deleted file]
target/linux/mediatek/patches-4.9/0086-pmic-led1.patch [deleted file]
target/linux/mediatek/patches-4.9/0087-pmic-led2.patch [deleted file]
target/linux/mediatek/patches-4.9/0088-pmic-led3.patch [deleted file]
target/linux/mediatek/patches-4.9/0091-dsa1.patch [deleted file]
target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch [deleted file]
target/linux/mediatek/patches-4.9/0092-dsa2.patch [deleted file]
target/linux/mediatek/patches-4.9/0092-dsa3.patch [deleted file]
target/linux/mediatek/patches-4.9/0092-dsa4.patch [deleted file]
target/linux/mediatek/patches-4.9/0092-dsa5.patch [deleted file]
target/linux/mediatek/patches-4.9/0093-dsa-compat.patch [deleted file]
target/linux/mediatek/patches-4.9/0094-net-affinity.patch [deleted file]
target/linux/mediatek/patches-4.9/0095-ephy.patch [deleted file]
target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch [deleted file]
target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch [deleted file]
target/linux/mediatek/patches-4.9/0103-nand_fixes.patch [deleted file]
target/linux/mediatek/patches-4.9/0200-devicetree.patch [deleted file]
target/linux/mediatek/patches-4.9/0201-block2mtd.patch [deleted file]

index 361771199f099ae53add773d0c57b95d628868f9..e071ab27a0f2a0e92b9b5ce785f532413222767b 100755 (executable)
@@ -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"
diff --git a/target/linux/mediatek/base-files/etc/config/mtkhnat b/target/linux/mediatek/base-files/etc/config/mtkhnat
new file mode 100644 (file)
index 0000000..a23bd1c
--- /dev/null
@@ -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
diff --git a/target/linux/mediatek/base-files/etc/init.d/mtkhnat b/target/linux/mediatek/base-files/etc/init.d/mtkhnat
new file mode 100755 (executable)
index 0000000..32011e7
--- /dev/null
@@ -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
+}
diff --git a/target/linux/mediatek/base-files/etc/uci-defaults/99-firewall b/target/linux/mediatek/base-files/etc/uci-defaults/99-firewall
new file mode 100755 (executable)
index 0000000..9a0dd9b
--- /dev/null
@@ -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
diff --git a/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps b/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps
new file mode 100755 (executable)
index 0000000..9267340
--- /dev/null
@@ -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
diff --git a/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow b/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow
new file mode 100644 (file)
index 0000000..9a84ff4
--- /dev/null
@@ -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
+
index 7e936c4dad8c508d01cbfcb129645f11efbb054f..7161a4b84ed9dad248436b221d1c6196528e1cf2 100755 (executable)
@@ -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`
diff --git a/target/linux/mediatek/base-files/sbin/mtkhnat b/target/linux/mediatek/base-files/sbin/mtkhnat
new file mode 100755 (executable)
index 0000000..fdfc842
--- /dev/null
@@ -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
index 2a49d947232ee189716f317d12bfad280f102820..9d15a7d631143acda56329933e46ffe2d27b98b0 100644 (file)
@@ -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
index 7093d3513179ef0e336d5052bb8ffdaecefdbb92..620ad95e766196631607e1314ddfaa6f2099b990 100644 (file)
@@ -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"
 
 
        };
 
        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;
                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";
                #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;
                status = "disabled";
        };
 
-       spi: spi@1100a000 {
+       spi0: spi@1100a000 {
                compatible = "mediatek,mt7623-spi",
                             "mediatek,mt6589-spi";
                reg = <0 0x1100a000 0 0x1000>;
                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";
                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";
                        #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>;
+       };
 };
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi b/target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi
new file mode 100644 (file)
index 0000000..7c783d6
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ * Author: John Crispin <john@phrozen.org>
+ *        Sean Wang <sean.wang@mediatek.com>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&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>;
+                       };
+               };
+       };
+};
index 1278b8bf0d050aad6e7b9b3c5def59b4107c329f..bcd2df264dd11b7df69de3bd89b00e69df5b17ec 100644 (file)
                                 <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;
index 6606176d4d6a80c06521470ecbdd0aba41e2b2f7..d9f08d015dab65109289ba877ad80bff217f9807 100644 (file)
                                 <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;
index be7bced254b1a6a31565eac1fd38dc6759d9e723..6f45ff6863b2c84d7fbf8b2bb44dca0dcecdb290 100644 (file)
                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 {
                                 <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>;
                };
 
 };
 
 &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";
diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts
new file mode 100644 (file)
index 0000000..a66956e
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2017 Sean Wang <sean.wang@mediatek.com>
+ *
+ * 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";
+};
diff --git a/target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c b/target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c
new file mode 100644 (file)
index 0000000..df8eb54
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Driver for Mediatek Hardware Random Number Generator
+ *
+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#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 <sean.wang@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/Makefile b/target/linux/mediatek/files/drivers/crypto/mediatek/Makefile
new file mode 100644 (file)
index 0000000..187be79
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mtk-crypto.o
+mtk-crypto-objs:= mtk-platform.o mtk-aes.o mtk-sha.o
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c
new file mode 100644 (file)
index 0000000..9e845e8
--- /dev/null
@@ -0,0 +1,1304 @@
+/*
+ * Cryptographic API.
+ *
+ * Driver for EIP97 AES acceleration.
+ *
+ * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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);
+}
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c
new file mode 100644 (file)
index 0000000..b6ecc28
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * Driver for EIP97 cryptographic accelerator.
+ *
+ * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#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 <ryder.lee@mediatek.com>");
+MODULE_DESCRIPTION("Cryptographic accelerator driver for EIP97");
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h
new file mode 100644 (file)
index 0000000..303c152
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Driver for EIP97 cryptographic accelerator.
+ *
+ * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#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_ */
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h
new file mode 100644 (file)
index 0000000..94f4eb8
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Support for MediaTek cryptographic accelerator.
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ */
+
+#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__ */
diff --git a/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c
new file mode 100644 (file)
index 0000000..2226f12
--- /dev/null
@@ -0,0 +1,1358 @@
+/*
+ * Cryptographic API.
+ *
+ * Driver for EIP97 SHA1/SHA2(HMAC) acceleration.
+ *
+ * Copyright (c) 2016 Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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);
+}
index 574bf9395e711180799fec55f05b185167440c07..ea1474dc854053d93840474d54452482358e6235 100644 (file)
@@ -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
diff --git a/target/linux/mediatek/modules.mk b/target/linux/mediatek/modules.mk
new file mode 100644 (file)
index 0000000..447ae11
--- /dev/null
@@ -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))
diff --git a/target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch b/target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch
deleted file mode 100644 (file)
index 282c28d..0000000
+++ /dev/null
@@ -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"),
diff --git a/target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch b/target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch
deleted file mode 100644 (file)
index 0e8ce0c..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From 1e021917e634b173d466bf0dd3d2ae84e51a77ff Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 27 Jul 2014 09:38:50 +0100
-Subject: [PATCH 001/102] NET: multi phy support
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- 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;
diff --git a/target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch b/target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch
new file mode 100644 (file)
index 0000000..ff04a9f
--- /dev/null
@@ -0,0 +1,23 @@
+From 9fdcf63545855f3a6f82dee109510f4735e861c8 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:54:13 +0200
+Subject: [PATCH 01/57] arch: arm: add dts build code
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch
deleted file mode 100644 (file)
index ce38640..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang@mediatek.com>
-Date: Thu, 20 Oct 2016 16:56:37 +0800
-Subject: [PATCH] soc: mediatek: Add MT2701 power dt-bindings
-
-Add power dt-bindings for MT2701.
-
-Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
-Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
-Acked-by: Rob Herring <robh@kernel.org>
-Reviewed-by: Kevin Hilman <khilman@baylibre.com>
-Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
----
- .../devicetree/bindings/soc/mediatek/scpsys.txt    | 13 +++++++----
- include/dt-bindings/power/mt2701-power.h           | 27 ++++++++++++++++++++++
- 2 files changed, 35 insertions(+), 5 deletions(-)
- create mode 100644 include/dt-bindings/power/mt2701-power.h
-
---- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
-+++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
-@@ -9,17 +9,20 @@ domain control.
- The driver implements the Generic PM domain bindings described in
- power/power_domain.txt. It provides the power domains defined in
--include/dt-bindings/power/mt8173-power.h.
-+include/dt-bindings/power/mt8173-power.h and mt2701-power.h.
- Required properties:
--- compatible: Must be "mediatek,mt8173-scpsys"
-+- compatible: Should be one of:
-+      - "mediatek,mt2701-scpsys"
-+      - "mediatek,mt8173-scpsys"
- - #power-domain-cells: Must be 1
- - reg: Address range of the SCPSYS unit
- - infracfg: must contain a phandle to the infracfg controller
- - clock, clock-names: clocks according to the common clock binding.
--                      The clocks needed "mm", "mfg", "venc" and "venc_lt".
--                    These are the clocks which hardware needs to be enabled
--                    before enabling certain power domains.
-+                      These are clocks which hardware needs to be
-+                      enabled before enabling certain power domains.
-+      Required clocks for MT2701: "mm", "mfg", "ethif"
-+      Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
- Optional properties:
- - vdec-supply: Power supply for the vdec power domain
---- /dev/null
-+++ b/include/dt-bindings/power/mt2701-power.h
-@@ -0,0 +1,26 @@
-+/*
-+ * Copyright (C) 2015 MediaTek Inc.
-+ *
-+ * This program is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H
-+#define _DT_BINDINGS_POWER_MT2701_POWER_H
-+
-+#define MT2701_POWER_DOMAIN_CONN      0
-+#define MT2701_POWER_DOMAIN_DISP      1
-+#define MT2701_POWER_DOMAIN_IFR_MSC   2
-+#define MT2701_POWER_DOMAIN_VDEC      3
-+#define MT2701_POWER_DOMAIN_ISP               4
-+#define MT2701_POWER_DOMAIN_BDP               5
-+#define MT2701_POWER_DOMAIN_ETH               6
-+#define MT2701_POWER_DOMAIN_HIF               7
-+
-+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
diff --git a/target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
new file mode 100644 (file)
index 0000000..9dd6fcd
--- /dev/null
@@ -0,0 +1,154 @@
+From ad2d4df46d8ef6a7aab20f0b668fa7db5257cbea Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 6 Jan 2016 21:55:10 +0100
+Subject: [PATCH 02/57] dt-bindings: add MediaTek PCIe binding documentation
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ .../devicetree/bindings/pci/mediatek-pcie.txt      | 140 +++++++++++++++++++++
+ 1 file changed, 140 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
+@@ -0,0 +1,140 @@
++Mediatek PCIe controller
++
++Required properties:
++- compatible: Should be one of:
++      - "mediatek,mt2701-pcie"
++      - "mediatek,mt7623-pcie"
++- device_type: Must be "pci"
++- reg: A list of physical base address and length for each set of controller
++  registers. A list of register ranges to use. Must contain an
++    entry for each entry in the reg-names property.
++- reg-names: Must include the following entries:
++  "pcie": PCIe registers
++  "pcie phy0": PCIe PHY0 registers
++  "pcie phy1": PCIe PHY0 registers
++  "pcie phy2": PCIe PHY0 registers
++- interrupts: A list of interrupt outputs of the controller. Must contain an
++  entry for each entry in the interrupt-names property.
++- interrupt-names: Must include the following entries:
++  "pcie0": The interrupt that is asserted for port0
++  "pcie1": The interrupt that is asserted for port1
++  "pcie2": The interrupt that is asserted for port2
++- bus-range: Range of bus numbers associated with this controller
++- #address-cells: Address representation for root ports (must be 3)
++- #size-cells: Size representation for root ports (must be 2)
++- ranges: Describes the translation of addresses for root ports and standard
++  PCI regions. The entries must be 6 cells each.
++  Please refer to the standard PCI bus binding document for a more detailed
++  explanation.
++- #interrupt-cells: Size representation for interrupts (must be 1)
++- clocks: Must contain an entry for each entry in clock-names.
++  See ../clocks/clock-bindings.txt for details.
++- clock-names: Must include the following entries:
++  - pcie0
++  - pcie1
++  - pcie2
++- resets: Must contain an entry for each entry in reset-names.
++  See ../reset/reset.txt for details.
++- reset-names: Must include the following entries:
++  - pcie0
++  - pcie1
++  - pcie2
++- mediatek,hifsys: Must contain a phandle to the HIFSYS syscon range.
++Root ports are defined as subnodes of the PCIe controller node.
++
++Required properties:
++- device_type: Must be "pci"
++- assigned-addresses: Address and size of the port configuration registers
++- reg: PCI bus address of the root port
++- #address-cells: Must be 3
++- #size-cells: Must be 2
++- ranges: Sub-ranges distributed from the PCIe controller node. An empty
++  property is sufficient.
++
++Example:
++
++SoC DTSI:
++
++      hifsys: clock-controller@1a000000 {
++              compatible = "mediatek,mt7623-hifsys",
++                           "mediatek,mt2701-hifsys",
++                           "syscon";
++              reg = <0 0x1a000000 0 0x1000>;
++              #clock-cells = <1>;
++              #reset-cells = <1>;
++      };
++
++      pcie-controller@1a140000 {
++              compatible = "mediatek,mt7623-pcie";
++              device_type = "pci";
++              reg = <0 0x1a140000 0 0x8000>, /* PCI-Express registers */
++                    <0 0x1a149000 0 0x1000>, /* PCI-Express PHY0 */
++                    <0 0x1a14a000 0 0x1000>, /* PCI-Express PHY1 */
++                    <0 0x1a244000 0 0x1000>; /* PCI-Express PHY2 */
++              reg-names = "pcie", "pcie phy0", "pcie phy1", "pcie phy2";
++              interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>,
++                           <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>,
++                           <GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
++              interrupt-names = "pcie0", "pcie1", "pcie2";
++              clocks = <&topckgen CLK_TOP_ETHIF_SEL>;
++              clock-names = "pcie";
++              power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
++              resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>,
++                       <&hifsys MT2701_HIFSYS_PCIE1_RST>,
++                       <&hifsys MT2701_HIFSYS_PCIE2_RST>;
++              reset-names = "pcie0", "pice1", "pcie2";
++
++              bus-range = <0x00 0xff>;
++              #address-cells = <3>;
++              #size-cells = <2>;
++
++                mediatek,hifsys = <&hifsys>;
++
++              ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* io space */
++                        0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* pci memory */
++
++              status = "disabled";
++
++              pcie@1,0 {
++                      device_type = "pci";
++                      reg = <0x0800 0 0 0 0>;
++
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      ranges;
++
++                      status = "disabled";
++              };
++
++              pcie@2,0{
++                      device_type = "pci";
++                      reg = <0x1000 0 0 0 0>;
++
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      ranges;
++
++                      status = "disabled";
++              };
++
++              pcie@3,0{
++                      device_type = "pci";
++                      reg = <0x1800 0 0 0 0>;
++
++                      #address-cells = <3>;
++                      #size-cells = <2>;
++                      ranges;
++
++                      status = "disabled";
++              };
++      };
++
++Board DTS:
++
++      pcie-controller {
++              status = "okay";
++
++              pci@1,0 {
++                      status = "okay";
++              };
++      };
diff --git a/target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
new file mode 100644 (file)
index 0000000..43f51ef
--- /dev/null
@@ -0,0 +1,698 @@
+From 950bd9b0691dd10209c333086a6bdda0108ed3a8 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 5 Jan 2016 20:20:04 +0100
+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
+a single Root complex (RC) with 3 Root Ports. The SoCs supports a Gen2
+1-lan Link on each port.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ 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
+@@ -25,6 +25,7 @@ config MACH_MT6592
+ config MACH_MT7623
+       bool "MediaTek MT7623 SoCs support"
+       default ARCH_MEDIATEK
++      select MIGHT_HAVE_PCI
+ config MACH_MT8127
+       bool "MediaTek MT8127 SoCs support"
+--- a/drivers/pci/host/Kconfig
++++ b/drivers/pci/host/Kconfig
+@@ -301,4 +301,15 @@ config VMD
+         To compile this driver as a module, choose M here: the
+         module will be called vmd.
++config PCIE_MTK
++      bool "Mediatek PCIe Controller"
++      depends on MACH_MT2701 || MACH_MT7623
++      depends on OF
++      depends on PCI
++      help
++        Say Y here if you want to enable PCI controller support on Mediatek MT7623.
++        MT7623 PCIe supports single Root complex (RC) with 3 Root Ports.
++        Each port supports a Gen2 1-lan Link.
++        PCIe include one Host/PCI bridge and 3 PCIe MAC.
++
+ endmenu
+--- a/drivers/pci/host/Makefile
++++ b/drivers/pci/host/Makefile
+@@ -33,3 +33,4 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-arm
+ obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
+ obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
+ obj-$(CONFIG_VMD) += vmd.o
++obj-$(CONFIG_PCIE_MTK) += pcie-mediatek.o
+--- /dev/null
++++ b/drivers/pci/host/pcie-mediatek.c
+@@ -0,0 +1,641 @@
++/*
++ *  Mediatek MT2701/MT7623 SoC PCIE support
++ *
++ *  Copyright (C) 2015 Mediatek
++ *  Copyright (C) 2015 Ziv Huang <ziv.huang@mediatek.com>
++ *  Copyright (C) 2015 John Crispin <blogic@openwrt.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <asm/irq.h>
++#include <asm/mach/pci.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_pci.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++#include <linux/reset.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include <linux/pm_runtime.h>
++#include <linux/clk.h>
++#include <linux/regmap.h>
++#include <linux/mfd/syscon.h>
++
++#define MEMORY_BASE                   0x80000000
++
++/* PCIE Registers */
++#define PCICFG                                0x00
++#define PCIINT                                0x08
++#define PCIENA                                0x0c
++#define CFGADDR                               0x20
++#define CFGDATA                               0x24
++#define MEMBASE                               0x28
++#define IOBASE                                0x2c
++
++/* per Port Registers */
++#define BAR0SETUP                     0x10
++#define IMBASEBAR0                    0x18
++#define PCIE_CLASS                    0x34
++#define PCIE_SISTAT                   0x50
++
++#define MTK_PCIE_HIGH_PERF            BIT(14)
++#define PCIEP0_BASE                   0x2000
++#define PCIEP1_BASE                   0x3000
++#define PCIEP2_BASE                   0x4000
++
++#define PHY_P0_CTL                    0x9000
++#define PHY_P1_CTL                    0xa000
++#define PHY_P2_CTL                    0x4000
++
++#define RSTCTL_PCIE0_RST              BIT(24)
++#define RSTCTL_PCIE1_RST              BIT(25)
++#define RSTCTL_PCIE2_RST              BIT(26)
++
++#define HIFSYS_SYSCFG1                        0x14
++#define HIFSYS_SYSCFG1_PHY2_MASK      (0x3 << 20)
++
++#define MTK_PHY_CLK                   0xb00
++#define MTK_PHY_CLKDRV_OFFSET         BIT(2)
++#define MTK_PHY_CLKDRV_OFFSET_MASK    0xe
++#define MTK_PHY_PLL                   0xb04
++#define MTK_PHY_CLKDRV_AMP            BIT(30)
++#define MTK_PHY_CLKDRV_AMP_MASK               0xe0000000
++#define MTK_PHY_REFCLK_SEL            0xc00
++#define MTK_PHY_XTAL_EXT_EN           (BIT(17) | BIT(12))
++#define MTK_PHY_XTAL_EXT_EN_MASK      0x33000
++#define MTK_PHY_PLL_BC                        0xc08
++#define MTK_PHY_PLL_BC_PE2H           0xc0
++#define MTK_PHY_PLL_BC_PE2H_MASK      0x380000
++#define MTK_PHY_PLL_IC                        0xc0c
++#define MTK_PHY_PLL_IC_BR_PE2H                BIT(28)
++#define MTK_PHY_PLL_IC_BR_PE2H_MASK   0x30000000
++#define MTK_PHY_PLL_IC_PE2H           BIT(12)
++#define MTK_PHY_PLL_IC_PE2H_MASK      0xf000
++#define MTK_PHY_PLL_IR                        0xc10
++#define MTK_PHY_PLL_IR_PE2H           BIT(17)
++#define MTK_PHY_PLL_IR_PE2H_MASK      0xf0000
++#define MTK_PHY_PLL_BP                        0xc14
++#define MTK_PHY_PLL_BP_PE2H           (BIT(19) | BIT(17))
++#define MTK_PHY_PLL_BP_PE2H_MASK      0xf0000
++#define MTK_PHY_SSC_DELTA1            0xc3c
++#define MTK_PHY_SSC_DELTA1_PE2H               (0x3c << 16)
++#define MTK_PHY_SSC_DELTA1_PE2H_MASK  0xffff0000
++#define MTK_PHY_SSC_DELTA             0xc48
++#define MTK_PHY_SSC_DELTA_PE2H                0x36
++#define MTK_PHY_SSC_DELTA_PE2H_MASK   0xffff
++
++#define MAX_PORT_NUM                  3
++
++struct mtk_pcie_port {
++      int id;
++      int enable;
++      int irq;
++      u32 link;
++      void __iomem *phy_base;
++      struct reset_control *rstc;
++};
++
++#define mtk_foreach_port(pcie, p)                     \
++              for ((p) = pcie->port;  \
++                   (p) != &pcie->port[MAX_PORT_NUM]; (p)++)
++
++struct mtk_pcie {
++      struct device *dev;
++      void __iomem *pcie_base;
++      struct regmap *hifsys;
++
++      struct resource io;
++      struct resource pio;
++      struct resource mem;
++      struct resource prefetch;
++      struct resource busn;
++
++      u32 io_bus_addr;
++      u32 mem_bus_addr;
++
++      struct clk *clk;
++
++      struct mtk_pcie_port port[MAX_PORT_NUM];
++      int pcie_card_link;
++};
++
++static struct mtk_pcie_port_data {
++      u32 base;
++      u32 perst_n;
++      u32 interrupt_en;
++} mtk_pcie_port_data[MAX_PORT_NUM] = {
++      { PCIEP0_BASE, BIT(1), BIT(20) },
++      { PCIEP1_BASE, BIT(2), BIT(21) },
++      { PCIEP2_BASE, BIT(3), BIT(22) },
++};
++
++static const struct mtk_phy_init {
++      uint32_t reg;
++      uint32_t mask;
++      uint32_t val;
++} mtk_phy_init[] = {
++      { MTK_PHY_REFCLK_SEL, MTK_PHY_XTAL_EXT_EN_MASK, MTK_PHY_XTAL_EXT_EN },
++      { MTK_PHY_PLL, MTK_PHY_CLKDRV_AMP_MASK, MTK_PHY_CLKDRV_AMP },
++      { MTK_PHY_CLK, MTK_PHY_CLKDRV_OFFSET_MASK, MTK_PHY_CLKDRV_OFFSET },
++      { MTK_PHY_SSC_DELTA1, MTK_PHY_SSC_DELTA1_PE2H_MASK, MTK_PHY_SSC_DELTA1_PE2H },
++      { MTK_PHY_SSC_DELTA, MTK_PHY_SSC_DELTA_PE2H_MASK, MTK_PHY_SSC_DELTA_PE2H },
++      { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_BR_PE2H_MASK, MTK_PHY_PLL_IC_BR_PE2H },
++      { MTK_PHY_PLL_BC, MTK_PHY_PLL_BC_PE2H_MASK, MTK_PHY_PLL_BC_PE2H },
++      { MTK_PHY_PLL_IR, MTK_PHY_PLL_IR_PE2H_MASK, MTK_PHY_PLL_IR_PE2H },
++      { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_PE2H_MASK, MTK_PHY_PLL_IC_PE2H },
++      { MTK_PHY_PLL_BP, MTK_PHY_PLL_BP_PE2H_MASK, MTK_PHY_PLL_BP_PE2H },
++};
++
++static struct mtk_pcie *sys_to_pcie(struct pci_sys_data *sys)
++{
++      return sys->private_data;
++}
++
++static void pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned reg)
++{
++      iowrite32(val, pcie->pcie_base + reg);
++}
++
++static u32 pcie_r32(struct mtk_pcie *pcie, unsigned reg)
++{
++      return ioread32(pcie->pcie_base + reg);
++}
++
++static void pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned reg)
++{
++      u32 v = pcie_r32(pcie, reg);
++
++      v &= mask;
++      v |= val;
++      pcie_w32(pcie, v, reg);
++}
++
++static int pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where,
++                          int size, u32 *val)
++{
++      struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata);
++      unsigned int slot = PCI_SLOT(devfn);
++      u8 func = PCI_FUNC(devfn);
++      u32 address;
++      u32 data;
++      u32 num = 0;
++
++      if (bus)
++              num = bus->number;
++
++      address = (((where & 0xf00) >> 8) << 24) |
++                (num << 16) |
++                (slot << 11) |
++                (func << 8) |
++                (where & 0xfc);
++
++      pcie_w32(pcie, address, CFGADDR);
++      data = pcie_r32(pcie, CFGDATA);
++
++      switch (size) {
++      case 1:
++              *val = (data >> ((where & 3) << 3)) & 0xff;
++              break;
++      case 2:
++              *val = (data >> ((where & 3) << 3)) & 0xffff;
++              break;
++      case 4:
++              *val = data;
++              break;
++      }
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int pcie_config_write(struct pci_bus *bus, unsigned int devfn, int where,
++                           int size, u32 val)
++{
++      struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata);
++      unsigned int slot = PCI_SLOT(devfn);
++      u8 func = PCI_FUNC(devfn);
++      u32 address;
++      u32 data;
++      u32 num = 0;
++
++      if (bus)
++              num = bus->number;
++
++      address = (((where & 0xf00) >> 8) << 24) |
++                (num << 16) | (slot << 11) | (func << 8) | (where & 0xfc);
++      pcie_w32(pcie, address, CFGADDR);
++      data = pcie_r32(pcie, CFGDATA);
++
++      switch (size) {
++      case 1:
++              data = (data & ~(0xff << ((where & 3) << 3))) |
++                     (val << ((where & 3) << 3));
++              break;
++      case 2:
++              data = (data & ~(0xffff << ((where & 3) << 3))) |
++                     (val << ((where & 3) << 3));
++              break;
++      case 4:
++              data = val;
++              break;
++      }
++      pcie_w32(pcie, data, CFGDATA);
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops mtk_pcie_ops = {
++      .read   = pcie_config_read,
++      .write  = pcie_config_write,
++};
++
++static int __init mtk_pcie_setup(int nr, struct pci_sys_data *sys)
++{
++      struct mtk_pcie *pcie = sys_to_pcie(sys);
++
++      request_resource(&ioport_resource, &pcie->pio);
++      request_resource(&iomem_resource, &pcie->mem);
++
++      pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
++      pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
++      pci_add_resource(&sys->resources, &pcie->busn);
++
++      return 1;
++}
++
++static struct pci_bus * __init mtk_pcie_scan_bus(int nr,
++                                              struct pci_sys_data *sys)
++{
++      struct mtk_pcie *pcie = sys_to_pcie(sys);
++      struct pci_bus *bus;
++
++      bus = pci_create_root_bus(pcie->dev, sys->busnr, &mtk_pcie_ops, sys,
++                                &sys->resources);
++      if (!bus)
++              return NULL;
++
++      pci_scan_child_bus(bus);
++
++      return bus;
++}
++
++static int __init mtk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++      struct mtk_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
++      struct mtk_pcie_port *port;
++      int irq = -1;
++
++      mtk_foreach_port(pcie, port)
++              if (port->id == slot)
++                      irq = port->irq;
++
++      return irq;
++}
++
++static void mtk_pcie_configure_phy(struct mtk_pcie *pcie,
++                                 struct mtk_pcie_port *port)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) {
++              void __iomem *phy_addr = port->phy_base + mtk_phy_init[i].reg;
++              u32 val = ioread32(phy_addr);
++
++              val &= ~mtk_phy_init[i].mask;
++              val |= mtk_phy_init[i].val;
++              iowrite32(val, phy_addr);
++      }
++      usleep_range(5000, 6000);
++}
++
++static void mtk_pcie_configure_rc(struct mtk_pcie *pcie,
++                                struct mtk_pcie_port *port,
++                                struct pci_bus *bus)
++{
++      u32 val = 0;
++
++      pcie_config_write(bus,
++                        port->id << 3,
++                        PCI_BASE_ADDRESS_0, 4, MEMORY_BASE);
++
++      pcie_config_read(bus,
++                       port->id << 3, PCI_BASE_ADDRESS_0, 4, &val);
++
++      /* Configure RC Credit */
++      pcie_config_read(bus, port->id << 3, 0x73c, 4, &val);
++      val &= ~(0x9fff) << 16;
++      val |= 0x806c << 16;
++      pcie_config_write(bus, port->id << 3, 0x73c, 4, val);
++
++      /* Configure RC FTS number */
++      pcie_config_read(bus, port->id << 3, 0x70c, 4, &val);
++      val &= ~(0xff3) << 8;
++      val |= 0x50 << 8;
++      pcie_config_write(bus, port->id << 3, 0x70c, 4, val);
++}
++
++static int mtk_pcie_preinit(struct mtk_pcie *pcie)
++{
++      struct mtk_pcie_port *port;
++      u32 val = 0;
++      struct pci_bus bus;
++      struct pci_sys_data sys;
++
++      memset(&bus, 0, sizeof(bus));
++      memset(&sys, 0, sizeof(sys));
++      bus.sysdata = (void *)&sys;
++      sys.private_data = (void *)pcie;
++
++      pcibios_min_io = 0;
++      pcibios_min_mem = 0;
++
++      /* The PHY on Port 2 is shared with USB */
++      if (pcie->port[2].enable)
++              regmap_update_bits(pcie->hifsys, HIFSYS_SYSCFG1,
++                                 HIFSYS_SYSCFG1_PHY2_MASK, 0x0);
++
++      /* PCIe RC Reset */
++      mtk_foreach_port(pcie, port)
++              if (port->enable)
++                      reset_control_assert(port->rstc);
++      usleep_range(1000, 2000);
++      mtk_foreach_port(pcie, port)
++              if (port->enable)
++                      reset_control_deassert(port->rstc);
++      usleep_range(1000, 2000);
++
++      /* Configure PCIe PHY */
++      mtk_foreach_port(pcie, port)
++              if (port->enable)
++                      mtk_pcie_configure_phy(pcie, port);
++
++      /* PCIe EP reset */
++      val = 0;
++      mtk_foreach_port(pcie, port)
++              if (port->enable)
++                      val |= mtk_pcie_port_data[port->id].perst_n;
++      pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG);
++      usleep_range(1000, 2000);
++      pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG);
++      usleep_range(1000, 2000);
++      msleep(100);
++
++      /* check the link status */
++      val = 0;
++      mtk_foreach_port(pcie, port) {
++              if (port->enable) {
++                      u32 base = mtk_pcie_port_data[port->id].base;
++
++                      if ((pcie_r32(pcie, base + PCIE_SISTAT) & 0x1))
++                              port->link = 1;
++                      else
++                              reset_control_assert(port->rstc);
++              }
++      }
++
++      mtk_foreach_port(pcie, port)
++              if (port->link)
++                      pcie->pcie_card_link++;
++
++      if (!pcie->pcie_card_link)
++              return -ENODEV;
++
++      pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE);
++      pcie_w32(pcie, pcie->io_bus_addr, IOBASE);
++
++      mtk_foreach_port(pcie, port) {
++              if (port->link) {
++                      u32 base = mtk_pcie_port_data[port->id].base;
++                      u32 inte = mtk_pcie_port_data[port->id].interrupt_en;
++
++                      pcie_m32(pcie, 0, inte, PCIENA);
++                      pcie_w32(pcie, 0x7fff0001, base + BAR0SETUP);
++                      pcie_w32(pcie, MEMORY_BASE, base + IMBASEBAR0);
++                      pcie_w32(pcie, 0x06040001, base + PCIE_CLASS);
++              }
++      }
++
++      mtk_foreach_port(pcie, port)
++              if (port->link)
++                      mtk_pcie_configure_rc(pcie, port, &bus);
++
++      return 0;
++}
++
++static int mtk_pcie_parse_dt(struct mtk_pcie *pcie)
++{
++      struct device_node *np = pcie->dev->of_node, *port;
++      struct of_pci_range_parser parser;
++      struct of_pci_range range;
++      struct resource res;
++      int err;
++
++      pcie->hifsys = syscon_regmap_lookup_by_phandle(np, "mediatek,hifsys");
++      if (IS_ERR(pcie->hifsys)) {
++              dev_err(pcie->dev, "missing \"mediatek,hifsys\" phandle\n");
++              return PTR_ERR(pcie->hifsys);
++      }
++
++      if (of_pci_range_parser_init(&parser, np)) {
++              dev_err(pcie->dev, "missing \"ranges\" property\n");
++              return -EINVAL;
++      }
++
++      for_each_of_pci_range(&parser, &range) {
++              err = of_pci_range_to_resource(&range, np, &res);
++              if (err < 0) {
++                      dev_err(pcie->dev, "failed to read resource range\n");
++                      return err;
++              }
++
++              switch (res.flags & IORESOURCE_TYPE_BITS) {
++              case IORESOURCE_IO:
++                      memcpy(&pcie->pio, &res, sizeof(res));
++                      pcie->pio.start = (resource_size_t)range.pci_addr;
++                      pcie->pio.end = (resource_size_t)
++                                      (range.pci_addr + range.size - 1);
++                      pcie->io_bus_addr = (resource_size_t)range.cpu_addr;
++                      break;
++
++              case IORESOURCE_MEM:
++                      if (res.flags & IORESOURCE_PREFETCH) {
++                              memcpy(&pcie->prefetch, &res, sizeof(res));
++                              pcie->prefetch.name = "prefetchable";
++                              pcie->prefetch.start =
++                                      (resource_size_t)range.pci_addr;
++                              pcie->prefetch.end = (resource_size_t)
++                                      (range.pci_addr + range.size - 1);
++                      } else {
++                              memcpy(&pcie->mem, &res, sizeof(res));
++                              pcie->mem.name = "non-prefetchable";
++                              pcie->mem.start = (resource_size_t)
++                                      range.pci_addr;
++                              pcie->prefetch.end = (resource_size_t)
++                                      (range.pci_addr + range.size - 1);
++                              pcie->mem_bus_addr = (resource_size_t)
++                                      range.cpu_addr;
++                      }
++                      break;
++              }
++      }
++
++      err = of_pci_parse_bus_range(np, &pcie->busn);
++      if (err < 0) {
++              dev_err(pcie->dev, "failed to parse ranges property: %d\n",
++                      err);
++              pcie->busn.name = np->name;
++              pcie->busn.start = 0;
++              pcie->busn.end = 0xff;
++              pcie->busn.flags = IORESOURCE_BUS;
++      }
++
++      /* parse root ports */
++      for_each_child_of_node(np, port) {
++              unsigned int index;
++              char rst[] = "pcie0";
++
++              err = of_pci_get_devfn(port);
++              if (err < 0) {
++                      dev_err(pcie->dev, "failed to parse address: %d\n",
++                              err);
++                      return err;
++              }
++
++              index = PCI_SLOT(err);
++              if (index > MAX_PORT_NUM) {
++                      dev_err(pcie->dev, "invalid port number: %d\n", index);
++                      continue;
++              }
++              index--;
++              pcie->port[index].id = index;
++
++              if (!of_device_is_available(port))
++                      continue;
++
++              rst[4] += index;
++              pcie->port[index].rstc = devm_reset_control_get(pcie->dev,
++                                                                 rst);
++              if (!IS_ERR(pcie->port[index].rstc))
++                      pcie->port[index].enable = 1;
++      }
++      return 0;
++}
++
++static int mtk_pcie_get_resources(struct mtk_pcie *pcie)
++{
++      struct platform_device *pdev = to_platform_device(pcie->dev);
++      struct mtk_pcie_port *port;
++      struct resource *res;
++
++      pcie->clk = devm_clk_get(&pdev->dev, "pcie");
++      if (IS_ERR(pcie->clk)) {
++              dev_err(&pdev->dev, "Failed to get pcie clk\n");
++              return PTR_ERR(pcie->clk);
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pcie->pcie_base = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(pcie->pcie_base)) {
++              dev_err(&pdev->dev, "Failed to get pcie range\n");
++              return PTR_ERR(pcie->pcie_base);
++      }
++
++      mtk_foreach_port(pcie, port) {
++              if (!port->enable)
++                      continue;
++              res = platform_get_resource(pdev, IORESOURCE_MEM, port->id + 1);
++              port->phy_base = devm_ioremap_resource(&pdev->dev, res);
++              if (IS_ERR(port->phy_base)) {
++                      dev_err(&pdev->dev, "Failed to get pcie phy%d range %p\n",
++                              port->id, port->phy_base);
++                      return PTR_ERR(port->phy_base);
++              }
++              port->irq = platform_get_irq(pdev, port->id);
++      }
++
++      return clk_prepare_enable(pcie->clk);
++}
++
++static int mtk_pcie_probe(struct platform_device *pdev)
++{
++      struct mtk_pcie *pcie;
++      struct hw_pci hw;
++      int ret;
++
++      pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
++      if (!pcie)
++              return -ENOMEM;
++
++      pcie->dev = &pdev->dev;
++      ret = mtk_pcie_parse_dt(pcie);
++      if (ret < 0)
++              return ret;
++
++      pm_runtime_enable(&pdev->dev);
++      pm_runtime_get_sync(&pdev->dev);
++
++      ret = mtk_pcie_get_resources(pcie);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "failed to request resources: %d\n", ret);
++              goto err_out;
++      }
++
++      ret = mtk_pcie_preinit(pcie);
++      if (ret)
++              return ret;
++
++      memset(&hw, 0, sizeof(hw));
++      hw.nr_controllers = 1;
++      hw.private_data = (void **)&pcie;
++      hw.setup = mtk_pcie_setup;
++      hw.map_irq = mtk_pcie_map_irq;
++      hw.scan = mtk_pcie_scan_bus;
++
++      pci_common_init_dev(pcie->dev, &hw);
++      platform_set_drvdata(pdev, pcie);
++
++      return 0;
++
++err_out:
++      clk_disable_unprepare(pcie->clk);
++      pm_runtime_put_sync(&pdev->dev);
++      pm_runtime_disable(&pdev->dev);
++
++      return ret;
++}
++
++static const struct of_device_id mtk_pcie_ids[] = {
++      { .compatible = "mediatek,mt2701-pcie" },
++      { .compatible = "mediatek,mt7623-pcie" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mtk_pcie_ids);
++
++static struct platform_driver mtk_pcie_driver = {
++      .probe = mtk_pcie_probe,
++      .driver = {
++              .name = "mediatek-pcie",
++              .owner = THIS_MODULE,
++              .of_match_table = of_match_ptr(mtk_pcie_ids),
++      },
++};
++
++static int __init mtk_pcie_init(void)
++{
++      return platform_driver_register(&mtk_pcie_driver);
++}
++
++module_init(mtk_pcie_init);
diff --git a/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
new file mode 100644 (file)
index 0000000..8d91b12
--- /dev/null
@@ -0,0 +1,75 @@
+From 2f47c01fe3015f4c649849ddffe04f12a122abe2 Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:37 +0800
+Subject: [PATCH 04/57] soc: mediatek: Add MT2701 power dt-bindings
+
+Add power dt-bindings for MT2701.
+
+Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ .../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
++++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+@@ -9,17 +9,20 @@ domain control.
+ The driver implements the Generic PM domain bindings described in
+ power/power_domain.txt. It provides the power domains defined in
+-include/dt-bindings/power/mt8173-power.h.
++include/dt-bindings/power/mt8173-power.h and mt2701-power.h.
+ Required properties:
+-- compatible: Must be "mediatek,mt8173-scpsys"
++- compatible: Should be one of:
++      - "mediatek,mt2701-scpsys"
++      - "mediatek,mt8173-scpsys"
+ - #power-domain-cells: Must be 1
+ - reg: Address range of the SCPSYS unit
+ - infracfg: must contain a phandle to the infracfg controller
+ - clock, clock-names: clocks according to the common clock binding.
+-                      The clocks needed "mm", "mfg", "venc" and "venc_lt".
+-                    These are the clocks which hardware needs to be enabled
+-                    before enabling certain power domains.
++                      These are clocks which hardware needs to be
++                      enabled before enabling certain power domains.
++      Required clocks for MT2701: "mm", "mfg", "ethif"
++      Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt"
+ Optional properties:
+ - vdec-supply: Power supply for the vdec power domain
+--- /dev/null
++++ b/include/dt-bindings/power/mt2701-power.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2015 MediaTek Inc.
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H
++#define _DT_BINDINGS_POWER_MT2701_POWER_H
++
++#define MT2701_POWER_DOMAIN_CONN      0
++#define MT2701_POWER_DOMAIN_DISP      1
++#define MT2701_POWER_DOMAIN_IFR_MSC   2
++#define MT2701_POWER_DOMAIN_VDEC      3
++#define MT2701_POWER_DOMAIN_ISP               4
++#define MT2701_POWER_DOMAIN_BDP               5
++#define MT2701_POWER_DOMAIN_ETH               6
++#define MT2701_POWER_DOMAIN_HIF               7
++
++#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
diff --git a/target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch
new file mode 100644 (file)
index 0000000..ef40ba2
--- /dev/null
@@ -0,0 +1,1431 @@
+From f76b34c799d87ab241432b1241f6fc6d9db3ecb6 Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@mediatek.com>
+Date: Tue, 5 Jan 2016 14:30:20 +0800
+Subject: [PATCH 05/57] clk: mediatek: Add MT2701 clock support
+
+Add MT2701 clock support, include topckgen, apmixedsys,
+infracfg, pericfg and subsystem clocks.
+
+Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+---
+ drivers/clk/mediatek/Kconfig      |    8 +
+ drivers/clk/mediatek/Makefile     |    1 +
+ drivers/clk/mediatek/clk-gate.c   |   56 ++
+ drivers/clk/mediatek/clk-gate.h   |    2 +
+ drivers/clk/mediatek/clk-mt2701.c | 1210 +++++++++++++++++++++++++++++++++++++
+ drivers/clk/mediatek/clk-mtk.c    |   25 +
+ drivers/clk/mediatek/clk-mtk.h    |   35 +-
+ 7 files changed, 1334 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/clk/mediatek/clk-mt2701.c
+
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -6,6 +6,14 @@ config COMMON_CLK_MEDIATEK
+       ---help---
+         Mediatek SoCs' clock support.
++config COMMON_CLK_MT2701
++      bool "Clock driver for Mediatek MT2701 and MT7623"
++      depends on COMMON_CLK
++      select COMMON_CLK_MEDIATEK
++      default ARCH_MEDIATEK
++      ---help---
++        This driver supports Mediatek MT2701 and MT7623 clocks.
++
+ config COMMON_CLK_MT8135
+       bool "Clock driver for Mediatek MT8135"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
+ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
++obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+ obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
+--- a/drivers/clk/mediatek/clk-gate.c
++++ b/drivers/clk/mediatek/clk-gate.c
+@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw
+       regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
+ }
++static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
++{
++      struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
++      u32 val;
++
++      regmap_read(cg->regmap, cg->sta_ofs, &val);
++      val |= BIT(cg->bit);
++      regmap_write(cg->regmap, cg->sta_ofs, val);
++}
++
++static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
++{
++      struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
++      u32 val;
++
++      regmap_read(cg->regmap, cg->sta_ofs, &val);
++      val &= ~(BIT(cg->bit));
++      regmap_write(cg->regmap, cg->sta_ofs, val);
++}
++
+ static int mtk_cg_enable(struct clk_hw *hw)
+ {
+       mtk_cg_clr_bit(hw);
+@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct cl
+       mtk_cg_clr_bit(hw);
+ }
++static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
++{
++      mtk_cg_clr_bit_no_setclr(hw);
++
++      return 0;
++}
++
++static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
++{
++      mtk_cg_set_bit_no_setclr(hw);
++}
++
++static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw)
++{
++      mtk_cg_set_bit_no_setclr(hw);
++
++      return 0;
++}
++
++static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
++{
++      mtk_cg_clr_bit_no_setclr(hw);
++}
++
+ const struct clk_ops mtk_clk_gate_ops_setclr = {
+       .is_enabled     = mtk_cg_bit_is_cleared,
+       .enable         = mtk_cg_enable,
+@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_se
+       .disable        = mtk_cg_disable_inv,
+ };
++const struct clk_ops mtk_clk_gate_ops_no_setclr = {
++      .is_enabled     = mtk_cg_bit_is_cleared,
++      .enable         = mtk_cg_enable_no_setclr,
++      .disable        = mtk_cg_disable_no_setclr,
++};
++
++const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
++      .is_enabled     = mtk_cg_bit_is_set,
++      .enable         = mtk_cg_enable_inv_no_setclr,
++      .disable        = mtk_cg_disable_inv_no_setclr,
++};
++
+ struct clk *mtk_clk_register_gate(
+               const char *name,
+               const char *parent_name,
+--- a/drivers/clk/mediatek/clk-gate.h
++++ b/drivers/clk/mediatek/clk-gate.h
+@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_mt
+ extern const struct clk_ops mtk_clk_gate_ops_setclr;
+ extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
++extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
++extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
+ struct clk *mtk_clk_register_gate(
+               const char *name,
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -0,0 +1,1210 @@
++/*
++ * Copyright (c) 2014 MediaTek Inc.
++ * Author: Shunli Wang <shunli.wang@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++
++#include "clk-mtk.h"
++#include "clk-gate.h"
++
++#include <dt-bindings/clock/mt2701-clk.h>
++
++static DEFINE_SPINLOCK(lock);
++
++static const struct mtk_fixed_clk top_fixed_clks[] __initconst = {
++      FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m", 108 * MHZ),
++      FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m", 400 * MHZ),
++      FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m", 295750000),
++      FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m", 340 * MHZ),
++      FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m", 340 * MHZ),
++      FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", 340 * MHZ),
++      FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m", 300 * MHZ),
++      FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", 27 * MHZ),
++      FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", 416 * MHZ),
++};
++
++static const struct mtk_fixed_factor top_fixed_divs[] __initconst = {
++      FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1),
++      FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
++      FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3),
++      FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
++      FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7),
++      FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2),
++      FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4),
++      FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8),
++      FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16),
++      FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2),
++      FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4),
++      FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8),
++      FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2),
++      FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4),
++      FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2),
++      FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4),
++
++      FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1),
++      FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
++      FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
++      FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
++      FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
++      FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26),
++      FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52),
++      FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108),
++      FACTOR(CLK_TOP_USB_PHY48M, "USB_PHY48M_CK", "univpll", 1, 26),
++      FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2),
++      FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4),
++      FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8),
++      FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1),
++      FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2),
++      FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4),
++      FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8),
++      FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16),
++      FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32),
++      FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2),
++      FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4),
++      FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8),
++
++      FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
++      FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
++      FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
++      FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8),
++
++      FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
++      FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
++
++      FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2),
++      FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4),
++      FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1),
++
++      FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1),
++      FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2),
++      FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4),
++
++      FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1),
++      FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1),
++      FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2),
++
++      FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1),
++      FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2),
++      FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4),
++
++      FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1),
++      FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2),
++      FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3),
++
++      FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1),
++
++      FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1),
++      FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4),
++      FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8),
++      FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16),
++      FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24),
++
++      FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3),
++      FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3),
++      FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3),
++      FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1),
++      FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1),
++      FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8),
++      FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793),
++      FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1),
++};
++
++static const char * const axi_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d2",
++      "syspll_d5",
++      "syspll1_d4",
++      "univpll_d5",
++      "univpll2_d2",
++      "mmpll_d2",
++      "dmpll_d2"
++};
++
++static const char * const mem_parents[] __initconst = {
++      "clk26m",
++      "dmpll_ck"
++};
++
++static const char * const ddrphycfg_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d8"
++};
++
++static const char * const mm_parents[] __initconst = {
++      "clk26m",
++      "vencpll_ck",
++      "syspll1_d2",
++      "syspll1_d4",
++      "univpll_d5",
++      "univpll1_d2",
++      "univpll2_d2",
++      "dmpll_ck"
++};
++
++static const char * const pwm_parents[] __initconst = {
++      "clk26m",
++      "univpll2_d4",
++      "univpll3_d2",
++      "univpll1_d4",
++};
++
++static const char * const vdec_parents[] __initconst = {
++      "clk26m",
++      "vdecpll_ck",
++      "syspll_d5",
++      "syspll1_d4",
++      "univpll_d5",
++      "univpll2_d2",
++      "vencpll_ck",
++      "msdcpll_d2",
++      "mmpll_d2"
++};
++
++static const char * const mfg_parents[] __initconst = {
++      "clk26m",
++      "mmpll_ck",
++      "dmpll_x2_ck",
++      "msdcpll_ck",
++      "clk26m",
++      "syspll_d3",
++      "univpll_d3",
++      "univpll1_d2"
++};
++
++static const char * const camtg_parents[] __initconst = {
++      "clk26m",
++      "univpll_d26",
++      "univpll2_d2",
++      "syspll3_d2",
++      "syspll3_d4",
++      "msdcpll_d2",
++      "mmpll_d2"
++};
++
++static const char * const uart_parents[] __initconst = {
++      "clk26m",
++      "univpll2_d8"
++};
++
++static const char * const spi_parents[] __initconst = {
++      "clk26m",
++      "syspll3_d2",
++      "syspll4_d2",
++      "univpll2_d4",
++      "univpll1_d8"
++};
++
++static const char * const usb20_parents[] __initconst = {
++      "clk26m",
++      "univpll1_d8",
++      "univpll3_d4"
++};
++
++static const char * const msdc30_parents[] __initconst = {
++      "clk26m",
++      "msdcpll_d2",
++      "syspll2_d2",
++      "syspll1_d4",
++      "univpll1_d4",
++      "univpll2_d4"
++};
++
++static const char * const audio_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d16"
++};
++
++static const char * const aud_intbus_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d4",
++      "syspll3_d2",
++      "syspll4_d2",
++      "univpll3_d2",
++      "univpll2_d4"
++};
++
++static const char * const pmicspi_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d8",
++      "syspll2_d4",
++      "syspll4_d2",
++      "syspll3_d4",
++      "syspll2_d8",
++      "syspll1_d16",
++      "univpll3_d4",
++      "univpll_d26",
++      "dmpll_d2",
++      "dmpll_d4"
++};
++
++static const char * const scp_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d8",
++      "dmpll_d2",
++      "dmpll_d4"
++};
++
++static const char * const dpi0_parents[] __initconst = {
++      "clk26m",
++      "mipipll",
++      "mipipll_d2",
++      "mipipll_d4",
++      "clk26m",
++      "tvdpll_ck",
++      "tvdpll_d2",
++      "tvdpll_d4"
++};
++
++static const char * const dpi1_parents[] __initconst = {
++      "clk26m",
++      "tvdpll_ck",
++      "tvdpll_d2",
++      "tvdpll_d4"
++};
++
++static const char * const tve_parents[] __initconst = {
++      "clk26m",
++      "mipipll",
++      "mipipll_d2",
++      "mipipll_d4",
++      "clk26m",
++      "tvdpll_ck",
++      "tvdpll_d2",
++      "tvdpll_d4"
++};
++
++static const char * const hdmi_parents[] __initconst = {
++      "clk26m",
++      "hdmipll_ck",
++      "hdmipll_d2",
++      "hdmipll_d3"
++};
++
++static const char * const apll_parents[] __initconst = {
++      "clk26m",
++      "audpll",
++      "audpll_d4",
++      "audpll_d8",
++      "audpll_d16",
++      "audpll_d24",
++      "clk26m",
++      "clk26m"
++};
++
++static const char * const rtc_parents[] __initconst = {
++      "32k_internal",
++      "32k_external",
++      "clk26m",
++      "univpll3_d8"
++};
++
++static const char * const nfi2x_parents[] __initconst = {
++      "clk26m",
++      "syspll2_d2",
++      "syspll_d7",
++      "univpll3_d2",
++      "syspll2_d4",
++      "univpll3_d4",
++      "syspll4_d4",
++      "clk26m"
++};
++
++static const char * const emmc_hclk_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d2",
++      "syspll1_d4",
++      "syspll2_d2"
++};
++
++static const char * const flash_parents[] __initconst = {
++      "clk26m_d8",
++      "clk26m",
++      "syspll2_d8",
++      "syspll3_d4",
++      "univpll3_d4",
++      "syspll4_d2",
++      "syspll2_d4",
++      "univpll2_d4"
++};
++
++static const char * const di_parents[] __initconst = {
++      "clk26m",
++      "tvd2pll_ck",
++      "tvd2pll_d2",
++      "clk26m"
++};
++
++static const char * const nr_osd_parents[] __initconst = {
++      "clk26m",
++      "vencpll_ck",
++      "syspll1_d2",
++      "syspll1_d4",
++      "univpll_d5",
++      "univpll1_d2",
++      "univpll2_d2",
++      "dmpll_ck"
++};
++
++static const char * const hdmirx_bist_parents[] __initconst = {
++      "clk26m",
++      "syspll_d3",
++      "clk26m",
++      "syspll1_d16",
++      "syspll4_d2",
++      "syspll1_d4",
++      "vencpll_ck",
++      "clk26m"
++};
++
++static const char * const intdir_parents[] __initconst = {
++      "clk26m",
++      "mmpll_ck",
++      "syspll_d2",
++      "univpll_d2"
++};
++
++static const char * const asm_parents[] __initconst = {
++      "clk26m",
++      "univpll2_d4",
++      "univpll2_d2",
++      "syspll_d5"
++};
++
++static const char * const ms_card_parents[] __initconst = {
++      "clk26m",
++      "univpll3_d8",
++      "syspll4_d4"
++};
++
++static const char * const ethif_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d2",
++      "syspll_d5",
++      "syspll1_d4",
++      "univpll_d5",
++      "univpll1_d2",
++      "dmpll_ck",
++      "dmpll_d2"
++};
++
++static const char * const hdmirx_parents[] __initconst = {
++      "clk26m",
++      "univpll_d52"
++};
++
++static const char * const cmsys_parents[] __initconst = {
++      "clk26m",
++      "syspll1_d2",
++      "univpll1_d2",
++      "univpll_d5",
++      "syspll_d5",
++      "syspll2_d2",
++      "syspll1_d4",
++      "syspll3_d2",
++      "syspll2_d4",
++      "syspll1_d8",
++      "clk26m",
++      "clk26m",
++      "clk26m",
++      "clk26m",
++      "clk26m"
++};
++
++static const char * const clk_8bdac_parents[] __initconst = {
++      "clkrtc_int",
++      "8bdac_ck_pre",
++      "clk26m",
++      "clk26m"
++};
++
++static const char * const aud2dvd_parents[] __initconst = {
++      "a1sys_hp_ck",
++      "a2sys_hp_ck"
++};
++
++static const char * const padmclk_parents[] __initconst = {
++      "clk26m",
++      "univpll_d26",
++      "univpll_d52",
++      "univpll_d108",
++      "univpll2_d8",
++      "univpll2_d16",
++      "univpll2_d32"
++};
++
++static const char * const aud_mux_parents[] __initconst = {
++      "clk26m",
++      "aud1pll_98m_ck",
++      "aud2pll_90m_ck",
++      "hadds2pll_98m",
++      "audio_ext1_ck",
++      "audio_ext2_ck"
++};
++
++static const char * const aud_src_parents[] __initconst = {
++      "aud_mux1_sel",
++      "aud_mux2_sel"
++};
++
++static const char * const cpu_parents[] __initconst = {
++      "clk26m",
++      "armpll",
++      "mainpll",
++      "mmpll"
++};
++
++static const struct mtk_composite top_muxes[] __initconst = {
++      MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
++              0x0040, 0, 3, INVALID_MUX_GATE_BIT),
++      MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1, 15),
++      MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23),
++      MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
++      MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
++      MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 16, 3, 23),
++      MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0050, 24, 3, 31),
++      MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 0, 1, 7),
++
++      MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents, 0x0060, 8, 3, 15),
++      MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 16, 2, 23),
++      MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0060, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0070, 0, 3, 7),
++      MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0070, 8, 3, 15),
++      MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents, 0x0070, 16, 1, 23),
++      MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0070, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0080, 0, 4, 7),
++      MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0080, 8, 2, 15),
++      MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x0080, 16, 3, 23),
++      MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0080, 24, 2, 31),
++
++      MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, 0x0090, 0, 3, 7),
++      MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x0090, 8, 2, 15),
++      MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0090, 16, 3, 23),
++
++      MUX_GATE(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00A0, 0, 2, 7),
++      MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, 0x00A0, 8, 3, 15),
++      MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents, 0x00A0, 24, 2, 31),
++
++      MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, 0x00B0, 0, 3, 7),
++      MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, 0x00B0, 8, 2, 15),
++      MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents, 0x00B0, 16, 3, 23),
++      MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents, 0x00B0, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel", hdmirx_bist_parents, 0x00C0, 0, 3, 7),
++      MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, 0x00C0, 8, 2, 15),
++      MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents, 0x00C0, 16, 2, 23),
++      MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents, 0x00C0, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents, 0x00D0, 0, 2, 7),
++      MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents, 0x00D0, 16, 2, 23),
++      MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents, 0x00D0, 24, 3, 31),
++
++      MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents, 0x00E0, 0, 1, 7),
++      MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x00E0, 8, 3, 15),
++      MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, 0x00E0, 16, 4, 23),
++
++      MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents, 0x00E0, 24, 3, 31),
++      MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents, 0x00F0, 0, 3, 7),
++      MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents, 0x00F0, 8, 2, 15),
++      MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents, 0x00F0, 16, 1, 23),
++
++      MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents, 0x0100, 0, 3),
++
++      MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents, 0x012c, 0, 3),
++      MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents, 0x012c, 3, 3),
++      MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents, 0x012c, 6, 3),
++      MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents, 0x012c, 15, 1, 23),
++      MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents, 0x012c, 16, 1, 24),
++      MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents, 0x012c, 17, 1, 25),
++      MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents, 0x012c, 18, 1, 26),
++      MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents, 0x012c, 19, 1, 27),
++      MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents, 0x012c, 20, 1, 28),
++};
++
++static const struct mtk_clk_divider top_adj_divs[] __initconst = {
++      DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext_ck1", 0x0120, 0, 8),
++      DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext_ck2", 0x0120, 8, 8),
++      DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel", 0x0120, 16, 8),
++      DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel", 0x0120, 24, 8),
++      DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel", 0x0124, 0, 8),
++      DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel", 0x0124, 8, 8),
++      DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel", 0x0124, 16, 8),
++      DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel", 0x0124, 24, 8),
++      DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel", 0x0128, 0, 8),
++      DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel", 0x0128, 8, 8),
++};
++
++static const struct mtk_gate_regs top_aud_cg_regs __initconst = {
++      .sta_ofs = 0x012C,
++};
++
++#define GATE_TOP_AUD(_id, _name, _parent, _shift) {   \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &top_aud_cg_regs,               \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_no_setclr,     \
++      }
++
++static const struct mtk_gate top_clks[] __initconst = {
++      GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", 21),
++      GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div", 22),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div", 23),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div", 24),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div", 25),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div", 26),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div", 27),
++      GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
++};
++
++static void __init mtk_topckgen_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      void __iomem *base;
++      int r;
++
++      base = of_iomap(node, 0);
++      if (!base) {
++              pr_err("%s(): ioremap failed\n", __func__);
++              return;
++      }
++
++      clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
++
++      mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
++                                                              clk_data);
++
++      mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
++                                                              clk_data);
++
++      mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
++                              base, &lock, clk_data);
++
++      mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
++                              base, &lock, clk_data);
++
++      mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
++
++static const struct mtk_gate_regs infra_cg_regs __initconst = {
++      .set_ofs = 0x0040,
++      .clr_ofs = 0x0044,
++      .sta_ofs = 0x0048,
++};
++
++#define GATE_ICG(_id, _name, _parent, _shift) {               \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &infra_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++static const struct mtk_gate infra_clks[] __initconst = {
++      GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0),
++      GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1),
++      GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2),
++      GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2_294m_ck", 4),
++      GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk_null", 5),
++      GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6),
++      GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7),
++      GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
++      GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12),
++      GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13),
++      GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14),
++      GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15),
++      GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16),
++      GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18),
++      GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19),
++      GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22),
++      GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23),
++      GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24),
++};
++
++static const struct mtk_fixed_factor infra_fixed_divs[] __initconst = {
++      FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2),
++};
++
++static void __init mtk_infrasys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
++
++      mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
++                                              clk_data);
++      mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
++
++static const struct mtk_gate_regs peri0_cg_regs __initconst = {
++      .set_ofs = 0x0008,
++      .clr_ofs = 0x0010,
++      .sta_ofs = 0x0018,
++};
++
++static const struct mtk_gate_regs peri1_cg_regs __initconst = {
++      .set_ofs = 0x000c,
++      .clr_ofs = 0x0014,
++      .sta_ofs = 0x001c,
++};
++
++#define GATE_PERI0(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &peri0_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++#define GATE_PERI1(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &peri1_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++static const struct mtk_gate peri_clks[] __initconst = {
++      GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31),
++      GATE_PERI1(CLK_PERI_ETH, "eth_ck", "clk26m", 30),
++      GATE_PERI1(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29),
++      GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28),
++      GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27),
++      GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26),
++      GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25),
++      GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24),
++      GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23),
++      GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22),
++      GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21),
++      GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20),
++      GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19),
++      GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18),
++      GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17),
++      GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16),
++      GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15),
++      GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14),
++      GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13),
++      GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
++      GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
++      GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
++      GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
++      GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
++      GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
++      GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
++      GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
++      GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
++      GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
++      GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
++      GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
++      GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0),
++
++      GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card", 11),
++      GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10),
++      GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9),
++      GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8),
++      GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7),
++      GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6),
++      GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5),
++      GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi_sel", 4),
++      GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi_sel", 3),
++      GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2),
++      GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1),
++      GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0),
++};
++
++static const char * const uart_ck_sel_parents[] __initconst = {
++      "clk26m",
++      "uart_sel",
++};
++
++static const struct mtk_composite peri_muxs[] __initconst = {
++      MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
++      MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
++      MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
++      MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
++};
++
++static void __init mtk_pericfg_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      void __iomem *base;
++      int r;
++
++      base = of_iomap(node, 0);
++      if (!base) {
++              pr_err("%s(): ioremap failed\n", __func__);
++              return;
++      }
++
++      clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
++
++      mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
++                                              clk_data);
++
++      mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
++                      &lock, clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
++
++static const struct mtk_gate_regs disp0_cg_regs __initconst = {
++      .set_ofs = 0x0104,
++      .clr_ofs = 0x0108,
++      .sta_ofs = 0x0100,
++};
++
++static const struct mtk_gate_regs disp1_cg_regs __initconst = {
++      .set_ofs = 0x0114,
++      .clr_ofs = 0x0118,
++      .sta_ofs = 0x0110,
++};
++
++#define GATE_DISP0(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &disp0_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++#define GATE_DISP1(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &disp1_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++static const struct mtk_gate mm_clks[] __initconst = {
++      GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0),
++      GATE_DISP0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1),
++      GATE_DISP0(CLK_MM_CMDQ, "mm_cmdq", "mm_sel", 2),
++      GATE_DISP0(CLK_MM_MUTEX, "mm_mutex", "mm_sel", 3),
++      GATE_DISP0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 4),
++      GATE_DISP0(CLK_MM_DISP_BLS, "mm_disp_bls", "mm_sel", 5),
++      GATE_DISP0(CLK_MM_DISP_WDMA, "mm_disp_wdma", "mm_sel", 6),
++      GATE_DISP0(CLK_MM_DISP_RDMA, "mm_disp_rdma", "mm_sel", 7),
++      GATE_DISP0(CLK_MM_DISP_OVL, "mm_disp_ovl", "mm_sel", 8),
++      GATE_DISP0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9),
++      GATE_DISP0(CLK_MM_MDP_WROT, "mm_mdp_wrot", "mm_sel", 10),
++      GATE_DISP0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11),
++      GATE_DISP0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 12),
++      GATE_DISP0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 13),
++      GATE_DISP0(CLK_MM_MDP_RDMA, "mm_mdp_rdma", "mm_sel", 14),
++      GATE_DISP0(CLK_MM_MDP_BLS_26M, "mm_mdp_bls_26m", "clk26m", 15),
++      GATE_DISP0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 16),
++      GATE_DISP0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 17),
++      GATE_DISP0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "rtc_sel", 18),
++      GATE_DISP0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19),
++      GATE_DISP0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 20),
++      GATE_DISP1(CLK_MM_DSI_ENGINE, "mm_dsi_eng", "mm_sel", 0),
++      GATE_DISP1(CLK_MM_DSI_DIG, "mm_dsi_dig", "dsio_lntc_dsiclk", 1),
++      GATE_DISP1(CLK_MM_DPI_DIGL, "mm_dpi_digl", "dpi0_sel", 2),
++      GATE_DISP1(CLK_MM_DPI_ENGINE, "mm_dpi_eng", "mm_sel", 3),
++      GATE_DISP1(CLK_MM_DPI1_DIGL, "mm_dpi1_digl", "dpi1_sel", 4),
++      GATE_DISP1(CLK_MM_DPI1_ENGINE, "mm_dpi1_eng", "mm_sel", 5),
++      GATE_DISP1(CLK_MM_TVE_OUTPUT, "mm_tve_output", "tve_sel", 6),
++      GATE_DISP1(CLK_MM_TVE_INPUT, "mm_tve_input", "dpi0_sel", 7),
++      GATE_DISP1(CLK_MM_HDMI_PIXEL, "mm_hdmi_pixel", "dpi1_sel", 8),
++      GATE_DISP1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmi_sel", 9),
++      GATE_DISP1(CLK_MM_HDMI_AUDIO, "mm_hdmi_audio", "apll_sel", 10),
++      GATE_DISP1(CLK_MM_HDMI_SPDIF, "mm_hdmi_spdif", "apll_sel", 11),
++      GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14),
++};
++
++static void __init mtk_mmsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_MM_NR);
++
++      mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_mmsys, "mediatek,mt2701-mmsys", mtk_mmsys_init);
++
++static const struct mtk_gate_regs img_cg_regs __initconst = {
++      .set_ofs = 0x0004,
++      .clr_ofs = 0x0008,
++      .sta_ofs = 0x0000,
++};
++
++#define GATE_IMG(_id, _name, _parent, _shift) {               \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &img_cg_regs,                   \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr,        \
++      }
++
++static const struct mtk_gate img_clks[] __initconst = {
++      GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0),
++      GATE_IMG(CLK_IMG_RESZ, "img_resz", "mm_sel", 1),
++      GATE_IMG(CLK_IMG_JPGDEC, "img_jpgdec", "mm_sel", 5),
++      GATE_IMG(CLK_IMG_VENC_LT, "img_venc_lt", "mm_sel", 8),
++      GATE_IMG(CLK_IMG_VENC, "img_venc", "mm_sel", 9),
++};
++
++static void __init mtk_imgsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_IMG_NR);
++
++      mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt2701-imgsys", mtk_imgsys_init);
++
++static const struct mtk_gate_regs vdec0_cg_regs __initconst = {
++      .set_ofs = 0x0000,
++      .clr_ofs = 0x0004,
++      .sta_ofs = 0x0000,
++};
++
++static const struct mtk_gate_regs vdec1_cg_regs __initconst = {
++      .set_ofs = 0x0008,
++      .clr_ofs = 0x000c,
++      .sta_ofs = 0x0008,
++};
++
++#define GATE_VDEC0(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &vdec0_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr_inv,    \
++      }
++
++#define GATE_VDEC1(_id, _name, _parent, _shift) {     \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &vdec1_cg_regs,                 \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr_inv,    \
++      }
++
++static const struct mtk_gate vdec_clks[] __initconst = {
++      GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0),
++      GATE_VDEC1(CLK_VDEC_LARB, "vdec_larb_cken", "mm_sel", 0),
++};
++
++static void __init mtk_vdecsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_VDEC_NR);
++
++      mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt2701-vdecsys", mtk_vdecsys_init);
++
++static const struct mtk_gate_regs hif_cg_regs __initconst = {
++      .sta_ofs = 0x0008,
++};
++
++#define GATE_HIF(_id, _name, _parent, _shift) {               \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &hif_cg_regs,                   \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++      }
++
++static const struct mtk_gate hif_clks[] __initconst = {
++      GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21),
++      GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22),
++      GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24),
++      GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25),
++      GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26),
++};
++
++static void __init mtk_hifsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
++
++      mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
++
++static const struct mtk_gate_regs eth_cg_regs __initconst = {
++      .sta_ofs = 0x0030,
++};
++
++#define GATE_eth(_id, _name, _parent, _shift) {               \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &eth_cg_regs,                   \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_no_setclr_inv, \
++      }
++
++static const struct mtk_gate eth_clks[] __initconst = {
++      GATE_HIF(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5),
++      GATE_HIF(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6),
++      GATE_HIF(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7),
++      GATE_HIF(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8),
++      GATE_HIF(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11),
++      GATE_HIF(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14),
++      GATE_HIF(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17),
++      GATE_HIF(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29),
++};
++
++static void __init mtk_ethsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
++
++      mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
++
++static const struct mtk_gate_regs bdp0_cg_regs __initconst = {
++      .set_ofs = 0x0104,
++      .clr_ofs = 0x0108,
++      .sta_ofs = 0x0100,
++};
++
++static const struct mtk_gate_regs bdp1_cg_regs __initconst = {
++      .set_ofs = 0x0114,
++      .clr_ofs = 0x0118,
++      .sta_ofs = 0x0110,
++};
++
++#define GATE_BDP0(_id, _name, _parent, _shift) {      \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &bdp0_cg_regs,                  \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr_inv,    \
++      }
++
++#define GATE_BDP1(_id, _name, _parent, _shift) {      \
++              .id = _id,                              \
++              .name = _name,                          \
++              .parent_name = _parent,                 \
++              .regs = &bdp1_cg_regs,                  \
++              .shift = _shift,                        \
++              .ops = &mtk_clk_gate_ops_setclr_inv,    \
++      }
++
++static const struct mtk_gate bdp_clks[] __initconst = {
++      GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0),
++      GATE_BDP0(CLK_BDP_BRG_DRAM, "brg_dram", "mm_sel", 1),
++      GATE_BDP0(CLK_BDP_LARB_DRAM, "larb_dram", "mm_sel", 2),
++      GATE_BDP0(CLK_BDP_WR_VDI_PXL, "wr_vdi_pxl", "hdmi_0_deep340m", 3),
++      GATE_BDP0(CLK_BDP_WR_VDI_DRAM, "wr_vdi_dram", "mm_sel", 4),
++      GATE_BDP0(CLK_BDP_WR_B, "wr_bclk", "mm_sel", 5),
++      GATE_BDP0(CLK_BDP_DGI_IN, "dgi_in", "dpi1_sel", 6),
++      GATE_BDP0(CLK_BDP_DGI_OUT, "dgi_out", "dpi_sel", 7),
++      GATE_BDP0(CLK_BDP_FMT_MAST_27, "fmt_mast_27", "dpi1_sel", 8),
++      GATE_BDP0(CLK_BDP_FMT_B, "fmt_bclk", "mm_sel", 9),
++      GATE_BDP0(CLK_BDP_OSD_B, "osd_bclk", "mm_sel", 10),
++      GATE_BDP0(CLK_BDP_OSD_DRAM, "osd_dram", "mm_sel", 11),
++      GATE_BDP0(CLK_BDP_OSD_AGENT, "osd_agent", "osd_sel", 12),
++      GATE_BDP0(CLK_BDP_OSD_PXL, "osd_pxl", "dpi1_sel", 13),
++      GATE_BDP0(CLK_BDP_RLE_B, "rle_bclk", "mm_sel", 14),
++      GATE_BDP0(CLK_BDP_RLE_AGENT, "rle_agent", "mm_sel", 15),
++      GATE_BDP0(CLK_BDP_RLE_DRAM, "rle_dram", "mm_sel", 16),
++      GATE_BDP0(CLK_BDP_F27M, "f27m", "di_sel", 17),
++      GATE_BDP0(CLK_BDP_F27M_VDOUT, "f27m_vdout", "di_sel", 18),
++      GATE_BDP0(CLK_BDP_F27_74_74, "f27_74_74", "di_sel", 19),
++      GATE_BDP0(CLK_BDP_F2FS, "f2fs", "di_sel", 20),
++      GATE_BDP0(CLK_BDP_F2FS74_148, "f2fs74_148", "di_sel", 21),
++      GATE_BDP0(CLK_BDP_FB, "fbclk", "mm_sel", 22),
++      GATE_BDP0(CLK_BDP_VDO_DRAM, "vdo_dram", "mm_sel", 23),
++      GATE_BDP0(CLK_BDP_VDO_2FS, "vdo_2fs", "di_sel", 24),
++      GATE_BDP0(CLK_BDP_VDO_B, "vdo_bclk", "mm_sel", 25),
++      GATE_BDP0(CLK_BDP_WR_DI_PXL, "wr_di_pxl", "di_sel", 26),
++      GATE_BDP0(CLK_BDP_WR_DI_DRAM, "wr_di_dram", "mm_sel", 27),
++      GATE_BDP0(CLK_BDP_WR_DI_B, "wr_di_bclk", "mm_sel", 28),
++      GATE_BDP0(CLK_BDP_NR_PXL, "nr_pxl", "nr_sel", 29),
++      GATE_BDP0(CLK_BDP_NR_DRAM, "nr_dram", "mm_sel", 30),
++      GATE_BDP0(CLK_BDP_NR_B, "nr_bclk", "mm_sel", 31),
++      GATE_BDP1(CLK_BDP_RX_F, "rx_fclk", "hadds2_fbclk", 0),
++      GATE_BDP1(CLK_BDP_RX_X, "rx_xclk", "clk26m", 1),
++      GATE_BDP1(CLK_BDP_RXPDT, "rxpdtclk", "hdmi_0_pix340m", 2),
++      GATE_BDP1(CLK_BDP_RX_CSCL_N, "rx_cscl_n", "clk26m", 3),
++      GATE_BDP1(CLK_BDP_RX_CSCL, "rx_cscl", "clk26m", 4),
++      GATE_BDP1(CLK_BDP_RX_DDCSCL_N, "rx_ddcscl_n", "hdmi_scl_rx", 5),
++      GATE_BDP1(CLK_BDP_RX_DDCSCL, "rx_ddcscl", "hdmi_scl_rx", 6),
++      GATE_BDP1(CLK_BDP_RX_VCO, "rx_vcoclk", "hadds2pll_294m", 7),
++      GATE_BDP1(CLK_BDP_RX_DP, "rx_dpclk", "hdmi_0_pll340m", 8),
++      GATE_BDP1(CLK_BDP_RX_P, "rx_pclk", "hdmi_0_pll340m", 9),
++      GATE_BDP1(CLK_BDP_RX_M, "rx_mclk", "hadds2pll_294m", 10),
++      GATE_BDP1(CLK_BDP_RX_PLL, "rx_pllclk", "hdmi_0_pix340m", 11),
++      GATE_BDP1(CLK_BDP_BRG_RT_B, "brg_rt_bclk", "mm_sel", 12),
++      GATE_BDP1(CLK_BDP_BRG_RT_DRAM, "brg_rt_dram", "mm_sel", 13),
++      GATE_BDP1(CLK_BDP_LARBRT_DRAM, "larbrt_dram", "mm_sel", 14),
++      GATE_BDP1(CLK_BDP_TMDS_SYN, "tmds_syn", "hdmi_0_pll340m", 15),
++      GATE_BDP1(CLK_BDP_HDMI_MON, "hdmi_mon", "hdmi_0_mon", 16),
++};
++
++static void __init mtk_bdpsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(CLK_BDP_NR);
++
++      mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks),
++                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_bdpsys, "mediatek,mt2701-bdpsys", mtk_bdpsys_init);
++
++#define MT8590_PLL_FMAX               (2000 * MHZ)
++#define CON0_MT8590_RST_BAR   BIT(27)
++
++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \
++                      _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) {  \
++              .id = _id,                                              \
++              .name = _name,                                          \
++              .reg = _reg,                                            \
++              .pwr_reg = _pwr_reg,                                    \
++              .en_mask = _en_mask,                                    \
++              .flags = _flags,                                        \
++              .rst_bar_mask = CON0_MT8590_RST_BAR,                    \
++              .fmax = MT8590_PLL_FMAX,                                \
++              .pcwbits = _pcwbits,                                    \
++              .pd_reg = _pd_reg,                                      \
++              .pd_shift = _pd_shift,                                  \
++              .tuner_reg = _tuner_reg,                                \
++              .pcw_reg = _pcw_reg,                                    \
++              .pcw_shift = _pcw_shift,                                \
++      }
++
++static const struct mtk_pll_data apmixed_plls[] = {
++      PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001, 0,
++                              21, 0x204, 24, 0x0, 0x204, 0),
++      PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001,
++                HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0),
++      PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001,
++                HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14),
++      PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0,
++                              21, 0x230, 4, 0x0, 0x234, 0),
++      PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0,
++                              21, 0x240, 4, 0x0, 0x244, 0),
++      PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0,
++                              21, 0x250, 4, 0x0, 0x254, 0),
++      PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0,
++                              31, 0x270, 4, 0x0, 0x274, 0),
++      PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0,
++                              31, 0x280, 4, 0x0, 0x284, 0),
++      PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0,
++                              31, 0x290, 4, 0x0, 0x294, 0),
++      PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0,
++                              31, 0x2a0, 4, 0x0, 0x2a4, 0),
++      PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0,
++                              31, 0x2b0, 4, 0x0, 0x2b4, 0),
++      PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0,
++                              31, 0x2c0, 4, 0x0, 0x2c4, 0),
++      PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0,
++                              21, 0x2d0, 4, 0x0, 0x2d4, 0),
++};
++
++static void __init mtk_apmixedsys_init(struct device_node *node)
++{
++      struct clk_onecell_data *clk_data;
++      int r;
++
++      clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
++      if (!clk_data)
++              return;
++
++      mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
++                                                              clk_data);
++
++      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++      if (r)
++              pr_err("%s(): could not register clock provider: %d\n",
++                      __func__, r);
++}
++CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
++                                                      mtk_apmixedsys_init);
+--- a/drivers/clk/mediatek/clk-mtk.c
++++ b/drivers/clk/mediatek/clk-mtk.c
+@@ -244,3 +244,28 @@ void mtk_clk_register_composites(const s
+                       clk_data->clks[mc->id] = clk;
+       }
+ }
++
++void __init mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
++                      int num, void __iomem *base, spinlock_t *lock,
++                              struct clk_onecell_data *clk_data)
++{
++      struct clk *clk;
++      int i;
++
++      for (i = 0; i <  num; i++) {
++              const struct mtk_clk_divider *mcd = &mcds[i];
++
++              clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
++                      mcd->flags, base +  mcd->div_reg, mcd->div_shift,
++                      mcd->div_width, mcd->clk_divider_flags, lock);
++
++              if (IS_ERR(clk)) {
++                      pr_err("Failed to register clk %s: %ld\n",
++                              mcd->name, PTR_ERR(clk));
++                      continue;
++              }
++
++              if (clk_data)
++                      clk_data->clks[mcd->id] = clk;
++      }
++}
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -121,7 +121,8 @@ struct mtk_composite {
+               .flags = CLK_SET_RATE_PARENT,                           \
+       }
+-#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) {     \
++#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,       \
++                                      _div_width, _div_shift) {       \
+               .id = _id,                                              \
+               .parent = _parent,                                      \
+               .name = _name,                                          \
+@@ -156,8 +157,36 @@ struct mtk_gate {
+       const struct clk_ops *ops;
+ };
+-int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
+-              int num, struct clk_onecell_data *clk_data);
++int mtk_clk_register_gates(struct device_node *node,
++                      const struct mtk_gate *clks, int num,
++                      struct clk_onecell_data *clk_data);
++
++struct mtk_clk_divider {
++      int id;
++      const char *name;
++      const char *parent_name;
++      unsigned long flags;
++
++      uint32_t div_reg;
++      unsigned char div_shift;
++      unsigned char div_width;
++      unsigned char clk_divider_flags;
++      const struct clk_div_table *clk_div_table;
++};
++
++#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) {  \
++              .id = _id,                                      \
++              .name = _name,                                  \
++              .parent_name = _parent,                         \
++              .flags = CLK_SET_RATE_PARENT,                   \
++              .div_reg = _reg,                                \
++              .div_shift = _shift,                            \
++              .div_width = _width,                            \
++}
++
++void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
++                      int num, void __iomem *base, spinlock_t *lock,
++                              struct clk_onecell_data *clk_data);
+ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
diff --git a/target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch
new file mode 100644 (file)
index 0000000..12bda9c
--- /dev/null
@@ -0,0 +1,36 @@
+From 596c3a7300c0419dba71d58cbd4136e0d1e12a4e Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@mediatek.com>
+Date: Tue, 5 Jan 2016 14:30:22 +0800
+Subject: [PATCH 06/57] reset: mediatek: mt2701 reset driver
+
+In infrasys and perifsys, there are many reset
+control bits for kinds of modules. These bits are
+used as actual reset controllers to be registered
+into kernel's generic reset controller framework.
+
+Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/clk/mediatek/clk-mt2701.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_register_reset_controller(node, 2, 0x30);
+ }
+ CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
+@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_register_reset_controller(node, 2, 0x0);
+ }
+ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
diff --git a/target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
new file mode 100644 (file)
index 0000000..f38b435
--- /dev/null
@@ -0,0 +1,29 @@
+From 60c14df3cc898b6b03d66ec725f9705bf431b677 Mon Sep 17 00:00:00 2001
+From: Erin Lo <erin.lo@mediatek.com>
+Date: Mon, 28 Dec 2015 15:09:02 +0800
+Subject: [PATCH 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.
+Add config options so we can build for one SoC only. Add MT2701.
+
+Signed-off-by: Erin Lo <erin.lo@mediatek.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ arch/arm/mach-mediatek/Kconfig | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/mach-mediatek/Kconfig
++++ b/arch/arm/mach-mediatek/Kconfig
+@@ -14,6 +14,10 @@ config MACH_MT2701
+       bool "MediaTek MT2701 SoCs support"
+       default ARCH_MEDIATEK
++config MACH_MT2701
++      bool "MediaTek MT2701 SoCs support"
++      default ARCH_MEDIATEK
++
+ config MACH_MT6589
+       bool "MediaTek MT6589 SoCs support"
+       default ARCH_MEDIATEK
diff --git a/target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
new file mode 100644 (file)
index 0000000..1d83e9a
--- /dev/null
@@ -0,0 +1,487 @@
+From b5a1e520d8039c242b2157b511f684ce464d6e21 Mon Sep 17 00:00:00 2001
+From: James Liao <jamesjj.liao@mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:35 +0800
+Subject: [PATCH 08/57] soc: mediatek: Refine scpsys to support multiple
+ platform
+
+Refine scpsys driver common code to support multiple SoC / platform.
+
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
+ 1 file changed, 210 insertions(+), 138 deletions(-)
+
+--- a/drivers/soc/mediatek/mtk-scpsys.c
++++ b/drivers/soc/mediatek/mtk-scpsys.c
+@@ -11,17 +11,15 @@
+  * GNU General Public License for more details.
+  */
+ #include <linux/clk.h>
+-#include <linux/delay.h>
++#include <linux/init.h>
+ #include <linux/io.h>
+-#include <linux/kernel.h>
+ #include <linux/mfd/syscon.h>
+-#include <linux/init.h>
+ #include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/pm_domain.h>
+-#include <linux/regmap.h>
+-#include <linux/soc/mediatek/infracfg.h>
+ #include <linux/regulator/consumer.h>
++#include <linux/soc/mediatek/infracfg.h>
++
+ #include <dt-bindings/power/mt8173-power.h>
+ #define SPM_VDE_PWR_CON                       0x0210
+@@ -34,6 +32,7 @@
+ #define SPM_MFG_2D_PWR_CON            0x02c0
+ #define SPM_MFG_ASYNC_PWR_CON         0x02c4
+ #define SPM_USB_PWR_CON                       0x02cc
++
+ #define SPM_PWR_STATUS                        0x060c
+ #define SPM_PWR_STATUS_2ND            0x0610
+@@ -55,12 +54,21 @@
+ #define PWR_STATUS_USB                        BIT(25)
+ enum clk_id {
+-      MT8173_CLK_NONE,
+-      MT8173_CLK_MM,
+-      MT8173_CLK_MFG,
+-      MT8173_CLK_VENC,
+-      MT8173_CLK_VENC_LT,
+-      MT8173_CLK_MAX,
++      CLK_NONE,
++      CLK_MM,
++      CLK_MFG,
++      CLK_VENC,
++      CLK_VENC_LT,
++      CLK_MAX,
++};
++
++static const char * const clk_names[] = {
++      NULL,
++      "mm",
++      "mfg",
++      "venc",
++      "venc_lt",
++      NULL,
+ };
+ #define MAX_CLKS      2
+@@ -76,98 +84,6 @@ struct scp_domain_data {
+       bool active_wakeup;
+ };
+-static const struct scp_domain_data scp_domain_data[] = {
+-      [MT8173_POWER_DOMAIN_VDEC] = {
+-              .name = "vdec",
+-              .sta_mask = PWR_STATUS_VDEC,
+-              .ctl_offs = SPM_VDE_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(12, 12),
+-              .clk_id = {MT8173_CLK_MM},
+-      },
+-      [MT8173_POWER_DOMAIN_VENC] = {
+-              .name = "venc",
+-              .sta_mask = PWR_STATUS_VENC,
+-              .ctl_offs = SPM_VEN_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(15, 12),
+-              .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
+-      },
+-      [MT8173_POWER_DOMAIN_ISP] = {
+-              .name = "isp",
+-              .sta_mask = PWR_STATUS_ISP,
+-              .ctl_offs = SPM_ISP_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(13, 12),
+-              .clk_id = {MT8173_CLK_MM},
+-      },
+-      [MT8173_POWER_DOMAIN_MM] = {
+-              .name = "mm",
+-              .sta_mask = PWR_STATUS_DISP,
+-              .ctl_offs = SPM_DIS_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(12, 12),
+-              .clk_id = {MT8173_CLK_MM},
+-              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
+-                      MT8173_TOP_AXI_PROT_EN_MM_M1,
+-      },
+-      [MT8173_POWER_DOMAIN_VENC_LT] = {
+-              .name = "venc_lt",
+-              .sta_mask = PWR_STATUS_VENC_LT,
+-              .ctl_offs = SPM_VEN2_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(15, 12),
+-              .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
+-      },
+-      [MT8173_POWER_DOMAIN_AUDIO] = {
+-              .name = "audio",
+-              .sta_mask = PWR_STATUS_AUDIO,
+-              .ctl_offs = SPM_AUDIO_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(15, 12),
+-              .clk_id = {MT8173_CLK_NONE},
+-      },
+-      [MT8173_POWER_DOMAIN_USB] = {
+-              .name = "usb",
+-              .sta_mask = PWR_STATUS_USB,
+-              .ctl_offs = SPM_USB_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(15, 12),
+-              .clk_id = {MT8173_CLK_NONE},
+-              .active_wakeup = true,
+-      },
+-      [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
+-              .name = "mfg_async",
+-              .sta_mask = PWR_STATUS_MFG_ASYNC,
+-              .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = 0,
+-              .clk_id = {MT8173_CLK_MFG},
+-      },
+-      [MT8173_POWER_DOMAIN_MFG_2D] = {
+-              .name = "mfg_2d",
+-              .sta_mask = PWR_STATUS_MFG_2D,
+-              .ctl_offs = SPM_MFG_2D_PWR_CON,
+-              .sram_pdn_bits = GENMASK(11, 8),
+-              .sram_pdn_ack_bits = GENMASK(13, 12),
+-              .clk_id = {MT8173_CLK_NONE},
+-      },
+-      [MT8173_POWER_DOMAIN_MFG] = {
+-              .name = "mfg",
+-              .sta_mask = PWR_STATUS_MFG,
+-              .ctl_offs = SPM_MFG_PWR_CON,
+-              .sram_pdn_bits = GENMASK(13, 8),
+-              .sram_pdn_ack_bits = GENMASK(21, 16),
+-              .clk_id = {MT8173_CLK_NONE},
+-              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
+-                      MT8173_TOP_AXI_PROT_EN_MFG_M0 |
+-                      MT8173_TOP_AXI_PROT_EN_MFG_M1 |
+-                      MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
+-      },
+-};
+-
+-#define NUM_DOMAINS   ARRAY_SIZE(scp_domain_data)
+-
+ struct scp;
+ struct scp_domain {
+@@ -179,7 +95,7 @@ struct scp_domain {
+ };
+ struct scp {
+-      struct scp_domain domains[NUM_DOMAINS];
++      struct scp_domain *domains;
+       struct genpd_onecell_data pd_data;
+       struct device *dev;
+       void __iomem *base;
+@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct
+       return scpd->data->active_wakeup;
+ }
+-static int scpsys_probe(struct platform_device *pdev)
++static void init_clks(struct platform_device *pdev, struct clk **clk)
++{
++      int i;
++
++      for (i = CLK_NONE + 1; i < CLK_MAX; i++)
++              clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
++}
++
++static struct scp *init_scp(struct platform_device *pdev,
++                      const struct scp_domain_data *scp_domain_data, int num)
+ {
+       struct genpd_onecell_data *pd_data;
+       struct resource *res;
+-      int i, j, ret;
++      int i, j;
+       struct scp *scp;
+-      struct clk *clk[MT8173_CLK_MAX];
++      struct clk *clk[CLK_MAX];
+       scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
+       if (!scp)
+-              return -ENOMEM;
++              return ERR_PTR(-ENOMEM);
+       scp->dev = &pdev->dev;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       scp->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(scp->base))
+-              return PTR_ERR(scp->base);
++              return ERR_CAST(scp->base);
++
++      scp->domains = devm_kzalloc(&pdev->dev,
++                              sizeof(*scp->domains) * num, GFP_KERNEL);
++      if (!scp->domains)
++              return ERR_PTR(-ENOMEM);
+       pd_data = &scp->pd_data;
+       pd_data->domains = devm_kzalloc(&pdev->dev,
+-                      sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
++                      sizeof(*pd_data->domains) * num, GFP_KERNEL);
+       if (!pd_data->domains)
+-              return -ENOMEM;
+-
+-      clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
+-      if (IS_ERR(clk[MT8173_CLK_MM]))
+-              return PTR_ERR(clk[MT8173_CLK_MM]);
+-
+-      clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
+-      if (IS_ERR(clk[MT8173_CLK_MFG]))
+-              return PTR_ERR(clk[MT8173_CLK_MFG]);
+-
+-      clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
+-      if (IS_ERR(clk[MT8173_CLK_VENC]))
+-              return PTR_ERR(clk[MT8173_CLK_VENC]);
+-
+-      clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
+-      if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
+-              return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
++              return ERR_PTR(-ENOMEM);
+       scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                       "infracfg");
+       if (IS_ERR(scp->infracfg)) {
+               dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
+                               PTR_ERR(scp->infracfg));
+-              return PTR_ERR(scp->infracfg);
++              return ERR_CAST(scp->infracfg);
+       }
+-      for (i = 0; i < NUM_DOMAINS; i++) {
++      for (i = 0; i < num; i++) {
+               struct scp_domain *scpd = &scp->domains[i];
+               const struct scp_domain_data *data = &scp_domain_data[i];
+@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_
+                       if (PTR_ERR(scpd->supply) == -ENODEV)
+                               scpd->supply = NULL;
+                       else
+-                              return PTR_ERR(scpd->supply);
++                              return ERR_CAST(scpd->supply);
+               }
+       }
+-      pd_data->num_domains = NUM_DOMAINS;
++      pd_data->num_domains = num;
++
++      init_clks(pdev, clk);
+-      for (i = 0; i < NUM_DOMAINS; i++) {
++      for (i = 0; i < num; i++) {
+               struct scp_domain *scpd = &scp->domains[i];
+               struct generic_pm_domain *genpd = &scpd->genpd;
+               const struct scp_domain_data *data = &scp_domain_data[i];
+@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_
+               scpd->scp = scp;
+               scpd->data = data;
+-              for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
+-                      scpd->clk[j] = clk[data->clk_id[j]];
++
++              for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
++                      struct clk *c = clk[data->clk_id[j]];
++
++                      if (IS_ERR(c)) {
++                              dev_err(&pdev->dev, "%s: clk unavailable\n",
++                                      data->name);
++                              return ERR_CAST(c);
++                      }
++
++                      scpd->clk[j] = c;
++              }
+               genpd->name = data->name;
+               genpd->power_off = scpsys_power_off;
+               genpd->power_on = scpsys_power_on;
+               genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
++      }
++
++      return scp;
++}
++
++static void mtk_register_power_domains(struct platform_device *pdev,
++                              struct scp *scp, int num)
++{
++      struct genpd_onecell_data *pd_data;
++      int i, ret;
++
++      for (i = 0; i < num; i++) {
++              struct scp_domain *scpd = &scp->domains[i];
++              struct generic_pm_domain *genpd = &scpd->genpd;
+               /*
+                * Initially turn on all domains to make the domains usable
+@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_
+        * valid.
+        */
++      pd_data = &scp->pd_data;
++
++      ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
++      if (ret)
++              dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
++}
++
++/*
++ * MT8173 power domain support
++ */
++
++static const struct scp_domain_data scp_domain_data_mt8173[] = {
++      [MT8173_POWER_DOMAIN_VDEC] = {
++              .name = "vdec",
++              .sta_mask = PWR_STATUS_VDEC,
++              .ctl_offs = SPM_VDE_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(12, 12),
++              .clk_id = {CLK_MM},
++      },
++      [MT8173_POWER_DOMAIN_VENC] = {
++              .name = "venc",
++              .sta_mask = PWR_STATUS_VENC,
++              .ctl_offs = SPM_VEN_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_MM, CLK_VENC},
++      },
++      [MT8173_POWER_DOMAIN_ISP] = {
++              .name = "isp",
++              .sta_mask = PWR_STATUS_ISP,
++              .ctl_offs = SPM_ISP_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(13, 12),
++              .clk_id = {CLK_MM},
++      },
++      [MT8173_POWER_DOMAIN_MM] = {
++              .name = "mm",
++              .sta_mask = PWR_STATUS_DISP,
++              .ctl_offs = SPM_DIS_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(12, 12),
++              .clk_id = {CLK_MM},
++              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
++                      MT8173_TOP_AXI_PROT_EN_MM_M1,
++      },
++      [MT8173_POWER_DOMAIN_VENC_LT] = {
++              .name = "venc_lt",
++              .sta_mask = PWR_STATUS_VENC_LT,
++              .ctl_offs = SPM_VEN2_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_MM, CLK_VENC_LT},
++      },
++      [MT8173_POWER_DOMAIN_AUDIO] = {
++              .name = "audio",
++              .sta_mask = PWR_STATUS_AUDIO,
++              .ctl_offs = SPM_AUDIO_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_NONE},
++      },
++      [MT8173_POWER_DOMAIN_USB] = {
++              .name = "usb",
++              .sta_mask = PWR_STATUS_USB,
++              .ctl_offs = SPM_USB_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_NONE},
++              .active_wakeup = true,
++      },
++      [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
++              .name = "mfg_async",
++              .sta_mask = PWR_STATUS_MFG_ASYNC,
++              .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = 0,
++              .clk_id = {CLK_MFG},
++      },
++      [MT8173_POWER_DOMAIN_MFG_2D] = {
++              .name = "mfg_2d",
++              .sta_mask = PWR_STATUS_MFG_2D,
++              .ctl_offs = SPM_MFG_2D_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(13, 12),
++              .clk_id = {CLK_NONE},
++      },
++      [MT8173_POWER_DOMAIN_MFG] = {
++              .name = "mfg",
++              .sta_mask = PWR_STATUS_MFG,
++              .ctl_offs = SPM_MFG_PWR_CON,
++              .sram_pdn_bits = GENMASK(13, 8),
++              .sram_pdn_ack_bits = GENMASK(21, 16),
++              .clk_id = {CLK_NONE},
++              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
++                      MT8173_TOP_AXI_PROT_EN_MFG_M0 |
++                      MT8173_TOP_AXI_PROT_EN_MFG_M1 |
++                      MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
++      },
++};
++
++#define NUM_DOMAINS_MT8173    ARRAY_SIZE(scp_domain_data_mt8173)
++
++static int __init scpsys_probe_mt8173(struct platform_device *pdev)
++{
++      struct scp *scp;
++      struct genpd_onecell_data *pd_data;
++      int ret;
++
++      scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
++      if (IS_ERR(scp))
++              return PTR_ERR(scp);
++
++      mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
++
++      pd_data = &scp->pd_data;
++
+       ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
+               pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
+       if (ret && IS_ENABLED(CONFIG_PM))
+@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_
+       if (ret && IS_ENABLED(CONFIG_PM))
+               dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+-      ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
+-      if (ret)
+-              dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
+-
+       return 0;
+ }
++/*
++ * scpsys driver init
++ */
++
+ static const struct of_device_id of_scpsys_match_tbl[] = {
+       {
+               .compatible = "mediatek,mt8173-scpsys",
++              .data = scpsys_probe_mt8173,
+       }, {
+               /* sentinel */
+       }
+ };
++static int scpsys_probe(struct platform_device *pdev)
++{
++      int (*probe)(struct platform_device *);
++      const struct of_device_id *of_id;
++
++      of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
++      if (!of_id || !of_id->data)
++              return -EINVAL;
++
++      probe = of_id->data;
++
++      return probe(pdev);
++}
++
+ static struct platform_driver scpsys_drv = {
+       .probe = scpsys_probe,
+       .driver = {
diff --git a/target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch
deleted file mode 100644 (file)
index 2cd1e75..0000000
+++ /dev/null
@@ -1,1431 +0,0 @@
-From a4c507d052390b42d7e8c59241e3c336796f730f Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang@mediatek.com>
-Date: Tue, 5 Jan 2016 14:30:20 +0800
-Subject: [PATCH 009/102] clk: mediatek: Add MT2701 clock support
-
-Add MT2701 clock support, include topckgen, apmixedsys,
-infracfg, pericfg and subsystem clocks.
-
-Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
-Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
----
- drivers/clk/mediatek/Kconfig      |    8 +
- drivers/clk/mediatek/Makefile     |    1 +
- drivers/clk/mediatek/clk-gate.c   |   56 ++
- drivers/clk/mediatek/clk-gate.h   |    2 +
- drivers/clk/mediatek/clk-mt2701.c | 1210 +++++++++++++++++++++++++++++++++++++
- drivers/clk/mediatek/clk-mtk.c    |   25 +
- drivers/clk/mediatek/clk-mtk.h    |   35 +-
- 7 files changed, 1334 insertions(+), 3 deletions(-)
- create mode 100644 drivers/clk/mediatek/clk-mt2701.c
-
---- a/drivers/clk/mediatek/Kconfig
-+++ b/drivers/clk/mediatek/Kconfig
-@@ -6,6 +6,14 @@ config COMMON_CLK_MEDIATEK
-       ---help---
-         Mediatek SoCs' clock support.
-+config COMMON_CLK_MT2701
-+      bool "Clock driver for Mediatek MT2701 and MT7623"
-+      depends on COMMON_CLK
-+      select COMMON_CLK_MEDIATEK
-+      default ARCH_MEDIATEK
-+      ---help---
-+        This driver supports Mediatek MT2701 and MT7623 clocks.
-+
- config COMMON_CLK_MT8135
-       bool "Clock driver for Mediatek MT8135"
-       depends on ARCH_MEDIATEK || COMPILE_TEST
---- a/drivers/clk/mediatek/Makefile
-+++ b/drivers/clk/mediatek/Makefile
-@@ -1,4 +1,5 @@
- obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
- obj-$(CONFIG_RESET_CONTROLLER) += reset.o
-+obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
- obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
- obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
---- a/drivers/clk/mediatek/clk-gate.c
-+++ b/drivers/clk/mediatek/clk-gate.c
-@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw
-       regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
- }
-+static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw)
-+{
-+      struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
-+      u32 val;
-+
-+      regmap_read(cg->regmap, cg->sta_ofs, &val);
-+      val |= BIT(cg->bit);
-+      regmap_write(cg->regmap, cg->sta_ofs, val);
-+}
-+
-+static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw)
-+{
-+      struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
-+      u32 val;
-+
-+      regmap_read(cg->regmap, cg->sta_ofs, &val);
-+      val &= ~(BIT(cg->bit));
-+      regmap_write(cg->regmap, cg->sta_ofs, val);
-+}
-+
- static int mtk_cg_enable(struct clk_hw *hw)
- {
-       mtk_cg_clr_bit(hw);
-@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct cl
-       mtk_cg_clr_bit(hw);
- }
-+static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
-+{
-+      mtk_cg_clr_bit_no_setclr(hw);
-+
-+      return 0;
-+}
-+
-+static void mtk_cg_disable_no_setclr(struct clk_hw *hw)
-+{
-+      mtk_cg_set_bit_no_setclr(hw);
-+}
-+
-+static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw)
-+{
-+      mtk_cg_set_bit_no_setclr(hw);
-+
-+      return 0;
-+}
-+
-+static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
-+{
-+      mtk_cg_clr_bit_no_setclr(hw);
-+}
-+
- const struct clk_ops mtk_clk_gate_ops_setclr = {
-       .is_enabled     = mtk_cg_bit_is_cleared,
-       .enable         = mtk_cg_enable,
-@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_se
-       .disable        = mtk_cg_disable_inv,
- };
-+const struct clk_ops mtk_clk_gate_ops_no_setclr = {
-+      .is_enabled     = mtk_cg_bit_is_cleared,
-+      .enable         = mtk_cg_enable_no_setclr,
-+      .disable        = mtk_cg_disable_no_setclr,
-+};
-+
-+const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
-+      .is_enabled     = mtk_cg_bit_is_set,
-+      .enable         = mtk_cg_enable_inv_no_setclr,
-+      .disable        = mtk_cg_disable_inv_no_setclr,
-+};
-+
- struct clk *mtk_clk_register_gate(
-               const char *name,
-               const char *parent_name,
---- a/drivers/clk/mediatek/clk-gate.h
-+++ b/drivers/clk/mediatek/clk-gate.h
-@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_mt
- extern const struct clk_ops mtk_clk_gate_ops_setclr;
- extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
-+extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
-+extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
- struct clk *mtk_clk_register_gate(
-               const char *name,
---- /dev/null
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -0,0 +1,1210 @@
-+/*
-+ * Copyright (c) 2014 MediaTek Inc.
-+ * Author: Shunli Wang <shunli.wang@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+
-+#include "clk-mtk.h"
-+#include "clk-gate.h"
-+
-+#include <dt-bindings/clock/mt2701-clk.h>
-+
-+static DEFINE_SPINLOCK(lock);
-+
-+static const struct mtk_fixed_clk top_fixed_clks[] __initconst = {
-+      FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m", 108 * MHZ),
-+      FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m", 400 * MHZ),
-+      FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m", 295750000),
-+      FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m", 340 * MHZ),
-+      FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m", 340 * MHZ),
-+      FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", 340 * MHZ),
-+      FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m", 300 * MHZ),
-+      FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", 27 * MHZ),
-+      FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", 416 * MHZ),
-+};
-+
-+static const struct mtk_fixed_factor top_fixed_divs[] __initconst = {
-+      FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1),
-+      FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
-+      FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3),
-+      FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
-+      FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7),
-+      FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2),
-+      FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4),
-+      FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8),
-+      FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16),
-+      FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2),
-+      FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4),
-+      FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8),
-+      FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2),
-+      FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4),
-+      FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2),
-+      FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4),
-+
-+      FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1),
-+      FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
-+      FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
-+      FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
-+      FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7),
-+      FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26),
-+      FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52),
-+      FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108),
-+      FACTOR(CLK_TOP_USB_PHY48M, "USB_PHY48M_CK", "univpll", 1, 26),
-+      FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2),
-+      FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4),
-+      FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8),
-+      FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1),
-+      FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2),
-+      FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4),
-+      FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8),
-+      FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16),
-+      FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32),
-+      FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2),
-+      FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4),
-+      FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8),
-+
-+      FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1),
-+      FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
-+      FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
-+      FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8),
-+
-+      FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1),
-+      FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
-+
-+      FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2),
-+      FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4),
-+      FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1),
-+
-+      FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1),
-+      FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2),
-+      FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4),
-+
-+      FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1),
-+      FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1),
-+      FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2),
-+
-+      FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1),
-+      FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2),
-+      FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4),
-+
-+      FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1),
-+      FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2),
-+      FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3),
-+
-+      FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1),
-+
-+      FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1),
-+      FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4),
-+      FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8),
-+      FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16),
-+      FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24),
-+
-+      FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3),
-+      FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3),
-+      FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3),
-+      FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1),
-+      FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1),
-+      FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8),
-+      FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793),
-+      FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1),
-+};
-+
-+static const char * const axi_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d2",
-+      "syspll_d5",
-+      "syspll1_d4",
-+      "univpll_d5",
-+      "univpll2_d2",
-+      "mmpll_d2",
-+      "dmpll_d2"
-+};
-+
-+static const char * const mem_parents[] __initconst = {
-+      "clk26m",
-+      "dmpll_ck"
-+};
-+
-+static const char * const ddrphycfg_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d8"
-+};
-+
-+static const char * const mm_parents[] __initconst = {
-+      "clk26m",
-+      "vencpll_ck",
-+      "syspll1_d2",
-+      "syspll1_d4",
-+      "univpll_d5",
-+      "univpll1_d2",
-+      "univpll2_d2",
-+      "dmpll_ck"
-+};
-+
-+static const char * const pwm_parents[] __initconst = {
-+      "clk26m",
-+      "univpll2_d4",
-+      "univpll3_d2",
-+      "univpll1_d4",
-+};
-+
-+static const char * const vdec_parents[] __initconst = {
-+      "clk26m",
-+      "vdecpll_ck",
-+      "syspll_d5",
-+      "syspll1_d4",
-+      "univpll_d5",
-+      "univpll2_d2",
-+      "vencpll_ck",
-+      "msdcpll_d2",
-+      "mmpll_d2"
-+};
-+
-+static const char * const mfg_parents[] __initconst = {
-+      "clk26m",
-+      "mmpll_ck",
-+      "dmpll_x2_ck",
-+      "msdcpll_ck",
-+      "clk26m",
-+      "syspll_d3",
-+      "univpll_d3",
-+      "univpll1_d2"
-+};
-+
-+static const char * const camtg_parents[] __initconst = {
-+      "clk26m",
-+      "univpll_d26",
-+      "univpll2_d2",
-+      "syspll3_d2",
-+      "syspll3_d4",
-+      "msdcpll_d2",
-+      "mmpll_d2"
-+};
-+
-+static const char * const uart_parents[] __initconst = {
-+      "clk26m",
-+      "univpll2_d8"
-+};
-+
-+static const char * const spi_parents[] __initconst = {
-+      "clk26m",
-+      "syspll3_d2",
-+      "syspll4_d2",
-+      "univpll2_d4",
-+      "univpll1_d8"
-+};
-+
-+static const char * const usb20_parents[] __initconst = {
-+      "clk26m",
-+      "univpll1_d8",
-+      "univpll3_d4"
-+};
-+
-+static const char * const msdc30_parents[] __initconst = {
-+      "clk26m",
-+      "msdcpll_d2",
-+      "syspll2_d2",
-+      "syspll1_d4",
-+      "univpll1_d4",
-+      "univpll2_d4"
-+};
-+
-+static const char * const audio_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d16"
-+};
-+
-+static const char * const aud_intbus_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d4",
-+      "syspll3_d2",
-+      "syspll4_d2",
-+      "univpll3_d2",
-+      "univpll2_d4"
-+};
-+
-+static const char * const pmicspi_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d8",
-+      "syspll2_d4",
-+      "syspll4_d2",
-+      "syspll3_d4",
-+      "syspll2_d8",
-+      "syspll1_d16",
-+      "univpll3_d4",
-+      "univpll_d26",
-+      "dmpll_d2",
-+      "dmpll_d4"
-+};
-+
-+static const char * const scp_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d8",
-+      "dmpll_d2",
-+      "dmpll_d4"
-+};
-+
-+static const char * const dpi0_parents[] __initconst = {
-+      "clk26m",
-+      "mipipll",
-+      "mipipll_d2",
-+      "mipipll_d4",
-+      "clk26m",
-+      "tvdpll_ck",
-+      "tvdpll_d2",
-+      "tvdpll_d4"
-+};
-+
-+static const char * const dpi1_parents[] __initconst = {
-+      "clk26m",
-+      "tvdpll_ck",
-+      "tvdpll_d2",
-+      "tvdpll_d4"
-+};
-+
-+static const char * const tve_parents[] __initconst = {
-+      "clk26m",
-+      "mipipll",
-+      "mipipll_d2",
-+      "mipipll_d4",
-+      "clk26m",
-+      "tvdpll_ck",
-+      "tvdpll_d2",
-+      "tvdpll_d4"
-+};
-+
-+static const char * const hdmi_parents[] __initconst = {
-+      "clk26m",
-+      "hdmipll_ck",
-+      "hdmipll_d2",
-+      "hdmipll_d3"
-+};
-+
-+static const char * const apll_parents[] __initconst = {
-+      "clk26m",
-+      "audpll",
-+      "audpll_d4",
-+      "audpll_d8",
-+      "audpll_d16",
-+      "audpll_d24",
-+      "clk26m",
-+      "clk26m"
-+};
-+
-+static const char * const rtc_parents[] __initconst = {
-+      "32k_internal",
-+      "32k_external",
-+      "clk26m",
-+      "univpll3_d8"
-+};
-+
-+static const char * const nfi2x_parents[] __initconst = {
-+      "clk26m",
-+      "syspll2_d2",
-+      "syspll_d7",
-+      "univpll3_d2",
-+      "syspll2_d4",
-+      "univpll3_d4",
-+      "syspll4_d4",
-+      "clk26m"
-+};
-+
-+static const char * const emmc_hclk_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d2",
-+      "syspll1_d4",
-+      "syspll2_d2"
-+};
-+
-+static const char * const flash_parents[] __initconst = {
-+      "clk26m_d8",
-+      "clk26m",
-+      "syspll2_d8",
-+      "syspll3_d4",
-+      "univpll3_d4",
-+      "syspll4_d2",
-+      "syspll2_d4",
-+      "univpll2_d4"
-+};
-+
-+static const char * const di_parents[] __initconst = {
-+      "clk26m",
-+      "tvd2pll_ck",
-+      "tvd2pll_d2",
-+      "clk26m"
-+};
-+
-+static const char * const nr_osd_parents[] __initconst = {
-+      "clk26m",
-+      "vencpll_ck",
-+      "syspll1_d2",
-+      "syspll1_d4",
-+      "univpll_d5",
-+      "univpll1_d2",
-+      "univpll2_d2",
-+      "dmpll_ck"
-+};
-+
-+static const char * const hdmirx_bist_parents[] __initconst = {
-+      "clk26m",
-+      "syspll_d3",
-+      "clk26m",
-+      "syspll1_d16",
-+      "syspll4_d2",
-+      "syspll1_d4",
-+      "vencpll_ck",
-+      "clk26m"
-+};
-+
-+static const char * const intdir_parents[] __initconst = {
-+      "clk26m",
-+      "mmpll_ck",
-+      "syspll_d2",
-+      "univpll_d2"
-+};
-+
-+static const char * const asm_parents[] __initconst = {
-+      "clk26m",
-+      "univpll2_d4",
-+      "univpll2_d2",
-+      "syspll_d5"
-+};
-+
-+static const char * const ms_card_parents[] __initconst = {
-+      "clk26m",
-+      "univpll3_d8",
-+      "syspll4_d4"
-+};
-+
-+static const char * const ethif_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d2",
-+      "syspll_d5",
-+      "syspll1_d4",
-+      "univpll_d5",
-+      "univpll1_d2",
-+      "dmpll_ck",
-+      "dmpll_d2"
-+};
-+
-+static const char * const hdmirx_parents[] __initconst = {
-+      "clk26m",
-+      "univpll_d52"
-+};
-+
-+static const char * const cmsys_parents[] __initconst = {
-+      "clk26m",
-+      "syspll1_d2",
-+      "univpll1_d2",
-+      "univpll_d5",
-+      "syspll_d5",
-+      "syspll2_d2",
-+      "syspll1_d4",
-+      "syspll3_d2",
-+      "syspll2_d4",
-+      "syspll1_d8",
-+      "clk26m",
-+      "clk26m",
-+      "clk26m",
-+      "clk26m",
-+      "clk26m"
-+};
-+
-+static const char * const clk_8bdac_parents[] __initconst = {
-+      "clkrtc_int",
-+      "8bdac_ck_pre",
-+      "clk26m",
-+      "clk26m"
-+};
-+
-+static const char * const aud2dvd_parents[] __initconst = {
-+      "a1sys_hp_ck",
-+      "a2sys_hp_ck"
-+};
-+
-+static const char * const padmclk_parents[] __initconst = {
-+      "clk26m",
-+      "univpll_d26",
-+      "univpll_d52",
-+      "univpll_d108",
-+      "univpll2_d8",
-+      "univpll2_d16",
-+      "univpll2_d32"
-+};
-+
-+static const char * const aud_mux_parents[] __initconst = {
-+      "clk26m",
-+      "aud1pll_98m_ck",
-+      "aud2pll_90m_ck",
-+      "hadds2pll_98m",
-+      "audio_ext1_ck",
-+      "audio_ext2_ck"
-+};
-+
-+static const char * const aud_src_parents[] __initconst = {
-+      "aud_mux1_sel",
-+      "aud_mux2_sel"
-+};
-+
-+static const char * const cpu_parents[] __initconst = {
-+      "clk26m",
-+      "armpll",
-+      "mainpll",
-+      "mmpll"
-+};
-+
-+static const struct mtk_composite top_muxes[] __initconst = {
-+      MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
-+              0x0040, 0, 3, INVALID_MUX_GATE_BIT),
-+      MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1, 15),
-+      MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23),
-+      MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7),
-+      MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15),
-+      MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 16, 3, 23),
-+      MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0050, 24, 3, 31),
-+      MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 0, 1, 7),
-+
-+      MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents, 0x0060, 8, 3, 15),
-+      MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 16, 2, 23),
-+      MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0060, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0070, 0, 3, 7),
-+      MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0070, 8, 3, 15),
-+      MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents, 0x0070, 16, 1, 23),
-+      MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0070, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0080, 0, 4, 7),
-+      MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0080, 8, 2, 15),
-+      MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x0080, 16, 3, 23),
-+      MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0080, 24, 2, 31),
-+
-+      MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, 0x0090, 0, 3, 7),
-+      MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x0090, 8, 2, 15),
-+      MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0090, 16, 3, 23),
-+
-+      MUX_GATE(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00A0, 0, 2, 7),
-+      MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, 0x00A0, 8, 3, 15),
-+      MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents, 0x00A0, 24, 2, 31),
-+
-+      MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, 0x00B0, 0, 3, 7),
-+      MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, 0x00B0, 8, 2, 15),
-+      MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents, 0x00B0, 16, 3, 23),
-+      MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents, 0x00B0, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel", hdmirx_bist_parents, 0x00C0, 0, 3, 7),
-+      MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, 0x00C0, 8, 2, 15),
-+      MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents, 0x00C0, 16, 2, 23),
-+      MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents, 0x00C0, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents, 0x00D0, 0, 2, 7),
-+      MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents, 0x00D0, 16, 2, 23),
-+      MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents, 0x00D0, 24, 3, 31),
-+
-+      MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents, 0x00E0, 0, 1, 7),
-+      MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x00E0, 8, 3, 15),
-+      MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, 0x00E0, 16, 4, 23),
-+
-+      MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents, 0x00E0, 24, 3, 31),
-+      MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents, 0x00F0, 0, 3, 7),
-+      MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents, 0x00F0, 8, 2, 15),
-+      MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents, 0x00F0, 16, 1, 23),
-+
-+      MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents, 0x0100, 0, 3),
-+
-+      MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents, 0x012c, 0, 3),
-+      MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents, 0x012c, 3, 3),
-+      MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents, 0x012c, 6, 3),
-+      MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents, 0x012c, 15, 1, 23),
-+      MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents, 0x012c, 16, 1, 24),
-+      MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents, 0x012c, 17, 1, 25),
-+      MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents, 0x012c, 18, 1, 26),
-+      MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents, 0x012c, 19, 1, 27),
-+      MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents, 0x012c, 20, 1, 28),
-+};
-+
-+static const struct mtk_clk_divider top_adj_divs[] __initconst = {
-+      DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext_ck1", 0x0120, 0, 8),
-+      DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext_ck2", 0x0120, 8, 8),
-+      DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel", 0x0120, 16, 8),
-+      DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel", 0x0120, 24, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel", 0x0124, 0, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel", 0x0124, 8, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel", 0x0124, 16, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel", 0x0124, 24, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel", 0x0128, 0, 8),
-+      DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel", 0x0128, 8, 8),
-+};
-+
-+static const struct mtk_gate_regs top_aud_cg_regs __initconst = {
-+      .sta_ofs = 0x012C,
-+};
-+
-+#define GATE_TOP_AUD(_id, _name, _parent, _shift) {   \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &top_aud_cg_regs,               \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_no_setclr,     \
-+      }
-+
-+static const struct mtk_gate top_clks[] __initconst = {
-+      GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", 21),
-+      GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div", 22),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div", 23),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div", 24),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div", 25),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div", 26),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div", 27),
-+      GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
-+};
-+
-+static void __init mtk_topckgen_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      void __iomem *base;
-+      int r;
-+
-+      base = of_iomap(node, 0);
-+      if (!base) {
-+              pr_err("%s(): ioremap failed\n", __func__);
-+              return;
-+      }
-+
-+      clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
-+
-+      mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
-+                                                              clk_data);
-+
-+      mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
-+                                                              clk_data);
-+
-+      mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes),
-+                              base, &lock, clk_data);
-+
-+      mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs),
-+                              base, &lock, clk_data);
-+
-+      mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
-+
-+static const struct mtk_gate_regs infra_cg_regs __initconst = {
-+      .set_ofs = 0x0040,
-+      .clr_ofs = 0x0044,
-+      .sta_ofs = 0x0048,
-+};
-+
-+#define GATE_ICG(_id, _name, _parent, _shift) {               \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &infra_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+static const struct mtk_gate infra_clks[] __initconst = {
-+      GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0),
-+      GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1),
-+      GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2),
-+      GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2_294m_ck", 4),
-+      GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk_null", 5),
-+      GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6),
-+      GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7),
-+      GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
-+      GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12),
-+      GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13),
-+      GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14),
-+      GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15),
-+      GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16),
-+      GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18),
-+      GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19),
-+      GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22),
-+      GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23),
-+      GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24),
-+};
-+
-+static const struct mtk_fixed_factor infra_fixed_divs[] __initconst = {
-+      FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2),
-+};
-+
-+static void __init mtk_infrasys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
-+
-+      mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
-+                                              clk_data);
-+      mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
-+
-+static const struct mtk_gate_regs peri0_cg_regs __initconst = {
-+      .set_ofs = 0x0008,
-+      .clr_ofs = 0x0010,
-+      .sta_ofs = 0x0018,
-+};
-+
-+static const struct mtk_gate_regs peri1_cg_regs __initconst = {
-+      .set_ofs = 0x000c,
-+      .clr_ofs = 0x0014,
-+      .sta_ofs = 0x001c,
-+};
-+
-+#define GATE_PERI0(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &peri0_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+#define GATE_PERI1(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &peri1_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+static const struct mtk_gate peri_clks[] __initconst = {
-+      GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31),
-+      GATE_PERI1(CLK_PERI_ETH, "eth_ck", "clk26m", 30),
-+      GATE_PERI1(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29),
-+      GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28),
-+      GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27),
-+      GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26),
-+      GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25),
-+      GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24),
-+      GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23),
-+      GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22),
-+      GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21),
-+      GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20),
-+      GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19),
-+      GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18),
-+      GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17),
-+      GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16),
-+      GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15),
-+      GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14),
-+      GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13),
-+      GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12),
-+      GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11),
-+      GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10),
-+      GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9),
-+      GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8),
-+      GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7),
-+      GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6),
-+      GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5),
-+      GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4),
-+      GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3),
-+      GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2),
-+      GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1),
-+      GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0),
-+
-+      GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card", 11),
-+      GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10),
-+      GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9),
-+      GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8),
-+      GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7),
-+      GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6),
-+      GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5),
-+      GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi_sel", 4),
-+      GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi_sel", 3),
-+      GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2),
-+      GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1),
-+      GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0),
-+};
-+
-+static const char * const uart_ck_sel_parents[] __initconst = {
-+      "clk26m",
-+      "uart_sel",
-+};
-+
-+static const struct mtk_composite peri_muxs[] __initconst = {
-+      MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1),
-+      MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1),
-+      MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1),
-+      MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1),
-+};
-+
-+static void __init mtk_pericfg_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      void __iomem *base;
-+      int r;
-+
-+      base = of_iomap(node, 0);
-+      if (!base) {
-+              pr_err("%s(): ioremap failed\n", __func__);
-+              return;
-+      }
-+
-+      clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
-+
-+      mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks),
-+                                              clk_data);
-+
-+      mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base,
-+                      &lock, clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
-+
-+static const struct mtk_gate_regs disp0_cg_regs __initconst = {
-+      .set_ofs = 0x0104,
-+      .clr_ofs = 0x0108,
-+      .sta_ofs = 0x0100,
-+};
-+
-+static const struct mtk_gate_regs disp1_cg_regs __initconst = {
-+      .set_ofs = 0x0114,
-+      .clr_ofs = 0x0118,
-+      .sta_ofs = 0x0110,
-+};
-+
-+#define GATE_DISP0(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &disp0_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+#define GATE_DISP1(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &disp1_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+static const struct mtk_gate mm_clks[] __initconst = {
-+      GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0),
-+      GATE_DISP0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1),
-+      GATE_DISP0(CLK_MM_CMDQ, "mm_cmdq", "mm_sel", 2),
-+      GATE_DISP0(CLK_MM_MUTEX, "mm_mutex", "mm_sel", 3),
-+      GATE_DISP0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 4),
-+      GATE_DISP0(CLK_MM_DISP_BLS, "mm_disp_bls", "mm_sel", 5),
-+      GATE_DISP0(CLK_MM_DISP_WDMA, "mm_disp_wdma", "mm_sel", 6),
-+      GATE_DISP0(CLK_MM_DISP_RDMA, "mm_disp_rdma", "mm_sel", 7),
-+      GATE_DISP0(CLK_MM_DISP_OVL, "mm_disp_ovl", "mm_sel", 8),
-+      GATE_DISP0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9),
-+      GATE_DISP0(CLK_MM_MDP_WROT, "mm_mdp_wrot", "mm_sel", 10),
-+      GATE_DISP0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11),
-+      GATE_DISP0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 12),
-+      GATE_DISP0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 13),
-+      GATE_DISP0(CLK_MM_MDP_RDMA, "mm_mdp_rdma", "mm_sel", 14),
-+      GATE_DISP0(CLK_MM_MDP_BLS_26M, "mm_mdp_bls_26m", "clk26m", 15),
-+      GATE_DISP0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 16),
-+      GATE_DISP0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 17),
-+      GATE_DISP0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "rtc_sel", 18),
-+      GATE_DISP0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19),
-+      GATE_DISP0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 20),
-+      GATE_DISP1(CLK_MM_DSI_ENGINE, "mm_dsi_eng", "mm_sel", 0),
-+      GATE_DISP1(CLK_MM_DSI_DIG, "mm_dsi_dig", "dsio_lntc_dsiclk", 1),
-+      GATE_DISP1(CLK_MM_DPI_DIGL, "mm_dpi_digl", "dpi0_sel", 2),
-+      GATE_DISP1(CLK_MM_DPI_ENGINE, "mm_dpi_eng", "mm_sel", 3),
-+      GATE_DISP1(CLK_MM_DPI1_DIGL, "mm_dpi1_digl", "dpi1_sel", 4),
-+      GATE_DISP1(CLK_MM_DPI1_ENGINE, "mm_dpi1_eng", "mm_sel", 5),
-+      GATE_DISP1(CLK_MM_TVE_OUTPUT, "mm_tve_output", "tve_sel", 6),
-+      GATE_DISP1(CLK_MM_TVE_INPUT, "mm_tve_input", "dpi0_sel", 7),
-+      GATE_DISP1(CLK_MM_HDMI_PIXEL, "mm_hdmi_pixel", "dpi1_sel", 8),
-+      GATE_DISP1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmi_sel", 9),
-+      GATE_DISP1(CLK_MM_HDMI_AUDIO, "mm_hdmi_audio", "apll_sel", 10),
-+      GATE_DISP1(CLK_MM_HDMI_SPDIF, "mm_hdmi_spdif", "apll_sel", 11),
-+      GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14),
-+};
-+
-+static void __init mtk_mmsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_MM_NR);
-+
-+      mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_mmsys, "mediatek,mt2701-mmsys", mtk_mmsys_init);
-+
-+static const struct mtk_gate_regs img_cg_regs __initconst = {
-+      .set_ofs = 0x0004,
-+      .clr_ofs = 0x0008,
-+      .sta_ofs = 0x0000,
-+};
-+
-+#define GATE_IMG(_id, _name, _parent, _shift) {               \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &img_cg_regs,                   \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr,        \
-+      }
-+
-+static const struct mtk_gate img_clks[] __initconst = {
-+      GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0),
-+      GATE_IMG(CLK_IMG_RESZ, "img_resz", "mm_sel", 1),
-+      GATE_IMG(CLK_IMG_JPGDEC, "img_jpgdec", "mm_sel", 5),
-+      GATE_IMG(CLK_IMG_VENC_LT, "img_venc_lt", "mm_sel", 8),
-+      GATE_IMG(CLK_IMG_VENC, "img_venc", "mm_sel", 9),
-+};
-+
-+static void __init mtk_imgsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_IMG_NR);
-+
-+      mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt2701-imgsys", mtk_imgsys_init);
-+
-+static const struct mtk_gate_regs vdec0_cg_regs __initconst = {
-+      .set_ofs = 0x0000,
-+      .clr_ofs = 0x0004,
-+      .sta_ofs = 0x0000,
-+};
-+
-+static const struct mtk_gate_regs vdec1_cg_regs __initconst = {
-+      .set_ofs = 0x0008,
-+      .clr_ofs = 0x000c,
-+      .sta_ofs = 0x0008,
-+};
-+
-+#define GATE_VDEC0(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &vdec0_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr_inv,    \
-+      }
-+
-+#define GATE_VDEC1(_id, _name, _parent, _shift) {     \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &vdec1_cg_regs,                 \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr_inv,    \
-+      }
-+
-+static const struct mtk_gate vdec_clks[] __initconst = {
-+      GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0),
-+      GATE_VDEC1(CLK_VDEC_LARB, "vdec_larb_cken", "mm_sel", 0),
-+};
-+
-+static void __init mtk_vdecsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_VDEC_NR);
-+
-+      mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt2701-vdecsys", mtk_vdecsys_init);
-+
-+static const struct mtk_gate_regs hif_cg_regs __initconst = {
-+      .sta_ofs = 0x0008,
-+};
-+
-+#define GATE_HIF(_id, _name, _parent, _shift) {               \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &hif_cg_regs,                   \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_no_setclr_inv, \
-+      }
-+
-+static const struct mtk_gate hif_clks[] __initconst = {
-+      GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21),
-+      GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22),
-+      GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24),
-+      GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25),
-+      GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26),
-+};
-+
-+static void __init mtk_hifsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR);
-+
-+      mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
-+
-+static const struct mtk_gate_regs eth_cg_regs __initconst = {
-+      .sta_ofs = 0x0030,
-+};
-+
-+#define GATE_eth(_id, _name, _parent, _shift) {               \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &eth_cg_regs,                   \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_no_setclr_inv, \
-+      }
-+
-+static const struct mtk_gate eth_clks[] __initconst = {
-+      GATE_HIF(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5),
-+      GATE_HIF(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6),
-+      GATE_HIF(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7),
-+      GATE_HIF(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8),
-+      GATE_HIF(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11),
-+      GATE_HIF(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14),
-+      GATE_HIF(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17),
-+      GATE_HIF(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29),
-+};
-+
-+static void __init mtk_ethsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR);
-+
-+      mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
-+
-+static const struct mtk_gate_regs bdp0_cg_regs __initconst = {
-+      .set_ofs = 0x0104,
-+      .clr_ofs = 0x0108,
-+      .sta_ofs = 0x0100,
-+};
-+
-+static const struct mtk_gate_regs bdp1_cg_regs __initconst = {
-+      .set_ofs = 0x0114,
-+      .clr_ofs = 0x0118,
-+      .sta_ofs = 0x0110,
-+};
-+
-+#define GATE_BDP0(_id, _name, _parent, _shift) {      \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &bdp0_cg_regs,                  \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr_inv,    \
-+      }
-+
-+#define GATE_BDP1(_id, _name, _parent, _shift) {      \
-+              .id = _id,                              \
-+              .name = _name,                          \
-+              .parent_name = _parent,                 \
-+              .regs = &bdp1_cg_regs,                  \
-+              .shift = _shift,                        \
-+              .ops = &mtk_clk_gate_ops_setclr_inv,    \
-+      }
-+
-+static const struct mtk_gate bdp_clks[] __initconst = {
-+      GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0),
-+      GATE_BDP0(CLK_BDP_BRG_DRAM, "brg_dram", "mm_sel", 1),
-+      GATE_BDP0(CLK_BDP_LARB_DRAM, "larb_dram", "mm_sel", 2),
-+      GATE_BDP0(CLK_BDP_WR_VDI_PXL, "wr_vdi_pxl", "hdmi_0_deep340m", 3),
-+      GATE_BDP0(CLK_BDP_WR_VDI_DRAM, "wr_vdi_dram", "mm_sel", 4),
-+      GATE_BDP0(CLK_BDP_WR_B, "wr_bclk", "mm_sel", 5),
-+      GATE_BDP0(CLK_BDP_DGI_IN, "dgi_in", "dpi1_sel", 6),
-+      GATE_BDP0(CLK_BDP_DGI_OUT, "dgi_out", "dpi_sel", 7),
-+      GATE_BDP0(CLK_BDP_FMT_MAST_27, "fmt_mast_27", "dpi1_sel", 8),
-+      GATE_BDP0(CLK_BDP_FMT_B, "fmt_bclk", "mm_sel", 9),
-+      GATE_BDP0(CLK_BDP_OSD_B, "osd_bclk", "mm_sel", 10),
-+      GATE_BDP0(CLK_BDP_OSD_DRAM, "osd_dram", "mm_sel", 11),
-+      GATE_BDP0(CLK_BDP_OSD_AGENT, "osd_agent", "osd_sel", 12),
-+      GATE_BDP0(CLK_BDP_OSD_PXL, "osd_pxl", "dpi1_sel", 13),
-+      GATE_BDP0(CLK_BDP_RLE_B, "rle_bclk", "mm_sel", 14),
-+      GATE_BDP0(CLK_BDP_RLE_AGENT, "rle_agent", "mm_sel", 15),
-+      GATE_BDP0(CLK_BDP_RLE_DRAM, "rle_dram", "mm_sel", 16),
-+      GATE_BDP0(CLK_BDP_F27M, "f27m", "di_sel", 17),
-+      GATE_BDP0(CLK_BDP_F27M_VDOUT, "f27m_vdout", "di_sel", 18),
-+      GATE_BDP0(CLK_BDP_F27_74_74, "f27_74_74", "di_sel", 19),
-+      GATE_BDP0(CLK_BDP_F2FS, "f2fs", "di_sel", 20),
-+      GATE_BDP0(CLK_BDP_F2FS74_148, "f2fs74_148", "di_sel", 21),
-+      GATE_BDP0(CLK_BDP_FB, "fbclk", "mm_sel", 22),
-+      GATE_BDP0(CLK_BDP_VDO_DRAM, "vdo_dram", "mm_sel", 23),
-+      GATE_BDP0(CLK_BDP_VDO_2FS, "vdo_2fs", "di_sel", 24),
-+      GATE_BDP0(CLK_BDP_VDO_B, "vdo_bclk", "mm_sel", 25),
-+      GATE_BDP0(CLK_BDP_WR_DI_PXL, "wr_di_pxl", "di_sel", 26),
-+      GATE_BDP0(CLK_BDP_WR_DI_DRAM, "wr_di_dram", "mm_sel", 27),
-+      GATE_BDP0(CLK_BDP_WR_DI_B, "wr_di_bclk", "mm_sel", 28),
-+      GATE_BDP0(CLK_BDP_NR_PXL, "nr_pxl", "nr_sel", 29),
-+      GATE_BDP0(CLK_BDP_NR_DRAM, "nr_dram", "mm_sel", 30),
-+      GATE_BDP0(CLK_BDP_NR_B, "nr_bclk", "mm_sel", 31),
-+      GATE_BDP1(CLK_BDP_RX_F, "rx_fclk", "hadds2_fbclk", 0),
-+      GATE_BDP1(CLK_BDP_RX_X, "rx_xclk", "clk26m", 1),
-+      GATE_BDP1(CLK_BDP_RXPDT, "rxpdtclk", "hdmi_0_pix340m", 2),
-+      GATE_BDP1(CLK_BDP_RX_CSCL_N, "rx_cscl_n", "clk26m", 3),
-+      GATE_BDP1(CLK_BDP_RX_CSCL, "rx_cscl", "clk26m", 4),
-+      GATE_BDP1(CLK_BDP_RX_DDCSCL_N, "rx_ddcscl_n", "hdmi_scl_rx", 5),
-+      GATE_BDP1(CLK_BDP_RX_DDCSCL, "rx_ddcscl", "hdmi_scl_rx", 6),
-+      GATE_BDP1(CLK_BDP_RX_VCO, "rx_vcoclk", "hadds2pll_294m", 7),
-+      GATE_BDP1(CLK_BDP_RX_DP, "rx_dpclk", "hdmi_0_pll340m", 8),
-+      GATE_BDP1(CLK_BDP_RX_P, "rx_pclk", "hdmi_0_pll340m", 9),
-+      GATE_BDP1(CLK_BDP_RX_M, "rx_mclk", "hadds2pll_294m", 10),
-+      GATE_BDP1(CLK_BDP_RX_PLL, "rx_pllclk", "hdmi_0_pix340m", 11),
-+      GATE_BDP1(CLK_BDP_BRG_RT_B, "brg_rt_bclk", "mm_sel", 12),
-+      GATE_BDP1(CLK_BDP_BRG_RT_DRAM, "brg_rt_dram", "mm_sel", 13),
-+      GATE_BDP1(CLK_BDP_LARBRT_DRAM, "larbrt_dram", "mm_sel", 14),
-+      GATE_BDP1(CLK_BDP_TMDS_SYN, "tmds_syn", "hdmi_0_pll340m", 15),
-+      GATE_BDP1(CLK_BDP_HDMI_MON, "hdmi_mon", "hdmi_0_mon", 16),
-+};
-+
-+static void __init mtk_bdpsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(CLK_BDP_NR);
-+
-+      mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks),
-+                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_bdpsys, "mediatek,mt2701-bdpsys", mtk_bdpsys_init);
-+
-+#define MT8590_PLL_FMAX               (2000 * MHZ)
-+#define CON0_MT8590_RST_BAR   BIT(27)
-+
-+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \
-+                      _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) {  \
-+              .id = _id,                                              \
-+              .name = _name,                                          \
-+              .reg = _reg,                                            \
-+              .pwr_reg = _pwr_reg,                                    \
-+              .en_mask = _en_mask,                                    \
-+              .flags = _flags,                                        \
-+              .rst_bar_mask = CON0_MT8590_RST_BAR,                    \
-+              .fmax = MT8590_PLL_FMAX,                                \
-+              .pcwbits = _pcwbits,                                    \
-+              .pd_reg = _pd_reg,                                      \
-+              .pd_shift = _pd_shift,                                  \
-+              .tuner_reg = _tuner_reg,                                \
-+              .pcw_reg = _pcw_reg,                                    \
-+              .pcw_shift = _pcw_shift,                                \
-+      }
-+
-+static const struct mtk_pll_data apmixed_plls[] = {
-+      PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001, 0,
-+                              21, 0x204, 24, 0x0, 0x204, 0),
-+      PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001,
-+                HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0),
-+      PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001,
-+                HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14),
-+      PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0,
-+                              21, 0x230, 4, 0x0, 0x234, 0),
-+      PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0,
-+                              21, 0x240, 4, 0x0, 0x244, 0),
-+      PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0,
-+                              21, 0x250, 4, 0x0, 0x254, 0),
-+      PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0,
-+                              31, 0x270, 4, 0x0, 0x274, 0),
-+      PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0,
-+                              31, 0x280, 4, 0x0, 0x284, 0),
-+      PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0,
-+                              31, 0x290, 4, 0x0, 0x294, 0),
-+      PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0,
-+                              31, 0x2a0, 4, 0x0, 0x2a4, 0),
-+      PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0,
-+                              31, 0x2b0, 4, 0x0, 0x2b4, 0),
-+      PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0,
-+                              31, 0x2c0, 4, 0x0, 0x2c4, 0),
-+      PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0,
-+                              21, 0x2d0, 4, 0x0, 0x2d4, 0),
-+};
-+
-+static void __init mtk_apmixedsys_init(struct device_node *node)
-+{
-+      struct clk_onecell_data *clk_data;
-+      int r;
-+
-+      clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
-+      if (!clk_data)
-+              return;
-+
-+      mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls),
-+                                                              clk_data);
-+
-+      r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-+      if (r)
-+              pr_err("%s(): could not register clock provider: %d\n",
-+                      __func__, r);
-+}
-+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
-+                                                      mtk_apmixedsys_init);
---- a/drivers/clk/mediatek/clk-mtk.c
-+++ b/drivers/clk/mediatek/clk-mtk.c
-@@ -244,3 +244,28 @@ void mtk_clk_register_composites(const s
-                       clk_data->clks[mc->id] = clk;
-       }
- }
-+
-+void __init mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
-+                      int num, void __iomem *base, spinlock_t *lock,
-+                              struct clk_onecell_data *clk_data)
-+{
-+      struct clk *clk;
-+      int i;
-+
-+      for (i = 0; i <  num; i++) {
-+              const struct mtk_clk_divider *mcd = &mcds[i];
-+
-+              clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
-+                      mcd->flags, base +  mcd->div_reg, mcd->div_shift,
-+                      mcd->div_width, mcd->clk_divider_flags, lock);
-+
-+              if (IS_ERR(clk)) {
-+                      pr_err("Failed to register clk %s: %ld\n",
-+                              mcd->name, PTR_ERR(clk));
-+                      continue;
-+              }
-+
-+              if (clk_data)
-+                      clk_data->clks[mcd->id] = clk;
-+      }
-+}
---- a/drivers/clk/mediatek/clk-mtk.h
-+++ b/drivers/clk/mediatek/clk-mtk.h
-@@ -121,7 +121,8 @@ struct mtk_composite {
-               .flags = CLK_SET_RATE_PARENT,                           \
-       }
--#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) {     \
-+#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,       \
-+                                      _div_width, _div_shift) {       \
-               .id = _id,                                              \
-               .parent = _parent,                                      \
-               .name = _name,                                          \
-@@ -156,8 +157,36 @@ struct mtk_gate {
-       const struct clk_ops *ops;
- };
--int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
--              int num, struct clk_onecell_data *clk_data);
-+int mtk_clk_register_gates(struct device_node *node,
-+                      const struct mtk_gate *clks, int num,
-+                      struct clk_onecell_data *clk_data);
-+
-+struct mtk_clk_divider {
-+      int id;
-+      const char *name;
-+      const char *parent_name;
-+      unsigned long flags;
-+
-+      uint32_t div_reg;
-+      unsigned char div_shift;
-+      unsigned char div_width;
-+      unsigned char clk_divider_flags;
-+      const struct clk_div_table *clk_div_table;
-+};
-+
-+#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) {  \
-+              .id = _id,                                      \
-+              .name = _name,                                  \
-+              .parent_name = _parent,                         \
-+              .flags = CLK_SET_RATE_PARENT,                   \
-+              .div_reg = _reg,                                \
-+              .div_shift = _shift,                            \
-+              .div_width = _width,                            \
-+}
-+
-+void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
-+                      int num, void __iomem *base, spinlock_t *lock,
-+                              struct clk_onecell_data *clk_data);
- struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
diff --git a/target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch
new file mode 100644 (file)
index 0000000..0b47635
--- /dev/null
@@ -0,0 +1,194 @@
+From fb9f97e047f5a831a54cd61529b8cfdc4d413bb6 Mon Sep 17 00:00:00 2001
+From: Shunli Wang <shunli.wang@mediatek.com>
+Date: Thu, 20 Oct 2016 16:56:38 +0800
+Subject: [PATCH 09/57] soc: mediatek: Add MT2701 scpsys driver
+
+Add scpsys driver for MT2701.
+
+mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
+be enabled on both arm64 and arm platforms.
+
+Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
+Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ drivers/soc/mediatek/Kconfig      |   2 +-
+ drivers/soc/mediatek/mtk-scpsys.c | 108 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 108 insertions(+), 2 deletions(-)
+
+--- a/drivers/soc/mediatek/Kconfig
++++ b/drivers/soc/mediatek/Kconfig
+@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
+ config MTK_SCPSYS
+       bool "MediaTek SCPSYS Support"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+-      default ARM64 && ARCH_MEDIATEK
++      default ARCH_MEDIATEK
+       select REGMAP
+       select MTK_INFRACFG
+       select PM_GENERIC_DOMAINS if PM
+--- a/drivers/soc/mediatek/mtk-scpsys.c
++++ b/drivers/soc/mediatek/mtk-scpsys.c
+@@ -20,6 +20,7 @@
+ #include <linux/regulator/consumer.h>
+ #include <linux/soc/mediatek/infracfg.h>
++#include <dt-bindings/power/mt2701-power.h>
+ #include <dt-bindings/power/mt8173-power.h>
+ #define SPM_VDE_PWR_CON                       0x0210
+@@ -27,8 +28,13 @@
+ #define SPM_VEN_PWR_CON                       0x0230
+ #define SPM_ISP_PWR_CON                       0x0238
+ #define SPM_DIS_PWR_CON                       0x023c
++#define SPM_CONN_PWR_CON              0x0280
+ #define SPM_VEN2_PWR_CON              0x0298
+-#define SPM_AUDIO_PWR_CON             0x029c
++#define SPM_AUDIO_PWR_CON             0x029c  /* MT8173 */
++#define SPM_BDP_PWR_CON                       0x029c  /* MT2701 */
++#define SPM_ETH_PWR_CON                       0x02a0
++#define SPM_HIF_PWR_CON                       0x02a4
++#define SPM_IFR_MSC_PWR_CON           0x02a8
+ #define SPM_MFG_2D_PWR_CON            0x02c0
+ #define SPM_MFG_ASYNC_PWR_CON         0x02c4
+ #define SPM_USB_PWR_CON                       0x02cc
+@@ -42,10 +48,15 @@
+ #define PWR_ON_2ND_BIT                        BIT(3)
+ #define PWR_CLK_DIS_BIT                       BIT(4)
++#define PWR_STATUS_CONN                       BIT(1)
+ #define PWR_STATUS_DISP                       BIT(3)
+ #define PWR_STATUS_MFG                        BIT(4)
+ #define PWR_STATUS_ISP                        BIT(5)
+ #define PWR_STATUS_VDEC                       BIT(7)
++#define PWR_STATUS_BDP                        BIT(14)
++#define PWR_STATUS_ETH                        BIT(15)
++#define PWR_STATUS_HIF                        BIT(16)
++#define PWR_STATUS_IFR_MSC            BIT(17)
+ #define PWR_STATUS_VENC_LT            BIT(20)
+ #define PWR_STATUS_VENC                       BIT(21)
+ #define PWR_STATUS_MFG_2D             BIT(22)
+@@ -59,6 +70,7 @@ enum clk_id {
+       CLK_MFG,
+       CLK_VENC,
+       CLK_VENC_LT,
++      CLK_ETHIF,
+       CLK_MAX,
+ };
+@@ -68,6 +80,7 @@ static const char * const clk_names[] =
+       "mfg",
+       "venc",
+       "venc_lt",
++      "ethif",
+       NULL,
+ };
+@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s
+ }
+ /*
++ * MT2701 power domain support
++ */
++
++static const struct scp_domain_data scp_domain_data_mt2701[] = {
++      [MT2701_POWER_DOMAIN_CONN] = {
++              .name = "conn",
++              .sta_mask = PWR_STATUS_CONN,
++              .ctl_offs = SPM_CONN_PWR_CON,
++              .bus_prot_mask = 0x0104,
++              .clk_id = {CLK_NONE},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_DISP] = {
++              .name = "disp",
++              .sta_mask = PWR_STATUS_DISP,
++              .ctl_offs = SPM_DIS_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .clk_id = {CLK_MM},
++              .bus_prot_mask = 0x0002,
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_VDEC] = {
++              .name = "vdec",
++              .sta_mask = PWR_STATUS_VDEC,
++              .ctl_offs = SPM_VDE_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(12, 12),
++              .clk_id = {CLK_MM},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_ISP] = {
++              .name = "isp",
++              .sta_mask = PWR_STATUS_ISP,
++              .ctl_offs = SPM_ISP_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(13, 12),
++              .clk_id = {CLK_MM},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_BDP] = {
++              .name = "bdp",
++              .sta_mask = PWR_STATUS_BDP,
++              .ctl_offs = SPM_BDP_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .clk_id = {CLK_NONE},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_ETH] = {
++              .name = "eth",
++              .sta_mask = PWR_STATUS_ETH,
++              .ctl_offs = SPM_ETH_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_ETHIF},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_HIF] = {
++              .name = "hif",
++              .sta_mask = PWR_STATUS_HIF,
++              .ctl_offs = SPM_HIF_PWR_CON,
++              .sram_pdn_bits = GENMASK(11, 8),
++              .sram_pdn_ack_bits = GENMASK(15, 12),
++              .clk_id = {CLK_ETHIF},
++              .active_wakeup = true,
++      },
++      [MT2701_POWER_DOMAIN_IFR_MSC] = {
++              .name = "ifr_msc",
++              .sta_mask = PWR_STATUS_IFR_MSC,
++              .ctl_offs = SPM_IFR_MSC_PWR_CON,
++              .clk_id = {CLK_NONE},
++              .active_wakeup = true,
++      },
++};
++
++#define NUM_DOMAINS_MT2701    ARRAY_SIZE(scp_domain_data_mt2701)
++
++static int __init scpsys_probe_mt2701(struct platform_device *pdev)
++{
++      struct scp *scp;
++
++      scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
++      if (IS_ERR(scp))
++              return PTR_ERR(scp);
++
++      mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
++
++      return 0;
++}
++
++/*
+  * MT8173 power domain support
+  */
+@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st
+ static const struct of_device_id of_scpsys_match_tbl[] = {
+       {
++              .compatible = "mediatek,mt2701-scpsys",
++              .data = scpsys_probe_mt2701,
++      }, {
+               .compatible = "mediatek,mt8173-scpsys",
+               .data = scpsys_probe_mt8173,
+       }, {
diff --git a/target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch
new file mode 100644 (file)
index 0000000..a7ebb06
--- /dev/null
@@ -0,0 +1,30 @@
+From 600e2bd5c3019f31e90ec876f4efb6c209cf0d73 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 6 Jan 2016 20:06:49 +0100
+Subject: [PATCH 10/57] clk: add hifsys reset
+
+Hi,
+
+small patch to add hifsys reset bits. Maybe you could add it to the next
+version of your patch series. i have teste scpsys and clk on mt7623 today
+and it works well.
+
+thanks,
+       John
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ 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
+@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_register_reset_controller(node, 1, 0x34);
+ }
+ CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch
deleted file mode 100644 (file)
index 18d4fbf..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 3ba0020ea70ffb5503eff1823be7fa5ceda38286 Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang@mediatek.com>
-Date: Tue, 5 Jan 2016 14:30:22 +0800
-Subject: [PATCH 011/102] reset: mediatek: mt2701 reset driver
-
-In infrasys and perifsys, there are many reset
-control bits for kinds of modules. These bits are
-used as actual reset controllers to be registered
-into kernel's generic reset controller framework.
-
-Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
-Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
----
- drivers/clk/mediatek/clk-mt2701.c |    4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_register_reset_controller(node, 2, 0x30);
- }
- CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
-@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_register_reset_controller(node, 2, 0x0);
- }
- CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
diff --git a/target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch
new file mode 100644 (file)
index 0000000..8a9da5e
--- /dev/null
@@ -0,0 +1,20 @@
+From 1e889b3d38ab5fb425762da57313b4cc8fc2f165 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 21 Feb 2016 13:52:12 +0100
+Subject: [PATCH 11/57] scpsys: various fixes
+
+---
+ 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
+@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_register_reset_controller(node, 1, 0x34);
+ }
+ CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
deleted file mode 100644 (file)
index 73e92dc..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 32fa899c6ab79953e4f470fb23c38bcc40edc5c8 Mon Sep 17 00:00:00 2001
-From: Erin Lo <erin.lo@mediatek.com>
-Date: Mon, 28 Dec 2015 15:09:02 +0800
-Subject: [PATCH 012/102] ARM: mediatek: Add MT2701 config options for
- mediatek SoCs.
-
-The upcoming MTK pinctrl driver have a big pin table for each SoC
-and we don't want to bloat the kernel binary if we don't need it.
-Add config options so we can build for one SoC only. Add MT2701.
-
-Signed-off-by: Erin Lo <erin.lo@mediatek.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
----
- arch/arm/mach-mediatek/Kconfig |    4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/arch/arm/mach-mediatek/Kconfig
-+++ b/arch/arm/mach-mediatek/Kconfig
-@@ -14,6 +14,10 @@ config MACH_MT2701
-       bool "MediaTek MT2701 SoCs support"
-       default ARCH_MEDIATEK
-+config MACH_MT2701
-+      bool "MediaTek MT2701 SoCs support"
-+      default ARCH_MEDIATEK
-+
- config MACH_MT6589
-       bool "MediaTek MT6589 SoCs support"
-       default ARCH_MEDIATEK
diff --git a/target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch
new file mode 100644 (file)
index 0000000..ed4111d
--- /dev/null
@@ -0,0 +1,21 @@
+From 0e60d2112968ccb2570535bf19fb5020c9b28c08 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 7 Apr 2016 07:18:35 +0200
+Subject: [PATCH 12/57] clk: dont disable unused clocks
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/clk/clk.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/clk/clk.c
++++ b/drivers/clk/clk.c
+@@ -796,7 +796,7 @@ unlock_out:
+               clk_core_disable_unprepare(core->parent);
+ }
+-static bool clk_ignore_unused;
++static bool clk_ignore_unused = true;
+ static int __init clk_ignore_unused_setup(char *__unused)
+ {
+       clk_ignore_unused = true;
diff --git a/target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch
new file mode 100644 (file)
index 0000000..26257bd
--- /dev/null
@@ -0,0 +1,69 @@
+From 03bead9276653dc842f6970250bc7eba41faf777 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 31 Mar 2016 06:46:51 +0200
+Subject: [PATCH 13/57] clk: mediatek: enable critical clocks
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[]
+       GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
+ };
++static struct clk_onecell_data *mt7623_top_clk_data __initdata;
++static struct clk_onecell_data *mt7623_pll_clk_data __initdata;
++
++static void __init mtk_clk_enable_critical(void)
++{
++      if (!mt7623_top_clk_data || !mt7623_pll_clk_data)
++              return;
++
++      clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]);
++      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]);
++      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
++      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]);
++}
++
+ static void __init mtk_topckgen_init(struct device_node *node)
+ {
+       struct clk_onecell_data *clk_data;
+@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str
+               return;
+       }
+-      clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
++      mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
+       mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
+                                                               clk_data);
+@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_clk_enable_critical();
+ }
+ CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
+@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s
+       struct clk_onecell_data *clk_data;
+       int r;
+-      clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
++      mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
+       if (!clk_data)
+               return;
+@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+                       __func__, r);
++
++      mtk_clk_enable_critical();
+ }
+ CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
+                                                       mtk_apmixedsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
new file mode 100644 (file)
index 0000000..7e19c6f
--- /dev/null
@@ -0,0 +1,287 @@
+From 3a947321d72af191ee87a390295c661c876cc6f4 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 31 Mar 2016 02:26:37 +0200
+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 <pi-cheng.chen@linaro.org>
+---
+ drivers/clk/mediatek/Makefile          |   2 +-
+ drivers/clk/mediatek/clk-cpumux.c      | 127 +++++++++++++++++++++++++++++++++
+ drivers/clk/mediatek/clk-cpumux.h      |  22 ++++++
+ drivers/clk/mediatek/clk-mt2701.c      |   8 +++
+ drivers/clk/mediatek/clk-mt8173.c      |  23 ++++++
+ include/dt-bindings/clock/mt2701-clk.h |   3 +-
+ include/dt-bindings/clock/mt8173-clk.h |   4 +-
+ 7 files changed, 186 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/clk/mediatek/clk-cpumux.c
+ create mode 100644 drivers/clk/mediatek/clk-cpumux.h
+
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -1,4 +1,4 @@
+-obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
++obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o
+ obj-$(CONFIG_RESET_CONTROLLER) += reset.o
+ obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-cpumux.c
+@@ -0,0 +1,127 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/mfd/syscon.h>
++#include <linux/slab.h>
++
++#include "clk-mtk.h"
++#include "clk-cpumux.h"
++
++struct mtk_clk_cpumux {
++      struct clk_hw   hw;
++      struct regmap   *regmap;
++      u32             reg;
++      u32             mask;
++      u8              shift;
++};
++
++static inline struct mtk_clk_cpumux *to_mtk_clk_mux(struct clk_hw *_hw)
++{
++      return container_of(_hw, struct mtk_clk_cpumux, hw);
++}
++
++static u8 clk_cpumux_get_parent(struct clk_hw *hw)
++{
++      struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw);
++      int num_parents = clk_hw_get_num_parents(hw);
++      unsigned int val;
++
++      regmap_read(mux->regmap, mux->reg, &val);
++
++      val >>= mux->shift;
++      val &= mux->mask;
++
++      if (val >= num_parents)
++              return -EINVAL;
++
++      return val;
++}
++
++static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
++{
++      struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw);
++      u32 mask, val;
++
++      val = index << mux->shift;
++      mask = mux->mask << mux->shift;
++
++      return regmap_update_bits(mux->regmap, mux->reg, mask, val);
++}
++
++static const struct clk_ops clk_cpumux_ops = {
++      .get_parent = clk_cpumux_get_parent,
++      .set_parent = clk_cpumux_set_parent,
++};
++
++static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux,
++                                         struct regmap *regmap)
++{
++      struct mtk_clk_cpumux *cpumux;
++      struct clk *clk;
++      struct clk_init_data init;
++
++      cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
++      if (!cpumux)
++              return ERR_PTR(-ENOMEM);
++
++      init.name = mux->name;
++      init.ops = &clk_cpumux_ops;
++      init.parent_names = mux->parent_names;
++      init.num_parents = mux->num_parents;
++      init.flags = mux->flags;
++
++      cpumux->reg = mux->mux_reg;
++      cpumux->shift = mux->mux_shift;
++      cpumux->mask = BIT(mux->mux_width) - 1;
++      cpumux->regmap = regmap;
++      cpumux->hw.init = &init;
++
++      clk = clk_register(NULL, &cpumux->hw);
++      if (IS_ERR(clk))
++              kfree(cpumux);
++
++      return clk;
++}
++
++int __init mtk_clk_register_cpumuxes(struct device_node *node,
++                            const struct mtk_composite *clks, int num,
++                            struct clk_onecell_data *clk_data)
++{
++      int i;
++      struct clk *clk;
++      struct regmap *regmap;
++
++      regmap = syscon_node_to_regmap(node);
++      if (IS_ERR(regmap)) {
++              pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
++                     PTR_ERR(regmap));
++              return PTR_ERR(regmap);
++      }
++
++      for (i = 0; i < num; i++) {
++              const struct mtk_composite *mux = &clks[i];
++
++              clk = mtk_clk_register_cpumux(mux, regmap);
++              if (IS_ERR(clk)) {
++                      pr_err("Failed to register clk %s: %ld\n",
++                             mux->name, PTR_ERR(clk));
++                      continue;
++              }
++
++              clk_data->clks[mux->id] = clk;
++      }
++
++      return 0;
++}
+--- /dev/null
++++ b/drivers/clk/mediatek/clk-cpumux.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __DRV_CLK_CPUMUX_H
++#define __DRV_CLK_CPUMUX_H
++
++int mtk_clk_register_cpumuxes(struct device_node *node,
++                            const struct mtk_composite *clks, int num,
++                            struct clk_onecell_data *clk_data);
++
++#endif /* __DRV_CLK_CPUMUX_H */
+--- a/drivers/clk/mediatek/clk-mt2701.c
++++ b/drivers/clk/mediatek/clk-mt2701.c
+@@ -18,6 +18,7 @@
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
++#include "clk-cpumux.h"
+ #include <dt-bindings/clock/mt2701-clk.h>
+@@ -465,6 +466,10 @@ static const char * const cpu_parents[]
+       "mmpll"
+ };
++static const struct mtk_composite cpu_muxes[] __initconst = {
++      MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2),
++};
++
+ static const struct mtk_composite top_muxes[] __initconst = {
+       MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
+               0x0040, 0, 3, INVALID_MUX_GATE_BIT),
+@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str
+       mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
+                                               clk_data);
++      mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
++                                              clk_data);
++
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+--- a/drivers/clk/mediatek/clk-mt8173.c
++++ b/drivers/clk/mediatek/clk-mt8173.c
+@@ -18,6 +18,7 @@
+ #include "clk-mtk.h"
+ #include "clk-gate.h"
++#include "clk-cpumux.h"
+ #include <dt-bindings/clock/mt8173-clk.h>
+@@ -525,6 +526,25 @@ static const char * const i2s3_b_ck_pare
+       "apll2_div5"
+ };
++static const char * const ca53_parents[] __initconst = {
++      "clk26m",
++      "armca7pll",
++      "mainpll",
++      "univpll"
++};
++
++static const char * const ca57_parents[] __initconst = {
++      "clk26m",
++      "armca15pll",
++      "mainpll",
++      "univpll"
++};
++
++static const struct mtk_composite cpu_muxes[] __initconst = {
++      MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
++      MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
++};
++
+ static const struct mtk_composite top_muxes[] __initconst = {
+       /* CLK_CFG_0 */
+       MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
+@@ -948,6 +968,9 @@ static void __init mtk_infrasys_init(str
+                                               clk_data);
+       mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
++      mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
++                                              clk_data);
++
+       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+       if (r)
+               pr_err("%s(): could not register clock provider: %d\n",
+--- a/include/dt-bindings/clock/mt2701-clk.h
++++ b/include/dt-bindings/clock/mt2701-clk.h
+@@ -221,7 +221,8 @@
+ #define CLK_INFRA_PMICWRAP                    17
+ #define CLK_INFRA_DDCCI                               18
+ #define CLK_INFRA_CLK_13M                     19
+-#define CLK_INFRA_NR                          20
++#define CLK_INFRA_CPUSEL                      20
++#define CLK_INFRA_NR                          21
+ /* PERICFG */
+--- a/include/dt-bindings/clock/mt8173-clk.h
++++ b/include/dt-bindings/clock/mt8173-clk.h
+@@ -193,7 +193,9 @@
+ #define CLK_INFRA_PMICSPI             10
+ #define CLK_INFRA_PMICWRAP            11
+ #define CLK_INFRA_CLK_13M             12
+-#define CLK_INFRA_NR_CLK              13
++#define CLK_INFRA_CA53SEL             13
++#define CLK_INFRA_CA57SEL             14
++#define CLK_INFRA_NR_CLK              15
+ /* PERI_SYS */
diff --git a/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch
deleted file mode 100644 (file)
index 0786e52..0000000
+++ /dev/null
@@ -1,486 +0,0 @@
-From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001
-From: James Liao <jamesjj.liao@mediatek.com>
-Date: Thu, 20 Oct 2016 16:56:35 +0800
-Subject: [PATCH 1/2] soc: mediatek: Refine scpsys to support multiple platform
-
-Refine scpsys driver common code to support multiple SoC / platform.
-
-Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
-Reviewed-by: Kevin Hilman <khilman@baylibre.com>
-Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
----
- drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++---------------
- 1 file changed, 210 insertions(+), 138 deletions(-)
-
---- a/drivers/soc/mediatek/mtk-scpsys.c
-+++ b/drivers/soc/mediatek/mtk-scpsys.c
-@@ -11,17 +11,15 @@
-  * GNU General Public License for more details.
-  */
- #include <linux/clk.h>
--#include <linux/delay.h>
-+#include <linux/init.h>
- #include <linux/io.h>
--#include <linux/kernel.h>
- #include <linux/mfd/syscon.h>
--#include <linux/init.h>
- #include <linux/of_device.h>
- #include <linux/platform_device.h>
- #include <linux/pm_domain.h>
--#include <linux/regmap.h>
--#include <linux/soc/mediatek/infracfg.h>
- #include <linux/regulator/consumer.h>
-+#include <linux/soc/mediatek/infracfg.h>
-+
- #include <dt-bindings/power/mt8173-power.h>
- #define SPM_VDE_PWR_CON                       0x0210
-@@ -34,6 +32,7 @@
- #define SPM_MFG_2D_PWR_CON            0x02c0
- #define SPM_MFG_ASYNC_PWR_CON         0x02c4
- #define SPM_USB_PWR_CON                       0x02cc
-+
- #define SPM_PWR_STATUS                        0x060c
- #define SPM_PWR_STATUS_2ND            0x0610
-@@ -55,12 +54,21 @@
- #define PWR_STATUS_USB                        BIT(25)
- enum clk_id {
--      MT8173_CLK_NONE,
--      MT8173_CLK_MM,
--      MT8173_CLK_MFG,
--      MT8173_CLK_VENC,
--      MT8173_CLK_VENC_LT,
--      MT8173_CLK_MAX,
-+      CLK_NONE,
-+      CLK_MM,
-+      CLK_MFG,
-+      CLK_VENC,
-+      CLK_VENC_LT,
-+      CLK_MAX,
-+};
-+
-+static const char * const clk_names[] = {
-+      NULL,
-+      "mm",
-+      "mfg",
-+      "venc",
-+      "venc_lt",
-+      NULL,
- };
- #define MAX_CLKS      2
-@@ -76,98 +84,6 @@ struct scp_domain_data {
-       bool active_wakeup;
- };
--static const struct scp_domain_data scp_domain_data[] = {
--      [MT8173_POWER_DOMAIN_VDEC] = {
--              .name = "vdec",
--              .sta_mask = PWR_STATUS_VDEC,
--              .ctl_offs = SPM_VDE_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(12, 12),
--              .clk_id = {MT8173_CLK_MM},
--      },
--      [MT8173_POWER_DOMAIN_VENC] = {
--              .name = "venc",
--              .sta_mask = PWR_STATUS_VENC,
--              .ctl_offs = SPM_VEN_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(15, 12),
--              .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
--      },
--      [MT8173_POWER_DOMAIN_ISP] = {
--              .name = "isp",
--              .sta_mask = PWR_STATUS_ISP,
--              .ctl_offs = SPM_ISP_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(13, 12),
--              .clk_id = {MT8173_CLK_MM},
--      },
--      [MT8173_POWER_DOMAIN_MM] = {
--              .name = "mm",
--              .sta_mask = PWR_STATUS_DISP,
--              .ctl_offs = SPM_DIS_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(12, 12),
--              .clk_id = {MT8173_CLK_MM},
--              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
--                      MT8173_TOP_AXI_PROT_EN_MM_M1,
--      },
--      [MT8173_POWER_DOMAIN_VENC_LT] = {
--              .name = "venc_lt",
--              .sta_mask = PWR_STATUS_VENC_LT,
--              .ctl_offs = SPM_VEN2_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(15, 12),
--              .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
--      },
--      [MT8173_POWER_DOMAIN_AUDIO] = {
--              .name = "audio",
--              .sta_mask = PWR_STATUS_AUDIO,
--              .ctl_offs = SPM_AUDIO_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(15, 12),
--              .clk_id = {MT8173_CLK_NONE},
--      },
--      [MT8173_POWER_DOMAIN_USB] = {
--              .name = "usb",
--              .sta_mask = PWR_STATUS_USB,
--              .ctl_offs = SPM_USB_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(15, 12),
--              .clk_id = {MT8173_CLK_NONE},
--              .active_wakeup = true,
--      },
--      [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
--              .name = "mfg_async",
--              .sta_mask = PWR_STATUS_MFG_ASYNC,
--              .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = 0,
--              .clk_id = {MT8173_CLK_MFG},
--      },
--      [MT8173_POWER_DOMAIN_MFG_2D] = {
--              .name = "mfg_2d",
--              .sta_mask = PWR_STATUS_MFG_2D,
--              .ctl_offs = SPM_MFG_2D_PWR_CON,
--              .sram_pdn_bits = GENMASK(11, 8),
--              .sram_pdn_ack_bits = GENMASK(13, 12),
--              .clk_id = {MT8173_CLK_NONE},
--      },
--      [MT8173_POWER_DOMAIN_MFG] = {
--              .name = "mfg",
--              .sta_mask = PWR_STATUS_MFG,
--              .ctl_offs = SPM_MFG_PWR_CON,
--              .sram_pdn_bits = GENMASK(13, 8),
--              .sram_pdn_ack_bits = GENMASK(21, 16),
--              .clk_id = {MT8173_CLK_NONE},
--              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
--                      MT8173_TOP_AXI_PROT_EN_MFG_M0 |
--                      MT8173_TOP_AXI_PROT_EN_MFG_M1 |
--                      MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
--      },
--};
--
--#define NUM_DOMAINS   ARRAY_SIZE(scp_domain_data)
--
- struct scp;
- struct scp_domain {
-@@ -179,7 +95,7 @@ struct scp_domain {
- };
- struct scp {
--      struct scp_domain domains[NUM_DOMAINS];
-+      struct scp_domain *domains;
-       struct genpd_onecell_data pd_data;
-       struct device *dev;
-       void __iomem *base;
-@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct
-       return scpd->data->active_wakeup;
- }
--static int scpsys_probe(struct platform_device *pdev)
-+static void init_clks(struct platform_device *pdev, struct clk **clk)
-+{
-+      int i;
-+
-+      for (i = CLK_NONE + 1; i < CLK_MAX; i++)
-+              clk[i] = devm_clk_get(&pdev->dev, clk_names[i]);
-+}
-+
-+static struct scp *init_scp(struct platform_device *pdev,
-+                      const struct scp_domain_data *scp_domain_data, int num)
- {
-       struct genpd_onecell_data *pd_data;
-       struct resource *res;
--      int i, j, ret;
-+      int i, j;
-       struct scp *scp;
--      struct clk *clk[MT8173_CLK_MAX];
-+      struct clk *clk[CLK_MAX];
-       scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
-       if (!scp)
--              return -ENOMEM;
-+              return ERR_PTR(-ENOMEM);
-       scp->dev = &pdev->dev;
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       scp->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(scp->base))
--              return PTR_ERR(scp->base);
-+              return ERR_CAST(scp->base);
-+
-+      scp->domains = devm_kzalloc(&pdev->dev,
-+                              sizeof(*scp->domains) * num, GFP_KERNEL);
-+      if (!scp->domains)
-+              return ERR_PTR(-ENOMEM);
-       pd_data = &scp->pd_data;
-       pd_data->domains = devm_kzalloc(&pdev->dev,
--                      sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
-+                      sizeof(*pd_data->domains) * num, GFP_KERNEL);
-       if (!pd_data->domains)
--              return -ENOMEM;
--
--      clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
--      if (IS_ERR(clk[MT8173_CLK_MM]))
--              return PTR_ERR(clk[MT8173_CLK_MM]);
--
--      clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
--      if (IS_ERR(clk[MT8173_CLK_MFG]))
--              return PTR_ERR(clk[MT8173_CLK_MFG]);
--
--      clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
--      if (IS_ERR(clk[MT8173_CLK_VENC]))
--              return PTR_ERR(clk[MT8173_CLK_VENC]);
--
--      clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
--      if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
--              return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
-+              return ERR_PTR(-ENOMEM);
-       scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-                       "infracfg");
-       if (IS_ERR(scp->infracfg)) {
-               dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
-                               PTR_ERR(scp->infracfg));
--              return PTR_ERR(scp->infracfg);
-+              return ERR_CAST(scp->infracfg);
-       }
--      for (i = 0; i < NUM_DOMAINS; i++) {
-+      for (i = 0; i < num; i++) {
-               struct scp_domain *scpd = &scp->domains[i];
-               const struct scp_domain_data *data = &scp_domain_data[i];
-@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_
-                       if (PTR_ERR(scpd->supply) == -ENODEV)
-                               scpd->supply = NULL;
-                       else
--                              return PTR_ERR(scpd->supply);
-+                              return ERR_CAST(scpd->supply);
-               }
-       }
--      pd_data->num_domains = NUM_DOMAINS;
-+      pd_data->num_domains = num;
-+
-+      init_clks(pdev, clk);
--      for (i = 0; i < NUM_DOMAINS; i++) {
-+      for (i = 0; i < num; i++) {
-               struct scp_domain *scpd = &scp->domains[i];
-               struct generic_pm_domain *genpd = &scpd->genpd;
-               const struct scp_domain_data *data = &scp_domain_data[i];
-@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_
-               scpd->scp = scp;
-               scpd->data = data;
--              for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
--                      scpd->clk[j] = clk[data->clk_id[j]];
-+
-+              for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) {
-+                      struct clk *c = clk[data->clk_id[j]];
-+
-+                      if (IS_ERR(c)) {
-+                              dev_err(&pdev->dev, "%s: clk unavailable\n",
-+                                      data->name);
-+                              return ERR_CAST(c);
-+                      }
-+
-+                      scpd->clk[j] = c;
-+              }
-               genpd->name = data->name;
-               genpd->power_off = scpsys_power_off;
-               genpd->power_on = scpsys_power_on;
-               genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
-+      }
-+
-+      return scp;
-+}
-+
-+static void mtk_register_power_domains(struct platform_device *pdev,
-+                              struct scp *scp, int num)
-+{
-+      struct genpd_onecell_data *pd_data;
-+      int i, ret;
-+
-+      for (i = 0; i < num; i++) {
-+              struct scp_domain *scpd = &scp->domains[i];
-+              struct generic_pm_domain *genpd = &scpd->genpd;
-               /*
-                * Initially turn on all domains to make the domains usable
-@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_
-        * valid.
-        */
-+      pd_data = &scp->pd_data;
-+
-+      ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
-+      if (ret)
-+              dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
-+}
-+
-+/*
-+ * MT8173 power domain support
-+ */
-+
-+static const struct scp_domain_data scp_domain_data_mt8173[] = {
-+      [MT8173_POWER_DOMAIN_VDEC] = {
-+              .name = "vdec",
-+              .sta_mask = PWR_STATUS_VDEC,
-+              .ctl_offs = SPM_VDE_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(12, 12),
-+              .clk_id = {CLK_MM},
-+      },
-+      [MT8173_POWER_DOMAIN_VENC] = {
-+              .name = "venc",
-+              .sta_mask = PWR_STATUS_VENC,
-+              .ctl_offs = SPM_VEN_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_MM, CLK_VENC},
-+      },
-+      [MT8173_POWER_DOMAIN_ISP] = {
-+              .name = "isp",
-+              .sta_mask = PWR_STATUS_ISP,
-+              .ctl_offs = SPM_ISP_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(13, 12),
-+              .clk_id = {CLK_MM},
-+      },
-+      [MT8173_POWER_DOMAIN_MM] = {
-+              .name = "mm",
-+              .sta_mask = PWR_STATUS_DISP,
-+              .ctl_offs = SPM_DIS_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(12, 12),
-+              .clk_id = {CLK_MM},
-+              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
-+                      MT8173_TOP_AXI_PROT_EN_MM_M1,
-+      },
-+      [MT8173_POWER_DOMAIN_VENC_LT] = {
-+              .name = "venc_lt",
-+              .sta_mask = PWR_STATUS_VENC_LT,
-+              .ctl_offs = SPM_VEN2_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_MM, CLK_VENC_LT},
-+      },
-+      [MT8173_POWER_DOMAIN_AUDIO] = {
-+              .name = "audio",
-+              .sta_mask = PWR_STATUS_AUDIO,
-+              .ctl_offs = SPM_AUDIO_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_NONE},
-+      },
-+      [MT8173_POWER_DOMAIN_USB] = {
-+              .name = "usb",
-+              .sta_mask = PWR_STATUS_USB,
-+              .ctl_offs = SPM_USB_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_NONE},
-+              .active_wakeup = true,
-+      },
-+      [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
-+              .name = "mfg_async",
-+              .sta_mask = PWR_STATUS_MFG_ASYNC,
-+              .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = 0,
-+              .clk_id = {CLK_MFG},
-+      },
-+      [MT8173_POWER_DOMAIN_MFG_2D] = {
-+              .name = "mfg_2d",
-+              .sta_mask = PWR_STATUS_MFG_2D,
-+              .ctl_offs = SPM_MFG_2D_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(13, 12),
-+              .clk_id = {CLK_NONE},
-+      },
-+      [MT8173_POWER_DOMAIN_MFG] = {
-+              .name = "mfg",
-+              .sta_mask = PWR_STATUS_MFG,
-+              .ctl_offs = SPM_MFG_PWR_CON,
-+              .sram_pdn_bits = GENMASK(13, 8),
-+              .sram_pdn_ack_bits = GENMASK(21, 16),
-+              .clk_id = {CLK_NONE},
-+              .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
-+                      MT8173_TOP_AXI_PROT_EN_MFG_M0 |
-+                      MT8173_TOP_AXI_PROT_EN_MFG_M1 |
-+                      MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
-+      },
-+};
-+
-+#define NUM_DOMAINS_MT8173    ARRAY_SIZE(scp_domain_data_mt8173)
-+
-+static int __init scpsys_probe_mt8173(struct platform_device *pdev)
-+{
-+      struct scp *scp;
-+      struct genpd_onecell_data *pd_data;
-+      int ret;
-+
-+      scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
-+      if (IS_ERR(scp))
-+              return PTR_ERR(scp);
-+
-+      mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173);
-+
-+      pd_data = &scp->pd_data;
-+
-       ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
-               pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
-       if (ret && IS_ENABLED(CONFIG_PM))
-@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_
-       if (ret && IS_ENABLED(CONFIG_PM))
-               dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
--      ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
--      if (ret)
--              dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
--
-       return 0;
- }
-+/*
-+ * scpsys driver init
-+ */
-+
- static const struct of_device_id of_scpsys_match_tbl[] = {
-       {
-               .compatible = "mediatek,mt8173-scpsys",
-+              .data = scpsys_probe_mt8173,
-       }, {
-               /* sentinel */
-       }
- };
-+static int scpsys_probe(struct platform_device *pdev)
-+{
-+      int (*probe)(struct platform_device *);
-+      const struct of_device_id *of_id;
-+
-+      of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node);
-+      if (!of_id || !of_id->data)
-+              return -EINVAL;
-+
-+      probe = of_id->data;
-+
-+      return probe(pdev);
-+}
-+
- static struct platform_driver scpsys_drv = {
-       .probe = scpsys_probe,
-       .driver = {
diff --git a/target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch
new file mode 100644 (file)
index 0000000..af60025
--- /dev/null
@@ -0,0 +1,433 @@
+From 8aa2c6c4d8b20c0e9c69b15db4a0039d33f8b365 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 30 Mar 2016 23:48:53 +0200
+Subject: [PATCH 15/57] cpufreq: mediatek: add driver
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/cpufreq/Kconfig.arm      |   9 +
+ drivers/cpufreq/Makefile         |   1 +
+ drivers/cpufreq/mt7623-cpufreq.c | 389 +++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 399 insertions(+)
+ create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
+
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -74,6 +74,15 @@ config ARM_KIRKWOOD_CPUFREQ
+         This adds the CPUFreq driver for Marvell Kirkwood
+         SoCs.
++config ARM_MT7623_CPUFREQ
++      bool "Mediatek MT7623 CPUFreq support"
++      depends on ARCH_MEDIATEK && REGULATOR
++      depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
++      depends on !CPU_THERMAL || THERMAL=y
++      select PM_OPP
++      help
++        This adds the CPUFreq driver support for Mediatek MT7623 SoC.
++
+ config ARM_MT8173_CPUFREQ
+       tristate "Mediatek MT8173 CPUFreq support"
+       depends on ARCH_MEDIATEK && REGULATOR
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -58,6 +58,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)   += hi
+ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)               += imx6q-cpufreq.o
+ obj-$(CONFIG_ARM_INTEGRATOR)          += integrator-cpufreq.o
+ obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)    += kirkwood-cpufreq.o
++obj-$(CONFIG_ARM_MT7623_CPUFREQ)      += mt7623-cpufreq.o
+ obj-$(CONFIG_ARM_MT8173_CPUFREQ)      += mt8173-cpufreq.o
+ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)   += omap-cpufreq.o
+ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)      += pxa2xx-cpufreq.o
+--- /dev/null
++++ b/drivers/cpufreq/mt7623-cpufreq.c
+@@ -0,0 +1,389 @@
++/*
++ * Copyright (c) 2015 Linaro Ltd.
++ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/cpu.h>
++#include <linux/cpu_cooling.h>
++#include <linux/cpufreq.h>
++#include <linux/cpumask.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm_opp.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <linux/thermal.h>
++
++#define VOLT_TOL              (10000)
++
++/*
++ * When scaling the clock frequency of a CPU clock domain, the clock source
++ * needs to be switched to another stable PLL clock temporarily until
++ * the original PLL becomes stable at target frequency.
++ */
++struct mtk_cpu_dvfs_info {
++      struct device *cpu_dev;
++      struct regulator *proc_reg;
++      struct clk *cpu_clk;
++      struct clk *inter_clk;
++      struct thermal_cooling_device *cdev;
++      int intermediate_voltage;
++};
++
++static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
++{
++      return regulator_set_voltage(info->proc_reg, vproc,
++                                   vproc + VOLT_TOL);
++}
++
++static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
++                                unsigned int index)
++{
++      struct cpufreq_frequency_table *freq_table = policy->freq_table;
++      struct clk *cpu_clk = policy->clk;
++      struct clk *armpll = clk_get_parent(cpu_clk);
++      struct mtk_cpu_dvfs_info *info = policy->driver_data;
++      struct device *cpu_dev = info->cpu_dev;
++      struct dev_pm_opp *opp;
++      long freq_hz, old_freq_hz;
++      int vproc, old_vproc, inter_vproc, target_vproc, ret;
++
++      inter_vproc = info->intermediate_voltage;
++
++      old_freq_hz = clk_get_rate(cpu_clk);
++      old_vproc = regulator_get_voltage(info->proc_reg);
++
++      freq_hz = freq_table[index].frequency * 1000;
++
++      rcu_read_lock();
++      opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
++      if (IS_ERR(opp)) {
++              rcu_read_unlock();
++              pr_err("cpu%d: failed to find OPP for %ld\n",
++                     policy->cpu, freq_hz);
++              return PTR_ERR(opp);
++      }
++      vproc = dev_pm_opp_get_voltage(opp);
++      rcu_read_unlock();
++
++      /*
++       * If the new voltage or the intermediate voltage is higher than the
++       * current voltage, scale up voltage first.
++       */
++      target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
++      if (old_vproc < target_vproc) {
++              ret = mtk_cpufreq_set_voltage(info, target_vproc);
++              if (ret) {
++                      pr_err("cpu%d: failed to scale up voltage!\n",
++                             policy->cpu);
++                      mtk_cpufreq_set_voltage(info, old_vproc);
++                      return ret;
++              }
++      }
++
++      /* Reparent the CPU clock to intermediate clock. */
++      ret = clk_set_parent(cpu_clk, info->inter_clk);
++      if (ret) {
++              pr_err("cpu%d: failed to re-parent cpu clock!\n",
++                     policy->cpu);
++              mtk_cpufreq_set_voltage(info, old_vproc);
++              WARN_ON(1);
++              return ret;
++      }
++
++      /* Set the original PLL to target rate. */
++      ret = clk_set_rate(armpll, freq_hz);
++      if (ret) {
++              pr_err("cpu%d: failed to scale cpu clock rate!\n",
++                     policy->cpu);
++              clk_set_parent(cpu_clk, armpll);
++              mtk_cpufreq_set_voltage(info, old_vproc);
++              return ret;
++      }
++
++      /* Set parent of CPU clock back to the original PLL. */
++      ret = clk_set_parent(cpu_clk, armpll);
++      if (ret) {
++              pr_err("cpu%d: failed to re-parent cpu clock!\n",
++                     policy->cpu);
++              mtk_cpufreq_set_voltage(info, inter_vproc);
++              WARN_ON(1);
++              return ret;
++      }
++
++      /*
++       * If the new voltage is lower than the intermediate voltage or the
++       * original voltage, scale down to the new voltage.
++       */
++      if (vproc < inter_vproc || vproc < old_vproc) {
++              ret = mtk_cpufreq_set_voltage(info, vproc);
++              if (ret) {
++                      pr_err("cpu%d: failed to scale down voltage!\n",
++                             policy->cpu);
++                      clk_set_parent(cpu_clk, info->inter_clk);
++                      clk_set_rate(armpll, old_freq_hz);
++                      clk_set_parent(cpu_clk, armpll);
++                      return ret;
++              }
++      }
++
++      return 0;
++}
++
++static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
++{
++      struct mtk_cpu_dvfs_info *info = policy->driver_data;
++      struct device_node *np = of_node_get(info->cpu_dev->of_node);
++
++      if (WARN_ON(!np))
++              return;
++
++      if (of_find_property(np, "#cooling-cells", NULL)) {
++              info->cdev = of_cpufreq_cooling_register(np,
++                                                       policy->related_cpus);
++
++              if (IS_ERR(info->cdev)) {
++                      dev_err(info->cpu_dev,
++                              "running cpufreq without cooling device: %ld\n",
++                              PTR_ERR(info->cdev));
++
++                      info->cdev = NULL;
++              }
++      }
++
++      of_node_put(np);
++}
++
++static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
++{
++      struct device *cpu_dev;
++      struct regulator *proc_reg = ERR_PTR(-ENODEV);
++      struct clk *cpu_clk = ERR_PTR(-ENODEV);
++      struct clk *inter_clk = ERR_PTR(-ENODEV);
++      struct dev_pm_opp *opp;
++      unsigned long rate;
++      int ret;
++
++      cpu_dev = get_cpu_device(cpu);
++      if (!cpu_dev) {
++              pr_err("failed to get cpu%d device\n", cpu);
++              return -ENODEV;
++      }
++
++      cpu_clk = clk_get(cpu_dev, "cpu");
++      if (IS_ERR(cpu_clk)) {
++              if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
++                      pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
++              else
++                      pr_err("failed to get cpu clk for cpu%d\n", cpu);
++
++              ret = PTR_ERR(cpu_clk);
++              return ret;
++      }
++
++      inter_clk = clk_get(cpu_dev, "intermediate");
++      if (IS_ERR(inter_clk)) {
++              if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
++                      pr_warn("intermediate clk for cpu%d not ready, retry.\n",
++                              cpu);
++              else
++                      pr_err("failed to get intermediate clk for cpu%d\n",
++                             cpu);
++
++              ret = PTR_ERR(inter_clk);
++              goto out_free_resources;
++      }
++
++      proc_reg = regulator_get_exclusive(cpu_dev, "proc");
++      if (IS_ERR(proc_reg)) {
++              if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
++                      pr_warn("proc regulator for cpu%d not ready, retry.\n",
++                              cpu);
++              else
++                      pr_err("failed to get proc regulator for cpu%d\n",
++                             cpu);
++
++              ret = PTR_ERR(proc_reg);
++              goto out_free_resources;
++      }
++
++      ret = dev_pm_opp_of_add_table(cpu_dev);
++      if (ret) {
++              pr_warn("no OPP table for cpu%d\n", cpu);
++              goto out_free_resources;
++      }
++
++      /* Search a safe voltage for intermediate frequency. */
++      rate = clk_get_rate(inter_clk);
++      rcu_read_lock();
++      opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
++      if (IS_ERR(opp)) {
++              rcu_read_unlock();
++              pr_err("failed to get intermediate opp for cpu%d\n", cpu);
++              ret = PTR_ERR(opp);
++              goto out_free_opp_table;
++      }
++      info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
++      rcu_read_unlock();
++
++      info->cpu_dev = cpu_dev;
++      info->proc_reg = proc_reg;
++      info->cpu_clk = cpu_clk;
++      info->inter_clk = inter_clk;
++
++      return 0;
++
++out_free_opp_table:
++      dev_pm_opp_of_remove_table(cpu_dev);
++
++out_free_resources:
++      if (!IS_ERR(proc_reg))
++              regulator_put(proc_reg);
++      if (!IS_ERR(cpu_clk))
++              clk_put(cpu_clk);
++      if (!IS_ERR(inter_clk))
++              clk_put(inter_clk);
++
++      return ret;
++}
++
++static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
++{
++      if (!IS_ERR(info->proc_reg))
++              regulator_put(info->proc_reg);
++      if (!IS_ERR(info->cpu_clk))
++              clk_put(info->cpu_clk);
++      if (!IS_ERR(info->inter_clk))
++              clk_put(info->inter_clk);
++
++      dev_pm_opp_of_remove_table(info->cpu_dev);
++}
++
++static int mtk_cpufreq_init(struct cpufreq_policy *policy)
++{
++      struct mtk_cpu_dvfs_info *info;
++      struct cpufreq_frequency_table *freq_table;
++      int ret;
++
++      info = kzalloc(sizeof(*info), GFP_KERNEL);
++      if (!info)
++              return -ENOMEM;
++
++      ret = mtk_cpu_dvfs_info_init(info, policy->cpu);
++      if (ret) {
++              pr_err("%s failed to initialize dvfs info for cpu%d\n",
++                     __func__, policy->cpu);
++              goto out_free_dvfs_info;
++      }
++
++      ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
++      if (ret) {
++              pr_err("failed to init cpufreq table for cpu%d: %d\n",
++                     policy->cpu, ret);
++              goto out_release_dvfs_info;
++      }
++
++      ret = cpufreq_table_validate_and_show(policy, freq_table);
++      if (ret) {
++              pr_err("%s: invalid frequency table: %d\n", __func__, ret);
++              goto out_free_cpufreq_table;
++      }
++
++      /* CPUs in the same cluster share a clock and power domain. */
++      cpumask_setall(policy->cpus);
++      policy->driver_data = info;
++      policy->clk = info->cpu_clk;
++
++      return 0;
++
++out_free_cpufreq_table:
++      dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
++
++out_release_dvfs_info:
++      mtk_cpu_dvfs_info_release(info);
++
++out_free_dvfs_info:
++      kfree(info);
++
++      return ret;
++}
++
++static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
++{
++      struct mtk_cpu_dvfs_info *info = policy->driver_data;
++
++      cpufreq_cooling_unregister(info->cdev);
++      dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
++      mtk_cpu_dvfs_info_release(info);
++      kfree(info);
++
++      return 0;
++}
++
++static struct cpufreq_driver mt7623_cpufreq_driver = {
++      .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
++      .verify = cpufreq_generic_frequency_table_verify,
++      .target_index = mtk_cpufreq_set_target,
++      .get = cpufreq_generic_get,
++      .init = mtk_cpufreq_init,
++      .exit = mtk_cpufreq_exit,
++      .ready = mtk_cpufreq_ready,
++      .name = "mtk-cpufreq",
++      .attr = cpufreq_generic_attr,
++};
++
++static int mt7623_cpufreq_probe(struct platform_device *pdev)
++{
++      int ret;
++
++      ret = cpufreq_register_driver(&mt7623_cpufreq_driver);
++      if (ret)
++              pr_err("failed to register mtk cpufreq driver\n");
++
++      return ret;
++}
++
++static struct platform_driver mt7623_cpufreq_platdrv = {
++      .driver = {
++              .name   = "mt7623-cpufreq",
++      },
++      .probe          = mt7623_cpufreq_probe,
++};
++
++static int mt7623_cpufreq_driver_init(void)
++{
++      struct platform_device *pdev;
++      int err;
++
++      if (!of_machine_is_compatible("mediatek,mt7623"))
++              return -ENODEV;
++
++      err = platform_driver_register(&mt7623_cpufreq_platdrv);
++      if (err)
++              return err;
++
++      /*
++       * Since there's no place to hold device registration code and no
++       * device tree based way to match cpufreq driver yet, both the driver
++       * and the device registration codes are put here to handle defer
++       * probing.
++       */
++      pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0);
++      if (IS_ERR(pdev)) {
++              pr_err("failed to register mtk-cpufreq platform device\n");
++              return PTR_ERR(pdev);
++      }
++
++      return 0;
++}
++device_initcall(mt7623_cpufreq_driver_init);
diff --git a/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch
deleted file mode 100644 (file)
index 5147149..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001
-From: Shunli Wang <shunli.wang@mediatek.com>
-Date: Thu, 20 Oct 2016 16:56:38 +0800
-Subject: [PATCH 2/2] soc: mediatek: Add MT2701 scpsys driver
-
-Add scpsys driver for MT2701.
-
-mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should
-be enabled on both arm64 and arm platforms.
-
-Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
-Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
-Reviewed-by: Kevin Hilman <khilman@baylibre.com>
-Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
----
- drivers/soc/mediatek/Kconfig      |   2 +-
- drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++-
- 2 files changed, 117 insertions(+), 2 deletions(-)
-
---- a/drivers/soc/mediatek/Kconfig
-+++ b/drivers/soc/mediatek/Kconfig
-@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP
- config MTK_SCPSYS
-       bool "MediaTek SCPSYS Support"
-       depends on ARCH_MEDIATEK || COMPILE_TEST
--      default ARM64 && ARCH_MEDIATEK
-+      default ARCH_MEDIATEK
-       select REGMAP
-       select MTK_INFRACFG
-       select PM_GENERIC_DOMAINS if PM
---- a/drivers/soc/mediatek/mtk-scpsys.c
-+++ b/drivers/soc/mediatek/mtk-scpsys.c
-@@ -20,6 +20,7 @@
- #include <linux/regulator/consumer.h>
- #include <linux/soc/mediatek/infracfg.h>
-+#include <dt-bindings/power/mt2701-power.h>
- #include <dt-bindings/power/mt8173-power.h>
- #define SPM_VDE_PWR_CON                       0x0210
-@@ -27,8 +28,13 @@
- #define SPM_VEN_PWR_CON                       0x0230
- #define SPM_ISP_PWR_CON                       0x0238
- #define SPM_DIS_PWR_CON                       0x023c
-+#define SPM_CONN_PWR_CON              0x0280
- #define SPM_VEN2_PWR_CON              0x0298
--#define SPM_AUDIO_PWR_CON             0x029c
-+#define SPM_AUDIO_PWR_CON             0x029c  /* MT8173 */
-+#define SPM_BDP_PWR_CON                       0x029c  /* MT2701 */
-+#define SPM_ETH_PWR_CON                       0x02a0
-+#define SPM_HIF_PWR_CON                       0x02a4
-+#define SPM_IFR_MSC_PWR_CON           0x02a8
- #define SPM_MFG_2D_PWR_CON            0x02c0
- #define SPM_MFG_ASYNC_PWR_CON         0x02c4
- #define SPM_USB_PWR_CON                       0x02cc
-@@ -42,10 +48,15 @@
- #define PWR_ON_2ND_BIT                        BIT(3)
- #define PWR_CLK_DIS_BIT                       BIT(4)
-+#define PWR_STATUS_CONN                       BIT(1)
- #define PWR_STATUS_DISP                       BIT(3)
- #define PWR_STATUS_MFG                        BIT(4)
- #define PWR_STATUS_ISP                        BIT(5)
- #define PWR_STATUS_VDEC                       BIT(7)
-+#define PWR_STATUS_BDP                        BIT(14)
-+#define PWR_STATUS_ETH                        BIT(15)
-+#define PWR_STATUS_HIF                        BIT(16)
-+#define PWR_STATUS_IFR_MSC            BIT(17)
- #define PWR_STATUS_VENC_LT            BIT(20)
- #define PWR_STATUS_VENC                       BIT(21)
- #define PWR_STATUS_MFG_2D             BIT(22)
-@@ -59,6 +70,7 @@ enum clk_id {
-       CLK_MFG,
-       CLK_VENC,
-       CLK_VENC_LT,
-+      CLK_ETHIF,
-       CLK_MAX,
- };
-@@ -68,6 +80,7 @@ static const char * const clk_names[] =
-       "mfg",
-       "venc",
-       "venc_lt",
-+      "ethif",
-       NULL,
- };
-@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s
- }
- /*
-+ * MT2701 power domain support
-+ */
-+
-+static const struct scp_domain_data scp_domain_data_mt2701[] = {
-+      [MT2701_POWER_DOMAIN_CONN] = {
-+              .name = "conn",
-+              .sta_mask = PWR_STATUS_CONN,
-+              .ctl_offs = SPM_CONN_PWR_CON,
-+              .bus_prot_mask = 0x0104,
-+              .clk_id = {CLK_NONE},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_DISP] = {
-+              .name = "disp",
-+              .sta_mask = PWR_STATUS_DISP,
-+              .ctl_offs = SPM_DIS_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .clk_id = {CLK_MM},
-+              .bus_prot_mask = 0x0002,
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_VDEC] = {
-+              .name = "vdec",
-+              .sta_mask = PWR_STATUS_VDEC,
-+              .ctl_offs = SPM_VDE_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(12, 12),
-+              .clk_id = {CLK_MM},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_ISP] = {
-+              .name = "isp",
-+              .sta_mask = PWR_STATUS_ISP,
-+              .ctl_offs = SPM_ISP_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(13, 12),
-+              .clk_id = {CLK_MM},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_BDP] = {
-+              .name = "bdp",
-+              .sta_mask = PWR_STATUS_BDP,
-+              .ctl_offs = SPM_BDP_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .clk_id = {CLK_NONE},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_ETH] = {
-+              .name = "eth",
-+              .sta_mask = PWR_STATUS_ETH,
-+              .ctl_offs = SPM_ETH_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_ETHIF},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_HIF] = {
-+              .name = "hif",
-+              .sta_mask = PWR_STATUS_HIF,
-+              .ctl_offs = SPM_HIF_PWR_CON,
-+              .sram_pdn_bits = GENMASK(11, 8),
-+              .sram_pdn_ack_bits = GENMASK(15, 12),
-+              .clk_id = {CLK_ETHIF},
-+              .active_wakeup = true,
-+      },
-+      [MT2701_POWER_DOMAIN_IFR_MSC] = {
-+              .name = "ifr_msc",
-+              .sta_mask = PWR_STATUS_IFR_MSC,
-+              .ctl_offs = SPM_IFR_MSC_PWR_CON,
-+              .clk_id = {CLK_NONE},
-+              .active_wakeup = true,
-+      },
-+};
-+
-+#define NUM_DOMAINS_MT2701    ARRAY_SIZE(scp_domain_data_mt2701)
-+
-+static int __init scpsys_probe_mt2701(struct platform_device *pdev)
-+{
-+      struct scp *scp;
-+
-+      scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
-+      if (IS_ERR(scp))
-+              return PTR_ERR(scp);
-+
-+      mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701);
-+
-+      return 0;
-+}
-+
-+/*
-  * MT8173 power domain support
-  */
-@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st
- static const struct of_device_id of_scpsys_match_tbl[] = {
-       {
-+              .compatible = "mediatek,mt2701-scpsys",
-+              .data = scpsys_probe_mt2701,
-+      }, {
-               .compatible = "mediatek,mt8173-scpsys",
-               .data = scpsys_probe_mt8173,
-       }, {
diff --git a/target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch
new file mode 100644 (file)
index 0000000..2e8414e
--- /dev/null
@@ -0,0 +1,274 @@
+From 201be68268eddb1568c41780a62868cc1666a2de Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 6 May 2016 02:55:48 +0200
+Subject: [PATCH 16/57] pwm: add pwm-mediatek
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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
++++ b/drivers/pwm/Kconfig
+@@ -282,6 +282,15 @@ config PWM_MTK_DISP
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-mtk-disp.
++config PWM_MEDIATEK
++      tristate "MediaTek PWM support"
++      depends on ARCH_MEDIATEK || COMPILE_TEST
++      help
++        Generic PWM framework driver for Mediatek ARM SoC.
++
++        To compile this driver as a module, choose M here: the module
++        will be called pwm-mxs.
++
+ config PWM_MXS
+       tristate "Freescale MXS PWM support"
+       depends on ARCH_MXS && OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS)               += pwm-lpss.o
+ obj-$(CONFIG_PWM_LPSS_PCI)    += pwm-lpss-pci.o
+ obj-$(CONFIG_PWM_LPSS_PLATFORM)       += pwm-lpss-platform.o
+ obj-$(CONFIG_PWM_MESON)               += pwm-meson.o
++obj-$(CONFIG_PWM_MEDIATEK)    += pwm-mediatek.o
+ obj-$(CONFIG_PWM_MTK_DISP)    += pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS)         += pwm-mxs.o
+ obj-$(CONFIG_PWM_OMAP_DMTIMER)        += pwm-omap-dmtimer.o
+--- /dev/null
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -0,0 +1,230 @@
++/*
++ * Mediatek Pulse Width Modulator driver
++ *
++ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#define NUM_PWM               5
++
++/* PWM registers and bits definitions */
++#define PWMCON                        0x00
++#define PWMHDUR                       0x04
++#define PWMLDUR                       0x08
++#define PWMGDUR                       0x0c
++#define PWMWAVENUM            0x28
++#define PWMDWIDTH             0x2c
++#define PWMTHRES              0x30
++
++/**
++ * struct mtk_pwm_chip - struct representing pwm chip
++ *
++ * @mmio_base: base address of pwm chip
++ * @chip: linux pwm chip representation
++ */
++struct mtk_pwm_chip {
++      void __iomem *mmio_base;
++      struct pwm_chip chip;
++      struct clk *clk_top;
++      struct clk *clk_main;
++      struct clk *clk_pwm[NUM_PWM];
++};
++
++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
++{
++      return container_of(chip, struct mtk_pwm_chip, chip);
++}
++
++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
++                                unsigned long offset)
++{
++      return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
++                                  unsigned int num, unsigned long offset,
++                                  unsigned long val)
++{
++      iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++                          int duty_ns, int period_ns)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 resolution = 100 / 4;
++      u32 clkdiv = 0;
++
++      resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm]));
++
++      while (period_ns / resolution  > 8191) {
++              clkdiv++;
++              resolution *= 2;
++      }
++
++      if (clkdiv > 7)
++              return -1;
++
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
++      return 0;
++}
++
++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 val;
++      int ret;
++
++      ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]);
++      if (ret < 0)
++              return ret;
++
++      val = ioread32(pc->mmio_base);
++      val |= BIT(pwm->hwpwm);
++      iowrite32(val, pc->mmio_base);
++
++      return 0;
++}
++
++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 val;
++
++      val = ioread32(pc->mmio_base);
++      val &= ~BIT(pwm->hwpwm);
++      iowrite32(val, pc->mmio_base);
++        clk_unprepare(pc->clk_pwm[pwm->hwpwm]);
++}
++
++static const struct pwm_ops mtk_pwm_ops = {
++      .config = mtk_pwm_config,
++      .enable = mtk_pwm_enable,
++      .disable = mtk_pwm_disable,
++      .owner = THIS_MODULE,
++};
++
++static int mtk_pwm_probe(struct platform_device *pdev)
++{
++      struct mtk_pwm_chip *pc;
++      struct resource *r;
++      int ret;
++
++      pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++      if (!pc)
++              return -ENOMEM;
++
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++      if (IS_ERR(pc->mmio_base))
++              return PTR_ERR(pc->mmio_base);
++
++      pc->clk_main = devm_clk_get(&pdev->dev, "main");
++        if (IS_ERR(pc->clk_main))
++              return PTR_ERR(pc->clk_main);
++
++      pc->clk_top = devm_clk_get(&pdev->dev, "top");
++        if (IS_ERR(pc->clk_top))
++              return PTR_ERR(pc->clk_top);
++
++      pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1");
++        if (IS_ERR(pc->clk_pwm[0]))
++              return PTR_ERR(pc->clk_pwm[0]);
++
++      pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2");
++        if (IS_ERR(pc->clk_pwm[1]))
++              return PTR_ERR(pc->clk_pwm[1]);
++
++      pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3");
++        if (IS_ERR(pc->clk_pwm[2]))
++              return PTR_ERR(pc->clk_pwm[2]);
++
++      pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4");
++        if (IS_ERR(pc->clk_pwm[3]))
++              return PTR_ERR(pc->clk_pwm[3]);
++
++      pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5");
++        if (IS_ERR(pc->clk_pwm[4]))
++              return PTR_ERR(pc->clk_pwm[4]);
++
++      ret = clk_prepare(pc->clk_top);
++        if (ret < 0)
++              return ret;
++
++      ret = clk_prepare(pc->clk_main);
++      if (ret < 0)
++              goto disable_clk_top;
++
++      platform_set_drvdata(pdev, pc);
++
++      pc->chip.dev = &pdev->dev;
++      pc->chip.ops = &mtk_pwm_ops;
++      pc->chip.base = -1;
++      pc->chip.npwm = NUM_PWM;
++
++      ret = pwmchip_add(&pc->chip);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
++              goto disable_clk_main;
++      }
++
++      return 0;
++
++disable_clk_main:
++      clk_unprepare(pc->clk_main);
++disable_clk_top:
++      clk_unprepare(pc->clk_top);
++
++      return ret;
++}
++
++static int mtk_pwm_remove(struct platform_device *pdev)
++{
++      struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
++      int i;
++
++      for (i = 0; i < NUM_PWM; i++)
++              pwm_disable(&pc->chip.pwms[i]);
++
++      return pwmchip_remove(&pc->chip);
++}
++
++static const struct of_device_id mtk_pwm_of_match[] = {
++      { .compatible = "mediatek,mt7623-pwm" },
++      { }
++};
++
++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
++
++static struct platform_driver mtk_pwm_driver = {
++      .driver = {
++              .name = "mtk-pwm",
++              .owner = THIS_MODULE,
++              .of_match_table = mtk_pwm_of_match,
++      },
++      .probe = mtk_pwm_probe,
++      .remove = mtk_pwm_remove,
++};
++
++module_platform_driver(mtk_pwm_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch
deleted file mode 100644 (file)
index 86d9f45..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From f7121d2b19ddad33a09408a2c5923bfd95da8533 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 6 Jan 2016 20:06:49 +0100
-Subject: [PATCH 017/102] clk: add hifsys reset
-
-Hi,
-
-small patch to add hifsys reset bits. Maybe you could add it to the next
-version of your patch series. i have teste scpsys and clk on mt7623 today
-and it works well.
-
-thanks,
-       John
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/clk/mediatek/clk-mt2701.c                    |    2 ++
- include/dt-bindings/reset-controller/mt2701-resets.h |    9 +++++++++
- 2 files changed, 11 insertions(+)
-
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_register_reset_controller(node, 1, 0x34);
- }
- CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch b/target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch
new file mode 100644 (file)
index 0000000..73ac0ee
--- /dev/null
@@ -0,0 +1,27 @@
+From 2b866d69f6198701457d29c5886c0ad7865c785f Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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 <sean.wang@mediatek.com>
+---
+ 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[] = {
diff --git a/target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch b/target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch
new file mode 100644 (file)
index 0000000..ca0ee04
--- /dev/null
@@ -0,0 +1,78 @@
+From 424ca23e68b043ce26d6981839ca825ef8637aba Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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.
+
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+---
+ .../devicetree/bindings/leds/leds-mt6323.txt       | 60 ++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt
+@@ -0,0 +1,60 @@
++Device Tree Bindings for LED support on MT6323 PMIC
++
++MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED
++controllers are defined as the subnode of the function node provided by MT6323
++PMIC controller that is being defined as one kind of Muti-Function Device (MFD)
++using shared bus called PMIC wrapper for each subfunction to access remote
++MT6323 PMIC hardware.
++
++For MT6323 MFD bindings see:
++Documentation/devicetree/bindings/mfd/mt6397.txt
++For MediaTek PMIC wrapper bindings see:
++Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
++
++Required properties:
++- compatible : Must be "mediatek,mt6323-led"
++- address-cells : Must be 1
++- size-cells : Must be 0
++
++Each led is represented as a child node of the mediatek,mt6323-led that
++describes the initial behavior for each LED physically and currently only four
++LED child nodes can be supported.
++
++Required properties for the LED child node:
++- reg : LED channel number (0..3)
++
++Optional properties for the LED child node:
++- label : See Documentation/devicetree/bindings/leds/common.txt
++- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt
++- default-state: See Documentation/devicetree/bindings/leds/common.txt
++
++Example:
++
++      mt6323: pmic {
++              compatible = "mediatek,mt6323";
++
++              ...
++
++              mt6323led: leds {
++                      compatible = "mediatek,mt6323-led";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++
++                      led@0 {
++                              reg = <0>;
++                              label = "LED0";
++                              linux,default-trigger = "timer";
++                              default-state = "on";
++                      };
++                      led@1 {
++                              reg = <1>;
++                              label = "LED1";
++                              default-state = "off";
++                      };
++                      led@2 {
++                              reg = <2>;
++                              label = "LED2";
++                              default-state = "on";
++                      };
++              };
++      };
diff --git a/target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch b/target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch
new file mode 100644 (file)
index 0000000..c8afdc0
--- /dev/null
@@ -0,0 +1,24 @@
+From 7c137e4b83f32a67ccf6b39fa455aca71980a21f Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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 <sean.wang@mediatek.com>
+---
+ 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.
diff --git a/target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch b/target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch
new file mode 100644 (file)
index 0000000..37b926d
--- /dev/null
@@ -0,0 +1,539 @@
+From e482f9590f2e831c68bcf85e3f9f4c88bbd3329f Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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
+and/or blinked with the controller.
+
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
+---
+ drivers/leds/Kconfig       |   8 +
+ drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 510 insertions(+)
+ create mode 100644 drivers/leds/leds-mt6323.c
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532
+         This option enables support for the so called "User LED" of
+         Mikrotik's Routerboard 532.
++config LEDS_MT6323
++      tristate "LED Support for Mediatek MT6323 PMIC"
++      depends on LEDS_CLASS
++      depends on MFD_MT6397
++      help
++        This option enables support for on-chip LED drivers found on
++        Mediatek MT6323 PMIC.
++
+ config LEDS_S3C24XX
+       tristate "LED Support for Samsung S3C24XX GPIO LEDs"
+       depends on LEDS_CLASS
+--- /dev/null
++++ b/drivers/leds/leds-mt6323.c
+@@ -0,0 +1,502 @@
++/*
++ * LED driver for Mediatek MT6323 PMIC
++ *
++ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/mfd/mt6323/registers.h>
++#include <linux/mfd/mt6397/core.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++
++/*
++ * Register field for MT6323_TOP_CKPDN0 to enable
++ * 32K clock common for LED device.
++ */
++#define MT6323_RG_DRV_32K_CK_PDN      BIT(11)
++#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
++
++/*
++ * Register field for MT6323_TOP_CKPDN2 to enable
++ * individual clock for LED device.
++ */
++#define MT6323_RG_ISINK_CK_PDN(i)     BIT(i)
++#define MT6323_RG_ISINK_CK_PDN_MASK(i)        BIT(i)
++
++/*
++ * Register field for MT6323_TOP_CKCON1 to select
++ * clock source.
++ */
++#define MT6323_RG_ISINK_CK_SEL_MASK(i)        (BIT(10) << (i))
++
++/*
++ * Register for MT6323_ISINK_CON0 to setup the
++ * duty cycle of the blink.
++ */
++#define MT6323_ISINK_CON0(i)          (MT6323_ISINK0_CON0 + 0x8 * (i))
++#define MT6323_ISINK_DIM_DUTY_MASK    (0x1f << 8)
++#define MT6323_ISINK_DIM_DUTY(i)      (((i) << 8) & \
++                                      MT6323_ISINK_DIM_DUTY_MASK)
++
++/* Register to setup the period of the blink. */
++#define MT6323_ISINK_CON1(i)          (MT6323_ISINK0_CON1 + 0x8 * (i))
++#define MT6323_ISINK_DIM_FSEL_MASK    (0xffff)
++#define MT6323_ISINK_DIM_FSEL(i)      ((i) & MT6323_ISINK_DIM_FSEL_MASK)
++
++/* Register to control the brightness. */
++#define MT6323_ISINK_CON2(i)          (MT6323_ISINK0_CON2 + 0x8 * (i))
++#define MT6323_ISINK_CH_STEP_SHIFT    12
++#define MT6323_ISINK_CH_STEP_MASK     (0x7 << 12)
++#define MT6323_ISINK_CH_STEP(i)               (((i) << 12) & \
++                                      MT6323_ISINK_CH_STEP_MASK)
++#define MT6323_ISINK_SFSTR0_TC_MASK   (0x3 << 1)
++#define MT6323_ISINK_SFSTR0_TC(i)     (((i) << 1) & \
++                                      MT6323_ISINK_SFSTR0_TC_MASK)
++#define MT6323_ISINK_SFSTR0_EN_MASK   BIT(0)
++#define MT6323_ISINK_SFSTR0_EN                BIT(0)
++
++/* Register to LED channel enablement. */
++#define MT6323_ISINK_CH_EN_MASK(i)    BIT(i)
++#define MT6323_ISINK_CH_EN(i)         BIT(i)
++
++#define MT6323_MAX_PERIOD             10000
++#define MT6323_MAX_LEDS                       4
++#define MT6323_MAX_BRIGHTNESS         6
++#define MT6323_UNIT_DUTY              3125
++#define MT6323_CAL_HW_DUTY(o, p)      DIV_ROUND_CLOSEST((o) * 100000ul,\
++                                      (p) * MT6323_UNIT_DUTY)
++
++struct mt6323_leds;
++
++/**
++ * struct mt6323_led - state container for the LED device
++ * @id:                       the identifier in MT6323 LED device
++ * @parent:           the pointer to MT6323 LED controller
++ * @cdev:             LED class device for this LED device
++ * @current_brightness: current state of the LED device
++ */
++struct mt6323_led {
++      int                     id;
++      struct mt6323_leds      *parent;
++      struct led_classdev     cdev;
++      enum led_brightness     current_brightness;
++};
++
++/**
++ * struct mt6323_leds -       state container for holding LED controller
++ *                    of the driver
++ * @dev:              the device pointer
++ * @hw:                       the underlying hardware providing shared
++ *                    bus for the register operations
++ * @lock:             the lock among process context
++ * @led:              the array that contains the state of individual
++ *                    LED device
++ */
++struct mt6323_leds {
++      struct device           *dev;
++      struct mt6397_chip      *hw;
++      /* protect among process context */
++      struct mutex            lock;
++      struct mt6323_led       *led[MT6323_MAX_LEDS];
++};
++
++static int mt6323_led_hw_brightness(struct led_classdev *cdev,
++                                  enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      u32 con2_mask = 0, con2_val = 0;
++      int ret;
++
++      /*
++       * Setup current output for the corresponding
++       * brightness level.
++       */
++      con2_mask |= MT6323_ISINK_CH_STEP_MASK |
++                   MT6323_ISINK_SFSTR0_TC_MASK |
++                   MT6323_ISINK_SFSTR0_EN_MASK;
++      con2_val |=  MT6323_ISINK_CH_STEP(brightness - 1) |
++                   MT6323_ISINK_SFSTR0_TC(2) |
++                   MT6323_ISINK_SFSTR0_EN;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
++                               con2_mask, con2_val);
++      return ret;
++}
++
++static int mt6323_led_hw_off(struct led_classdev *cdev)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      status = MT6323_ISINK_CH_EN(led->id);
++      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++                               MT6323_ISINK_CH_EN_MASK(led->id), ~status);
++      if (ret < 0)
++              return ret;
++
++      usleep_range(100, 300);
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++                               MT6323_RG_ISINK_CK_PDN(led->id));
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static enum led_brightness
++mt6323_get_led_hw_brightness(struct led_classdev *cdev)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
++      if (ret < 0)
++              return ret;
++
++      if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
++              return 0;
++
++      ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
++      if (ret < 0)
++              return ret;
++
++      if (!(status & MT6323_ISINK_CH_EN(led->id)))
++              return 0;
++
++      ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
++      if (ret < 0)
++              return ret;
++
++      return  ((status & MT6323_ISINK_CH_STEP_MASK)
++                >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
++}
++
++static int mt6323_led_hw_on(struct led_classdev *cdev,
++                          enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned int status;
++      int ret;
++
++      /*
++       * Setup required clock source, enable the corresponding
++       * clock and channel and let work with continuous blink as
++       * the default.
++       */
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
++                               MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
++      if (ret < 0)
++              return ret;
++
++      status = MT6323_RG_ISINK_CK_PDN(led->id);
++      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
++                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
++                               ~status);
++      if (ret < 0)
++              return ret;
++
++      usleep_range(100, 300);
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
++                               MT6323_ISINK_CH_EN_MASK(led->id),
++                               MT6323_ISINK_CH_EN(led->id));
++      if (ret < 0)
++              return ret;
++
++      ret = mt6323_led_hw_brightness(cdev, brightness);
++      if (ret < 0)
++              return ret;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++                               MT6323_ISINK_DIM_DUTY_MASK,
++                               MT6323_ISINK_DIM_DUTY(31));
++      if (ret < 0)
++              return ret;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++                               MT6323_ISINK_DIM_FSEL_MASK,
++                               MT6323_ISINK_DIM_FSEL(1000));
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static int mt6323_led_set_blink(struct led_classdev *cdev,
++                              unsigned long *delay_on,
++                              unsigned long *delay_off)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      struct regmap *regmap = leds->hw->regmap;
++      unsigned long period;
++      u8 duty_hw;
++      int ret;
++
++      /*
++       * Units are in ms, if over the hardware able
++       * to support, fallback into software blink
++       */
++      period = *delay_on + *delay_off;
++
++      if (period > MT6323_MAX_PERIOD)
++              return -EINVAL;
++
++      /*
++       * LED subsystem requires a default user
++       * friendly blink pattern for the LED so using
++       * 1Hz duty cycle 50% here if without specific
++       * value delay_on and delay off being assigned.
++       */
++      if (!*delay_on && !*delay_off) {
++              *delay_on = 500;
++              *delay_off = 500;
++      }
++
++      /*
++       * Calculate duty_hw based on the percentage of period during
++       * which the led is ON.
++       */
++      duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
++
++      /* hardware doesn't support zero duty cycle. */
++      if (!duty_hw)
++              return -EINVAL;
++
++      mutex_lock(&leds->lock);
++      /*
++       * Set max_brightness as the software blink behavior
++       * when no blink brightness.
++       */
++      if (!led->current_brightness) {
++              ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
++              if (ret < 0)
++                      goto out;
++              led->current_brightness = cdev->max_brightness;
++      }
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
++                               MT6323_ISINK_DIM_DUTY_MASK,
++                               MT6323_ISINK_DIM_DUTY(duty_hw - 1));
++      if (ret < 0)
++              goto out;
++
++      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
++                               MT6323_ISINK_DIM_FSEL_MASK,
++                               MT6323_ISINK_DIM_FSEL(period - 1));
++out:
++      mutex_unlock(&leds->lock);
++
++      return ret;
++}
++
++static int mt6323_led_set_brightness(struct led_classdev *cdev,
++                                   enum led_brightness brightness)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      struct mt6323_leds *leds = led->parent;
++      int ret;
++
++      mutex_lock(&leds->lock);
++
++      if (!led->current_brightness && brightness) {
++              ret = mt6323_led_hw_on(cdev, brightness);
++              if (ret < 0)
++                      goto out;
++      } else if (brightness) {
++              ret = mt6323_led_hw_brightness(cdev, brightness);
++              if (ret < 0)
++                      goto out;
++      } else {
++              ret = mt6323_led_hw_off(cdev);
++              if (ret < 0)
++                      goto out;
++      }
++
++      led->current_brightness = brightness;
++out:
++      mutex_unlock(&leds->lock);
++
++      return ret;
++}
++
++static int mt6323_led_set_dt_default(struct led_classdev *cdev,
++                                   struct device_node *np)
++{
++      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
++      const char *state;
++      int ret = 0;
++
++      led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
++      led->cdev.default_trigger = of_get_property(np,
++                                                  "linux,default-trigger",
++                                                  NULL);
++
++      state = of_get_property(np, "default-state", NULL);
++      if (state) {
++              if (!strcmp(state, "keep")) {
++                      ret = mt6323_get_led_hw_brightness(cdev);
++                      if (ret < 0)
++                              return ret;
++                      led->current_brightness = ret;
++                      ret = 0;
++              } else if (!strcmp(state, "on")) {
++                      ret =
++                      mt6323_led_set_brightness(cdev, cdev->max_brightness);
++              } else  {
++                      ret = mt6323_led_set_brightness(cdev, LED_OFF);
++              }
++      }
++
++      return ret;
++}
++
++static int mt6323_led_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device_node *np = pdev->dev.of_node;
++      struct device_node *child;
++      struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
++      struct mt6323_leds *leds;
++      struct mt6323_led *led;
++      int ret;
++      unsigned int status;
++      u32 reg;
++
++      leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
++      if (!leds)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, leds);
++      leds->dev = dev;
++
++      /*
++       * leds->hw points to the underlying bus for the register
++       * controlled.
++       */
++      leds->hw = hw;
++      mutex_init(&leds->lock);
++
++      status = MT6323_RG_DRV_32K_CK_PDN;
++      ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++                               MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
++      if (ret < 0) {
++              dev_err(leds->dev,
++                      "Failed to update MT6323_TOP_CKPDN0 Register\n");
++              return ret;
++      }
++
++      for_each_available_child_of_node(np, child) {
++              ret = of_property_read_u32(child, "reg", &reg);
++              if (ret) {
++                      dev_err(dev, "Failed to read led 'reg' property\n");
++                      goto put_child_node;
++              }
++
++              if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) {
++                      dev_err(dev, "Invalid led reg %u\n", reg);
++                      ret = -EINVAL;
++                      goto put_child_node;
++              }
++
++              led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
++              if (!led) {
++                      ret = -ENOMEM;
++                      goto put_child_node;
++              }
++
++              leds->led[reg] = led;
++              leds->led[reg]->id = reg;
++              leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
++              leds->led[reg]->cdev.brightness_set_blocking =
++                                      mt6323_led_set_brightness;
++              leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
++              leds->led[reg]->cdev.brightness_get =
++                                      mt6323_get_led_hw_brightness;
++              leds->led[reg]->parent = leds;
++
++              ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
++              if (ret < 0) {
++                      dev_err(leds->dev,
++                              "Failed to LED set default from devicetree\n");
++                      goto put_child_node;
++              }
++
++              ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
++              if (ret) {
++                      dev_err(&pdev->dev, "Failed to register LED: %d\n",
++                              ret);
++                      goto put_child_node;
++              }
++              leds->led[reg]->cdev.dev->of_node = child;
++      }
++
++      return 0;
++
++put_child_node:
++      of_node_put(child);
++      return ret;
++}
++
++static int mt6323_led_remove(struct platform_device *pdev)
++{
++      struct mt6323_leds *leds = platform_get_drvdata(pdev);
++      int i;
++
++      /* Turn the LEDs off on driver removal. */
++      for (i = 0 ; leds->led[i] ; i++)
++              mt6323_led_hw_off(&leds->led[i]->cdev);
++
++      regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
++                         MT6323_RG_DRV_32K_CK_PDN_MASK,
++                         MT6323_RG_DRV_32K_CK_PDN);
++
++      mutex_destroy(&leds->lock);
++
++      return 0;
++}
++
++static const struct of_device_id mt6323_led_dt_match[] = {
++      { .compatible = "mediatek,mt6323-led" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
++
++static struct platform_driver mt6323_led_driver = {
++      .probe          = mt6323_led_probe,
++      .remove         = mt6323_led_remove,
++      .driver         = {
++              .name   = "mt6323-led",
++              .of_match_table = mt6323_led_dt_match,
++      },
++};
++
++module_platform_driver(mt6323_led_driver);
++
++MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
++MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch b/target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch
new file mode 100644 (file)
index 0000000..79e11e8
--- /dev/null
@@ -0,0 +1,27 @@
+From 6e81b4fee93c004078465589128ba07b6855be02 Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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 <sean.wang@mediatek.com>
+Acked-by: Lee Jones <lee.jones@linaro.org>
+---
+ 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"
+       },
diff --git a/target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch b/target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch
new file mode 100644 (file)
index 0000000..f01c841
--- /dev/null
@@ -0,0 +1,32 @@
+From 453ebd5d6b535388972fcea747025ced3afca5cc Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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
+       if (section >= eccsteps)
+               return -ERANGE;
+-      oob_region->length = fdm->reg_size - fdm->ecc_size;
+-      oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
++      oob_region->length = fdm->reg_size - 1;
++      oob_region->offset = section * fdm->reg_size + 1;
+       return 0;
+ }
+@@ -1114,7 +1114,7 @@ static void mtk_nfc_set_fdm(struct mtk_n
+               fdm->reg_size = NFI_FDM_MAX_SIZE;
+       /* bad block mark storage */
+-      fdm->ecc_size = 1;
++      fdm->ecc_size = fdm->reg_size;
+ }
+ static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
diff --git a/target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch b/target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch
new file mode 100644 (file)
index 0000000..153031b
--- /dev/null
@@ -0,0 +1,81 @@
+From 4ad0accdfb0941de1440906461c08bee715378d5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:57:44 +0200
+Subject: [PATCH 23/57] rng: add mediatek hw rng
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
deleted file mode 100644 (file)
index d6fe977..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-From 05be818061b9f2a0fa5ad0cde6881917ff14a2f2 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 6 Jan 2016 21:55:10 +0100
-Subject: [PATCH 024/102] dt-bindings: add MediaTek PCIe binding documentation
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- .../devicetree/bindings/pci/mediatek-pcie.txt      |  140 ++++++++++++++++++++
- 1 file changed, 140 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
-@@ -0,0 +1,140 @@
-+Mediatek PCIe controller
-+
-+Required properties:
-+- compatible: Should be one of:
-+      - "mediatek,mt2701-pcie"
-+      - "mediatek,mt7623-pcie"
-+- device_type: Must be "pci"
-+- reg: A list of physical base address and length for each set of controller
-+  registers. A list of register ranges to use. Must contain an
-+    entry for each entry in the reg-names property.
-+- reg-names: Must include the following entries:
-+  "pcie": PCIe registers
-+  "pcie phy0": PCIe PHY0 registers
-+  "pcie phy1": PCIe PHY0 registers
-+  "pcie phy2": PCIe PHY0 registers
-+- interrupts: A list of interrupt outputs of the controller. Must contain an
-+  entry for each entry in the interrupt-names property.
-+- interrupt-names: Must include the following entries:
-+  "pcie0": The interrupt that is asserted for port0
-+  "pcie1": The interrupt that is asserted for port1
-+  "pcie2": The interrupt that is asserted for port2
-+- bus-range: Range of bus numbers associated with this controller
-+- #address-cells: Address representation for root ports (must be 3)
-+- #size-cells: Size representation for root ports (must be 2)
-+- ranges: Describes the translation of addresses for root ports and standard
-+  PCI regions. The entries must be 6 cells each.
-+  Please refer to the standard PCI bus binding document for a more detailed
-+  explanation.
-+- #interrupt-cells: Size representation for interrupts (must be 1)
-+- clocks: Must contain an entry for each entry in clock-names.
-+  See ../clocks/clock-bindings.txt for details.
-+- clock-names: Must include the following entries:
-+  - pcie0
-+  - pcie1
-+  - pcie2
-+- resets: Must contain an entry for each entry in reset-names.
-+  See ../reset/reset.txt for details.
-+- reset-names: Must include the following entries:
-+  - pcie0
-+  - pcie1
-+  - pcie2
-+- mediatek,hifsys: Must contain a phandle to the HIFSYS syscon range.
-+Root ports are defined as subnodes of the PCIe controller node.
-+
-+Required properties:
-+- device_type: Must be "pci"
-+- assigned-addresses: Address and size of the port configuration registers
-+- reg: PCI bus address of the root port
-+- #address-cells: Must be 3
-+- #size-cells: Must be 2
-+- ranges: Sub-ranges distributed from the PCIe controller node. An empty
-+  property is sufficient.
-+
-+Example:
-+
-+SoC DTSI:
-+
-+      hifsys: clock-controller@1a000000 {
-+              compatible = "mediatek,mt7623-hifsys",
-+                           "mediatek,mt2701-hifsys",
-+                           "syscon";
-+              reg = <0 0x1a000000 0 0x1000>;
-+              #clock-cells = <1>;
-+              #reset-cells = <1>;
-+      };
-+
-+      pcie-controller@1a140000 {
-+              compatible = "mediatek,mt7623-pcie";
-+              device_type = "pci";
-+              reg = <0 0x1a140000 0 0x8000>, /* PCI-Express registers */
-+                    <0 0x1a149000 0 0x1000>, /* PCI-Express PHY0 */
-+                    <0 0x1a14a000 0 0x1000>, /* PCI-Express PHY1 */
-+                    <0 0x1a244000 0 0x1000>; /* PCI-Express PHY2 */
-+              reg-names = "pcie", "pcie phy0", "pcie phy1", "pcie phy2";
-+              interrupts = <GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>,
-+                           <GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>,
-+                           <GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>;
-+              interrupt-names = "pcie0", "pcie1", "pcie2";
-+              clocks = <&topckgen CLK_TOP_ETHIF_SEL>;
-+              clock-names = "pcie";
-+              power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>;
-+              resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>,
-+                       <&hifsys MT2701_HIFSYS_PCIE1_RST>,
-+                       <&hifsys MT2701_HIFSYS_PCIE2_RST>;
-+              reset-names = "pcie0", "pice1", "pcie2";
-+
-+              bus-range = <0x00 0xff>;
-+              #address-cells = <3>;
-+              #size-cells = <2>;
-+
-+                mediatek,hifsys = <&hifsys>;
-+
-+              ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* io space */
-+                        0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* pci memory */
-+
-+              status = "disabled";
-+
-+              pcie@1,0 {
-+                      device_type = "pci";
-+                      reg = <0x0800 0 0 0 0>;
-+
-+                      #address-cells = <3>;
-+                      #size-cells = <2>;
-+                      ranges;
-+
-+                      status = "disabled";
-+              };
-+
-+              pcie@2,0{
-+                      device_type = "pci";
-+                      reg = <0x1000 0 0 0 0>;
-+
-+                      #address-cells = <3>;
-+                      #size-cells = <2>;
-+                      ranges;
-+
-+                      status = "disabled";
-+              };
-+
-+              pcie@3,0{
-+                      device_type = "pci";
-+                      reg = <0x1800 0 0 0 0>;
-+
-+                      #address-cells = <3>;
-+                      #size-cells = <2>;
-+                      ranges;
-+
-+                      status = "disabled";
-+              };
-+      };
-+
-+Board DTS:
-+
-+      pcie-controller {
-+              status = "okay";
-+
-+              pci@1,0 {
-+                      status = "okay";
-+              };
-+      };
diff --git a/target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch b/target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch
new file mode 100644 (file)
index 0000000..fbdfbe9
--- /dev/null
@@ -0,0 +1,1034 @@
+From 6e0336d1660725c06b6ab4f5361873538dbaa9f9 Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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 <sean.wang@mediatek.com>
+Reviewed-by: Sean Young <sean@mess.org>
+---
+ 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 <sean.wang@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#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 <sean.wang@mediatek.com>");
++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);
diff --git a/target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
deleted file mode 100644 (file)
index 1ab8ce2..0000000
+++ /dev/null
@@ -1,698 +0,0 @@
-From 8ab1d4e0a9a68e03f472dee1c036a01d0198c20c Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 5 Jan 2016 20:20:04 +0100
-Subject: [PATCH 025/102] PCI: mediatek: add support for PCIe found on
- MT7623/MT2701
-
-Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
-a single Root complex (RC) with 3 Root Ports. The SoCs supports a Gen2
-1-lan Link on each port.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- 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
- config MACH_MT7623
-       bool "MediaTek MT7623 SoCs support"
-       default ARCH_MEDIATEK
-+      select MIGHT_HAVE_PCI
- config MACH_MT8127
-       bool "MediaTek MT8127 SoCs support"
---- a/drivers/pci/host/Kconfig
-+++ b/drivers/pci/host/Kconfig
-@@ -301,4 +301,15 @@ config VMD
-         To compile this driver as a module, choose M here: the
-         module will be called vmd.
-+config PCIE_MTK
-+      bool "Mediatek PCIe Controller"
-+      depends on MACH_MT2701 || MACH_MT7623
-+      depends on OF
-+      depends on PCI
-+      help
-+        Say Y here if you want to enable PCI controller support on Mediatek MT7623.
-+        MT7623 PCIe supports single Root complex (RC) with 3 Root Ports.
-+        Each port supports a Gen2 1-lan Link.
-+        PCIe include one Host/PCI bridge and 3 PCIe MAC.
-+
- endmenu
---- a/drivers/pci/host/Makefile
-+++ b/drivers/pci/host/Makefile
-@@ -33,3 +33,4 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-arm
- obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
- obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
- obj-$(CONFIG_VMD) += vmd.o
-+obj-$(CONFIG_PCIE_MTK) += pcie-mediatek.o
---- /dev/null
-+++ b/drivers/pci/host/pcie-mediatek.c
-@@ -0,0 +1,641 @@
-+/*
-+ *  Mediatek MT2701/MT7623 SoC PCIE support
-+ *
-+ *  Copyright (C) 2015 Mediatek
-+ *  Copyright (C) 2015 Ziv Huang <ziv.huang@mediatek.com>
-+ *  Copyright (C) 2015 John Crispin <blogic@openwrt.org>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify it
-+ *  under the terms of the GNU General Public License version 2 as published
-+ *  by the Free Software Foundation.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include <linux/ioport.h>
-+#include <linux/interrupt.h>
-+#include <linux/spinlock.h>
-+#include <linux/init.h>
-+#include <linux/device.h>
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <asm/irq.h>
-+#include <asm/mach/pci.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_pci.h>
-+#include <linux/of_platform.h>
-+#include <linux/of_irq.h>
-+#include <linux/reset.h>
-+#include <linux/platform_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/clk.h>
-+#include <linux/regmap.h>
-+#include <linux/mfd/syscon.h>
-+
-+#define MEMORY_BASE                   0x80000000
-+
-+/* PCIE Registers */
-+#define PCICFG                                0x00
-+#define PCIINT                                0x08
-+#define PCIENA                                0x0c
-+#define CFGADDR                               0x20
-+#define CFGDATA                               0x24
-+#define MEMBASE                               0x28
-+#define IOBASE                                0x2c
-+
-+/* per Port Registers */
-+#define BAR0SETUP                     0x10
-+#define IMBASEBAR0                    0x18
-+#define PCIE_CLASS                    0x34
-+#define PCIE_SISTAT                   0x50
-+
-+#define MTK_PCIE_HIGH_PERF            BIT(14)
-+#define PCIEP0_BASE                   0x2000
-+#define PCIEP1_BASE                   0x3000
-+#define PCIEP2_BASE                   0x4000
-+
-+#define PHY_P0_CTL                    0x9000
-+#define PHY_P1_CTL                    0xa000
-+#define PHY_P2_CTL                    0x4000
-+
-+#define RSTCTL_PCIE0_RST              BIT(24)
-+#define RSTCTL_PCIE1_RST              BIT(25)
-+#define RSTCTL_PCIE2_RST              BIT(26)
-+
-+#define HIFSYS_SYSCFG1                        0x14
-+#define HIFSYS_SYSCFG1_PHY2_MASK      (0x3 << 20)
-+
-+#define MTK_PHY_CLK                   0xb00
-+#define MTK_PHY_CLKDRV_OFFSET         BIT(2)
-+#define MTK_PHY_CLKDRV_OFFSET_MASK    0xe
-+#define MTK_PHY_PLL                   0xb04
-+#define MTK_PHY_CLKDRV_AMP            BIT(30)
-+#define MTK_PHY_CLKDRV_AMP_MASK               0xe0000000
-+#define MTK_PHY_REFCLK_SEL            0xc00
-+#define MTK_PHY_XTAL_EXT_EN           (BIT(17) | BIT(12))
-+#define MTK_PHY_XTAL_EXT_EN_MASK      0x33000
-+#define MTK_PHY_PLL_BC                        0xc08
-+#define MTK_PHY_PLL_BC_PE2H           0xc0
-+#define MTK_PHY_PLL_BC_PE2H_MASK      0x380000
-+#define MTK_PHY_PLL_IC                        0xc0c
-+#define MTK_PHY_PLL_IC_BR_PE2H                BIT(28)
-+#define MTK_PHY_PLL_IC_BR_PE2H_MASK   0x30000000
-+#define MTK_PHY_PLL_IC_PE2H           BIT(12)
-+#define MTK_PHY_PLL_IC_PE2H_MASK      0xf000
-+#define MTK_PHY_PLL_IR                        0xc10
-+#define MTK_PHY_PLL_IR_PE2H           BIT(17)
-+#define MTK_PHY_PLL_IR_PE2H_MASK      0xf0000
-+#define MTK_PHY_PLL_BP                        0xc14
-+#define MTK_PHY_PLL_BP_PE2H           (BIT(19) | BIT(17))
-+#define MTK_PHY_PLL_BP_PE2H_MASK      0xf0000
-+#define MTK_PHY_SSC_DELTA1            0xc3c
-+#define MTK_PHY_SSC_DELTA1_PE2H               (0x3c << 16)
-+#define MTK_PHY_SSC_DELTA1_PE2H_MASK  0xffff0000
-+#define MTK_PHY_SSC_DELTA             0xc48
-+#define MTK_PHY_SSC_DELTA_PE2H                0x36
-+#define MTK_PHY_SSC_DELTA_PE2H_MASK   0xffff
-+
-+#define MAX_PORT_NUM                  3
-+
-+struct mtk_pcie_port {
-+      int id;
-+      int enable;
-+      int irq;
-+      u32 link;
-+      void __iomem *phy_base;
-+      struct reset_control *rstc;
-+};
-+
-+#define mtk_foreach_port(pcie, p)                     \
-+              for ((p) = pcie->port;  \
-+                   (p) != &pcie->port[MAX_PORT_NUM]; (p)++)
-+
-+struct mtk_pcie {
-+      struct device *dev;
-+      void __iomem *pcie_base;
-+      struct regmap *hifsys;
-+
-+      struct resource io;
-+      struct resource pio;
-+      struct resource mem;
-+      struct resource prefetch;
-+      struct resource busn;
-+
-+      u32 io_bus_addr;
-+      u32 mem_bus_addr;
-+
-+      struct clk *clk;
-+
-+      struct mtk_pcie_port port[MAX_PORT_NUM];
-+      int pcie_card_link;
-+};
-+
-+static struct mtk_pcie_port_data {
-+      u32 base;
-+      u32 perst_n;
-+      u32 interrupt_en;
-+} mtk_pcie_port_data[MAX_PORT_NUM] = {
-+      { PCIEP0_BASE, BIT(1), BIT(20) },
-+      { PCIEP1_BASE, BIT(2), BIT(21) },
-+      { PCIEP2_BASE, BIT(3), BIT(22) },
-+};
-+
-+static const struct mtk_phy_init {
-+      uint32_t reg;
-+      uint32_t mask;
-+      uint32_t val;
-+} mtk_phy_init[] = {
-+      { MTK_PHY_REFCLK_SEL, MTK_PHY_XTAL_EXT_EN_MASK, MTK_PHY_XTAL_EXT_EN },
-+      { MTK_PHY_PLL, MTK_PHY_CLKDRV_AMP_MASK, MTK_PHY_CLKDRV_AMP },
-+      { MTK_PHY_CLK, MTK_PHY_CLKDRV_OFFSET_MASK, MTK_PHY_CLKDRV_OFFSET },
-+      { MTK_PHY_SSC_DELTA1, MTK_PHY_SSC_DELTA1_PE2H_MASK, MTK_PHY_SSC_DELTA1_PE2H },
-+      { MTK_PHY_SSC_DELTA, MTK_PHY_SSC_DELTA_PE2H_MASK, MTK_PHY_SSC_DELTA_PE2H },
-+      { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_BR_PE2H_MASK, MTK_PHY_PLL_IC_BR_PE2H },
-+      { MTK_PHY_PLL_BC, MTK_PHY_PLL_BC_PE2H_MASK, MTK_PHY_PLL_BC_PE2H },
-+      { MTK_PHY_PLL_IR, MTK_PHY_PLL_IR_PE2H_MASK, MTK_PHY_PLL_IR_PE2H },
-+      { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_PE2H_MASK, MTK_PHY_PLL_IC_PE2H },
-+      { MTK_PHY_PLL_BP, MTK_PHY_PLL_BP_PE2H_MASK, MTK_PHY_PLL_BP_PE2H },
-+};
-+
-+static struct mtk_pcie *sys_to_pcie(struct pci_sys_data *sys)
-+{
-+      return sys->private_data;
-+}
-+
-+static void pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned reg)
-+{
-+      iowrite32(val, pcie->pcie_base + reg);
-+}
-+
-+static u32 pcie_r32(struct mtk_pcie *pcie, unsigned reg)
-+{
-+      return ioread32(pcie->pcie_base + reg);
-+}
-+
-+static void pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned reg)
-+{
-+      u32 v = pcie_r32(pcie, reg);
-+
-+      v &= mask;
-+      v |= val;
-+      pcie_w32(pcie, v, reg);
-+}
-+
-+static int pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where,
-+                          int size, u32 *val)
-+{
-+      struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata);
-+      unsigned int slot = PCI_SLOT(devfn);
-+      u8 func = PCI_FUNC(devfn);
-+      u32 address;
-+      u32 data;
-+      u32 num = 0;
-+
-+      if (bus)
-+              num = bus->number;
-+
-+      address = (((where & 0xf00) >> 8) << 24) |
-+                (num << 16) |
-+                (slot << 11) |
-+                (func << 8) |
-+                (where & 0xfc);
-+
-+      pcie_w32(pcie, address, CFGADDR);
-+      data = pcie_r32(pcie, CFGDATA);
-+
-+      switch (size) {
-+      case 1:
-+              *val = (data >> ((where & 3) << 3)) & 0xff;
-+              break;
-+      case 2:
-+              *val = (data >> ((where & 3) << 3)) & 0xffff;
-+              break;
-+      case 4:
-+              *val = data;
-+              break;
-+      }
-+
-+      return PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int pcie_config_write(struct pci_bus *bus, unsigned int devfn, int where,
-+                           int size, u32 val)
-+{
-+      struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata);
-+      unsigned int slot = PCI_SLOT(devfn);
-+      u8 func = PCI_FUNC(devfn);
-+      u32 address;
-+      u32 data;
-+      u32 num = 0;
-+
-+      if (bus)
-+              num = bus->number;
-+
-+      address = (((where & 0xf00) >> 8) << 24) |
-+                (num << 16) | (slot << 11) | (func << 8) | (where & 0xfc);
-+      pcie_w32(pcie, address, CFGADDR);
-+      data = pcie_r32(pcie, CFGDATA);
-+
-+      switch (size) {
-+      case 1:
-+              data = (data & ~(0xff << ((where & 3) << 3))) |
-+                     (val << ((where & 3) << 3));
-+              break;
-+      case 2:
-+              data = (data & ~(0xffff << ((where & 3) << 3))) |
-+                     (val << ((where & 3) << 3));
-+              break;
-+      case 4:
-+              data = val;
-+              break;
-+      }
-+      pcie_w32(pcie, data, CFGDATA);
-+
-+      return PCIBIOS_SUCCESSFUL;
-+}
-+
-+static struct pci_ops mtk_pcie_ops = {
-+      .read   = pcie_config_read,
-+      .write  = pcie_config_write,
-+};
-+
-+static int __init mtk_pcie_setup(int nr, struct pci_sys_data *sys)
-+{
-+      struct mtk_pcie *pcie = sys_to_pcie(sys);
-+
-+      request_resource(&ioport_resource, &pcie->pio);
-+      request_resource(&iomem_resource, &pcie->mem);
-+
-+      pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
-+      pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset);
-+      pci_add_resource(&sys->resources, &pcie->busn);
-+
-+      return 1;
-+}
-+
-+static struct pci_bus * __init mtk_pcie_scan_bus(int nr,
-+                                              struct pci_sys_data *sys)
-+{
-+      struct mtk_pcie *pcie = sys_to_pcie(sys);
-+      struct pci_bus *bus;
-+
-+      bus = pci_create_root_bus(pcie->dev, sys->busnr, &mtk_pcie_ops, sys,
-+                                &sys->resources);
-+      if (!bus)
-+              return NULL;
-+
-+      pci_scan_child_bus(bus);
-+
-+      return bus;
-+}
-+
-+static int __init mtk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+      struct mtk_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
-+      struct mtk_pcie_port *port;
-+      int irq = -1;
-+
-+      mtk_foreach_port(pcie, port)
-+              if (port->id == slot)
-+                      irq = port->irq;
-+
-+      return irq;
-+}
-+
-+static void mtk_pcie_configure_phy(struct mtk_pcie *pcie,
-+                                 struct mtk_pcie_port *port)
-+{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) {
-+              void __iomem *phy_addr = port->phy_base + mtk_phy_init[i].reg;
-+              u32 val = ioread32(phy_addr);
-+
-+              val &= ~mtk_phy_init[i].mask;
-+              val |= mtk_phy_init[i].val;
-+              iowrite32(val, phy_addr);
-+      }
-+      usleep_range(5000, 6000);
-+}
-+
-+static void mtk_pcie_configure_rc(struct mtk_pcie *pcie,
-+                                struct mtk_pcie_port *port,
-+                                struct pci_bus *bus)
-+{
-+      u32 val = 0;
-+
-+      pcie_config_write(bus,
-+                        port->id << 3,
-+                        PCI_BASE_ADDRESS_0, 4, MEMORY_BASE);
-+
-+      pcie_config_read(bus,
-+                       port->id << 3, PCI_BASE_ADDRESS_0, 4, &val);
-+
-+      /* Configure RC Credit */
-+      pcie_config_read(bus, port->id << 3, 0x73c, 4, &val);
-+      val &= ~(0x9fff) << 16;
-+      val |= 0x806c << 16;
-+      pcie_config_write(bus, port->id << 3, 0x73c, 4, val);
-+
-+      /* Configure RC FTS number */
-+      pcie_config_read(bus, port->id << 3, 0x70c, 4, &val);
-+      val &= ~(0xff3) << 8;
-+      val |= 0x50 << 8;
-+      pcie_config_write(bus, port->id << 3, 0x70c, 4, val);
-+}
-+
-+static int mtk_pcie_preinit(struct mtk_pcie *pcie)
-+{
-+      struct mtk_pcie_port *port;
-+      u32 val = 0;
-+      struct pci_bus bus;
-+      struct pci_sys_data sys;
-+
-+      memset(&bus, 0, sizeof(bus));
-+      memset(&sys, 0, sizeof(sys));
-+      bus.sysdata = (void *)&sys;
-+      sys.private_data = (void *)pcie;
-+
-+      pcibios_min_io = 0;
-+      pcibios_min_mem = 0;
-+
-+      /* The PHY on Port 2 is shared with USB */
-+      if (pcie->port[2].enable)
-+              regmap_update_bits(pcie->hifsys, HIFSYS_SYSCFG1,
-+                                 HIFSYS_SYSCFG1_PHY2_MASK, 0x0);
-+
-+      /* PCIe RC Reset */
-+      mtk_foreach_port(pcie, port)
-+              if (port->enable)
-+                      reset_control_assert(port->rstc);
-+      usleep_range(1000, 2000);
-+      mtk_foreach_port(pcie, port)
-+              if (port->enable)
-+                      reset_control_deassert(port->rstc);
-+      usleep_range(1000, 2000);
-+
-+      /* Configure PCIe PHY */
-+      mtk_foreach_port(pcie, port)
-+              if (port->enable)
-+                      mtk_pcie_configure_phy(pcie, port);
-+
-+      /* PCIe EP reset */
-+      val = 0;
-+      mtk_foreach_port(pcie, port)
-+              if (port->enable)
-+                      val |= mtk_pcie_port_data[port->id].perst_n;
-+      pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG);
-+      usleep_range(1000, 2000);
-+      pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG);
-+      usleep_range(1000, 2000);
-+      msleep(100);
-+
-+      /* check the link status */
-+      val = 0;
-+      mtk_foreach_port(pcie, port) {
-+              if (port->enable) {
-+                      u32 base = mtk_pcie_port_data[port->id].base;
-+
-+                      if ((pcie_r32(pcie, base + PCIE_SISTAT) & 0x1))
-+                              port->link = 1;
-+                      else
-+                              reset_control_assert(port->rstc);
-+              }
-+      }
-+
-+      mtk_foreach_port(pcie, port)
-+              if (port->link)
-+                      pcie->pcie_card_link++;
-+
-+      if (!pcie->pcie_card_link)
-+              return -ENODEV;
-+
-+      pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE);
-+      pcie_w32(pcie, pcie->io_bus_addr, IOBASE);
-+
-+      mtk_foreach_port(pcie, port) {
-+              if (port->link) {
-+                      u32 base = mtk_pcie_port_data[port->id].base;
-+                      u32 inte = mtk_pcie_port_data[port->id].interrupt_en;
-+
-+                      pcie_m32(pcie, 0, inte, PCIENA);
-+                      pcie_w32(pcie, 0x7fff0001, base + BAR0SETUP);
-+                      pcie_w32(pcie, MEMORY_BASE, base + IMBASEBAR0);
-+                      pcie_w32(pcie, 0x06040001, base + PCIE_CLASS);
-+              }
-+      }
-+
-+      mtk_foreach_port(pcie, port)
-+              if (port->link)
-+                      mtk_pcie_configure_rc(pcie, port, &bus);
-+
-+      return 0;
-+}
-+
-+static int mtk_pcie_parse_dt(struct mtk_pcie *pcie)
-+{
-+      struct device_node *np = pcie->dev->of_node, *port;
-+      struct of_pci_range_parser parser;
-+      struct of_pci_range range;
-+      struct resource res;
-+      int err;
-+
-+      pcie->hifsys = syscon_regmap_lookup_by_phandle(np, "mediatek,hifsys");
-+      if (IS_ERR(pcie->hifsys)) {
-+              dev_err(pcie->dev, "missing \"mediatek,hifsys\" phandle\n");
-+              return PTR_ERR(pcie->hifsys);
-+      }
-+
-+      if (of_pci_range_parser_init(&parser, np)) {
-+              dev_err(pcie->dev, "missing \"ranges\" property\n");
-+              return -EINVAL;
-+      }
-+
-+      for_each_of_pci_range(&parser, &range) {
-+              err = of_pci_range_to_resource(&range, np, &res);
-+              if (err < 0) {
-+                      dev_err(pcie->dev, "failed to read resource range\n");
-+                      return err;
-+              }
-+
-+              switch (res.flags & IORESOURCE_TYPE_BITS) {
-+              case IORESOURCE_IO:
-+                      memcpy(&pcie->pio, &res, sizeof(res));
-+                      pcie->pio.start = (resource_size_t)range.pci_addr;
-+                      pcie->pio.end = (resource_size_t)
-+                                      (range.pci_addr + range.size - 1);
-+                      pcie->io_bus_addr = (resource_size_t)range.cpu_addr;
-+                      break;
-+
-+              case IORESOURCE_MEM:
-+                      if (res.flags & IORESOURCE_PREFETCH) {
-+                              memcpy(&pcie->prefetch, &res, sizeof(res));
-+                              pcie->prefetch.name = "prefetchable";
-+                              pcie->prefetch.start =
-+                                      (resource_size_t)range.pci_addr;
-+                              pcie->prefetch.end = (resource_size_t)
-+                                      (range.pci_addr + range.size - 1);
-+                      } else {
-+                              memcpy(&pcie->mem, &res, sizeof(res));
-+                              pcie->mem.name = "non-prefetchable";
-+                              pcie->mem.start = (resource_size_t)
-+                                      range.pci_addr;
-+                              pcie->prefetch.end = (resource_size_t)
-+                                      (range.pci_addr + range.size - 1);
-+                              pcie->mem_bus_addr = (resource_size_t)
-+                                      range.cpu_addr;
-+                      }
-+                      break;
-+              }
-+      }
-+
-+      err = of_pci_parse_bus_range(np, &pcie->busn);
-+      if (err < 0) {
-+              dev_err(pcie->dev, "failed to parse ranges property: %d\n",
-+                      err);
-+              pcie->busn.name = np->name;
-+              pcie->busn.start = 0;
-+              pcie->busn.end = 0xff;
-+              pcie->busn.flags = IORESOURCE_BUS;
-+      }
-+
-+      /* parse root ports */
-+      for_each_child_of_node(np, port) {
-+              unsigned int index;
-+              char rst[] = "pcie0";
-+
-+              err = of_pci_get_devfn(port);
-+              if (err < 0) {
-+                      dev_err(pcie->dev, "failed to parse address: %d\n",
-+                              err);
-+                      return err;
-+              }
-+
-+              index = PCI_SLOT(err);
-+              if (index > MAX_PORT_NUM) {
-+                      dev_err(pcie->dev, "invalid port number: %d\n", index);
-+                      continue;
-+              }
-+              index--;
-+              pcie->port[index].id = index;
-+
-+              if (!of_device_is_available(port))
-+                      continue;
-+
-+              rst[4] += index;
-+              pcie->port[index].rstc = devm_reset_control_get(pcie->dev,
-+                                                                 rst);
-+              if (!IS_ERR(pcie->port[index].rstc))
-+                      pcie->port[index].enable = 1;
-+      }
-+      return 0;
-+}
-+
-+static int mtk_pcie_get_resources(struct mtk_pcie *pcie)
-+{
-+      struct platform_device *pdev = to_platform_device(pcie->dev);
-+      struct mtk_pcie_port *port;
-+      struct resource *res;
-+
-+      pcie->clk = devm_clk_get(&pdev->dev, "pcie");
-+      if (IS_ERR(pcie->clk)) {
-+              dev_err(&pdev->dev, "Failed to get pcie clk\n");
-+              return PTR_ERR(pcie->clk);
-+      }
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      pcie->pcie_base = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(pcie->pcie_base)) {
-+              dev_err(&pdev->dev, "Failed to get pcie range\n");
-+              return PTR_ERR(pcie->pcie_base);
-+      }
-+
-+      mtk_foreach_port(pcie, port) {
-+              if (!port->enable)
-+                      continue;
-+              res = platform_get_resource(pdev, IORESOURCE_MEM, port->id + 1);
-+              port->phy_base = devm_ioremap_resource(&pdev->dev, res);
-+              if (IS_ERR(port->phy_base)) {
-+                      dev_err(&pdev->dev, "Failed to get pcie phy%d range %p\n",
-+                              port->id, port->phy_base);
-+                      return PTR_ERR(port->phy_base);
-+              }
-+              port->irq = platform_get_irq(pdev, port->id);
-+      }
-+
-+      return clk_prepare_enable(pcie->clk);
-+}
-+
-+static int mtk_pcie_probe(struct platform_device *pdev)
-+{
-+      struct mtk_pcie *pcie;
-+      struct hw_pci hw;
-+      int ret;
-+
-+      pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
-+      if (!pcie)
-+              return -ENOMEM;
-+
-+      pcie->dev = &pdev->dev;
-+      ret = mtk_pcie_parse_dt(pcie);
-+      if (ret < 0)
-+              return ret;
-+
-+      pm_runtime_enable(&pdev->dev);
-+      pm_runtime_get_sync(&pdev->dev);
-+
-+      ret = mtk_pcie_get_resources(pcie);
-+      if (ret < 0) {
-+              dev_err(&pdev->dev, "failed to request resources: %d\n", ret);
-+              goto err_out;
-+      }
-+
-+      ret = mtk_pcie_preinit(pcie);
-+      if (ret)
-+              return ret;
-+
-+      memset(&hw, 0, sizeof(hw));
-+      hw.nr_controllers = 1;
-+      hw.private_data = (void **)&pcie;
-+      hw.setup = mtk_pcie_setup;
-+      hw.map_irq = mtk_pcie_map_irq;
-+      hw.scan = mtk_pcie_scan_bus;
-+
-+      pci_common_init_dev(pcie->dev, &hw);
-+      platform_set_drvdata(pdev, pcie);
-+
-+      return 0;
-+
-+err_out:
-+      clk_disable_unprepare(pcie->clk);
-+      pm_runtime_put_sync(&pdev->dev);
-+      pm_runtime_disable(&pdev->dev);
-+
-+      return ret;
-+}
-+
-+static const struct of_device_id mtk_pcie_ids[] = {
-+      { .compatible = "mediatek,mt2701-pcie" },
-+      { .compatible = "mediatek,mt7623-pcie" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, mtk_pcie_ids);
-+
-+static struct platform_driver mtk_pcie_driver = {
-+      .probe = mtk_pcie_probe,
-+      .driver = {
-+              .name = "mediatek-pcie",
-+              .owner = THIS_MODULE,
-+              .of_match_table = of_match_ptr(mtk_pcie_ids),
-+      },
-+};
-+
-+static int __init mtk_pcie_init(void)
-+{
-+      return platform_driver_register(&mtk_pcie_driver);
-+}
-+
-+module_init(mtk_pcie_init);
diff --git a/target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch b/target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch
new file mode 100644 (file)
index 0000000..24e13d1
--- /dev/null
@@ -0,0 +1,110 @@
+From 3b9b46b5705214b16c5356284ad68be32ae56a26 Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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.
+
+Cc: devicetree@vger.kernel.org
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Acked-by: Rob Herring <robh@kernel.org>
+---
+ .../devicetree/bindings/net/dsa/mt7530.txt         | 92 ++++++++++++++++++++++
+ 1 file changed, 92 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt
+@@ -0,0 +1,92 @@
++Mediatek MT7530 Ethernet switch
++================================
++
++Required properties:
++
++- compatible: Must be compatible = "mediatek,mt7530";
++- #address-cells: Must be 1.
++- #size-cells: Must be 0.
++- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
++      on multi-chip module belong to MT7623A has or the remotely standalone
++      chip as the function MT7623N reference board provided for.
++- core-supply: Phandle to the regulator node necessary for the core power.
++- io-supply: Phandle to the regulator node necessary for the I/O power.
++      See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
++      for details for the regulator setup on these boards.
++
++If the property mediatek,mcm isn't defined, following property is required
++
++- reset-gpios: Should be a gpio specifier for a reset line.
++
++Else, following properties are required
++
++- resets : Phandle pointing to the system reset controller with
++      line index for the ethsys.
++- reset-names : Should be set to "mcm".
++
++Required properties for the child nodes within ports container:
++
++- reg: Port address described must be 6 for CPU port and from 0 to 5 for
++      user ports.
++- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
++       "cpu".
++
++See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
++required, optional properties and how the integrated switch subnodes must
++be specified.
++
++Example:
++
++      &mdio0 {
++              switch@0 {
++                      compatible = "mediatek,mt7530";
++                      #address-cells = <1>;
++                      #size-cells = <0>;
++                      reg = <0>;
++
++                      core-supply = <&mt6323_vpa_reg>;
++                      io-supply = <&mt6323_vemc3v3_reg>;
++                      reset-gpios = <&pio 33 0>;
++
++                      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@4 {
++                                      reg = <4>;
++                                      label = "wan";
++                              };
++
++                              port@6 {
++                                      reg = <6>;
++                                      label = "cpu";
++                                      ethernet = <&gmac0>;
++                                      phy-mode = "trgmii";
++                                      fixed-link {
++                                              speed = <1000>;
++                                              full-duplex;
++                                      };
++                              };
++                      };
++              };
++      };
diff --git a/target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch b/target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch
new file mode 100644 (file)
index 0000000..8a6d593
--- /dev/null
@@ -0,0 +1,1788 @@
+From 99d9d02a05df503184be094de336e7515fe3e235 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 14:26:29 +0200
+Subject: [PATCH 26/57] net: mediatek: backport v4.10 driver
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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 <sean.wang@mediatek.com>
++ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
++ */
++
++#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 <sean.wang@mediatek.com>");
++MODULE_AUTHOR("John Crispin <john@phrozen.org>");
++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 <sean.wang@mediatek.com>
++ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
++ */
++
++#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 <sean.wang@mediatek.com>
++ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
++ */
++
++#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 <sean.wang@mediatek.com>
++ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
++ */
++
++#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 <sean.wang@mediatek.com>
++ *   Copyright (C) 2016-2017 John Crispin <blogic@openwrt.org>
++ */
++
++#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
++
diff --git a/target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch
deleted file mode 100644 (file)
index 8784166..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-From 59aafd667d2880c90776931b6102b8252214d93c Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 21 Feb 2016 13:52:12 +0100
-Subject: [PATCH 026/102] 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(-)
-
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_register_reset_controller(node, 1, 0x34);
- }
- CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch
new file mode 100644 (file)
index 0000000..d21c8ee
--- /dev/null
@@ -0,0 +1,93 @@
+From f974e397b806f7b16d11cc1542538616291924f1 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 11:57:21 +0200
+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
+results in the amount of data, that DQL says is in the queue incorrect. As
+the data from multiple devices is infact enqueued. This makes any decision
+based on these value non deterministic. Fix this by tracking all TX
+traffic, regardless of the MAC it belongs to in the DQL of all devices
+using the DMA.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 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
+@@ -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)));
+-      netdev_sent_queue(dev, skb->len);
++      /* we have a single DMA ring so BQL needs to be updated for all devices
++       * sitting on this ring
++       */
++      for (i = 0; i < MTK_MAC_COUNT; i++) {
++              if (!eth->netdev[i])
++                      continue;
++
++              netdev_sent_queue(eth->netdev[i], skb->len);
++      }
++
+       skb_tx_timestamp(skb);
+       ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+@@ -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;
+-      unsigned int done[MTK_MAX_DEVS];
+-      unsigned int bytes[MTK_MAX_DEVS];
++      int total = 0, done = 0;
++      unsigned int bytes = 0;
+       u32 cpu, dma;
+       static int condition;
+-      int total = 0, i;
+-
+-      memset(done, 0, sizeof(done));
+-      memset(bytes, 0, sizeof(bytes));
++      int i;
+       cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
+       dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+       desc = mtk_qdma_phys_to_virt(ring, cpu);
+-      while ((cpu != dma) && budget) {
++      while ((cpu != dma) && done < budget) {
+               u32 next_cpu = desc->txd2;
+               int mac = 0;
+@@ -1035,9 +1041,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+               }
+               if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+-                      bytes[mac] += skb->len;
+-                      done[mac]++;
+-                      budget--;
++                      bytes += skb->len;
++                      done++;
+               }
+               mtk_tx_unmap(eth, tx_buf);
+@@ -1049,11 +1054,13 @@ static int mtk_poll_tx(struct mtk_eth *e
+       mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
++      /* we have a single DMA ring so BQL needs to be updated for all devices
++       * sitting on this ring
++       */
+       for (i = 0; i < MTK_MAC_COUNT; i++) {
+-              if (!eth->netdev[i] || !done[i])
++              if (!eth->netdev[i])
+                       continue;
+-              netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+-              total += done[i];
++              netdev_completed_queue(eth->netdev[i], done, bytes);
+       }
+       if (mtk_queue_stopped(eth) &&
diff --git a/target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch b/target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch
new file mode 100644 (file)
index 0000000..2ba1cb8
--- /dev/null
@@ -0,0 +1,192 @@
+From 5c01c03920c63630864d2b8641924a8c7c6cb62f Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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.
+The tag is being added after the source MAC address in the ethernet
+header.
+
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ include/net/dsa.h  |   1 +
+ net/dsa/Kconfig    |   2 +
+ net/dsa/Makefile   |   1 +
+ net/dsa/dsa.c      |   3 ++
+ net/dsa/dsa_priv.h |   3 ++
+ net/dsa/tag_mtk.c  | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 127 insertions(+)
+ create mode 100644 net/dsa/tag_mtk.c
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -27,6 +27,7 @@ enum dsa_tag_protocol {
+       DSA_TAG_PROTO_EDSA,
+       DSA_TAG_PROTO_BRCM,
+       DSA_TAG_PROTO_QCA,
++      DSA_TAG_PROTO_MTK,
+       DSA_TAG_LAST,           /* MUST BE LAST */
+ };
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -41,4 +41,6 @@ config NET_DSA_TAG_TRAILER
+ config NET_DSA_TAG_QCA
+       bool
++config NET_DSA_TAG_MTK
++      bool
+ endif
+--- a/net/dsa/Makefile
++++ b/net/dsa/Makefile
+@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += ta
+ dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
+ dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+ dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
++dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
+--- a/net/dsa/dsa.c
++++ b/net/dsa/dsa.c
+@@ -57,6 +57,9 @@ const struct dsa_device_ops *dsa_device_
+ #ifdef CONFIG_NET_DSA_TAG_QCA
+       [DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
+ #endif
++#ifdef CONFIG_NET_DSA_TAG_MTK
++      [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops,
++#endif
+       [DSA_TAG_PROTO_NONE] = &none_ops,
+ };
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -84,4 +84,7 @@ extern const struct dsa_device_ops brcm_
+ /* tag_qca.c */
+ extern const struct dsa_device_ops qca_netdev_ops;
++/* tag_mtk.c */
++extern const struct dsa_device_ops mtk_netdev_ops;
++
+ #endif
+--- /dev/null
++++ b/net/dsa/tag_mtk.c
+@@ -0,0 +1,117 @@
++/*
++ * Mediatek DSA Tag support
++ * Copyright (C) 2017 Landen Chao <landen.chao@mediatek.com>
++ *                  Sean Wang <sean.wang@mediatek.com>
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/etherdevice.h>
++#include "dsa_priv.h"
++
++#define MTK_HDR_LEN           4
++#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
++#define MTK_HDR_XMIT_DP_BIT_MASK      GENMASK(5, 0)
++
++static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
++                                  struct net_device *dev)
++{
++      struct dsa_slave_priv *p = netdev_priv(dev);
++      u8 *mtk_tag;
++
++      if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
++              goto out_free;
++
++      skb_push(skb, MTK_HDR_LEN);
++
++      memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
++
++      /* Build the tag after the MAC Source Address */
++      mtk_tag = skb->data + 2 * ETH_ALEN;
++      mtk_tag[0] = 0;
++      mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
++      mtk_tag[2] = 0;
++      mtk_tag[3] = 0;
++
++      return skb;
++
++out_free:
++      kfree_skb(skb);
++      return NULL;
++}
++
++static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
++                     struct packet_type *pt, struct net_device *orig_dev)
++{
++      struct dsa_switch_tree *dst = dev->dsa_ptr;
++      struct dsa_switch *ds;
++      int port;
++      __be16 *phdr, hdr;
++
++      if (unlikely(!dst))
++              goto out_drop;
++
++      skb = skb_unshare(skb, GFP_ATOMIC);
++      if (!skb)
++              goto out;
++
++      if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
++              goto out_drop;
++
++      /* The MTK header is added by the switch between src addr
++       * and ethertype at this point, skb->data points to 2 bytes
++       * after src addr so header should be 2 bytes right before.
++       */
++      phdr = (__be16 *)(skb->data - 2);
++      hdr = ntohs(*phdr);
++
++      /* Remove MTK tag and recalculate checksum. */
++      skb_pull_rcsum(skb, MTK_HDR_LEN);
++
++      memmove(skb->data - ETH_HLEN,
++              skb->data - ETH_HLEN - MTK_HDR_LEN,
++              2 * ETH_ALEN);
++
++      /* This protocol doesn't support cascading multiple
++       * switches so it's safe to assume the switch is first
++       * in the tree.
++       */
++      ds = dst->ds[0];
++      if (!ds)
++              goto out_drop;
++
++      /* Get source port information */
++      port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
++      if (!ds->ports[port].netdev)
++              goto out_drop;
++
++      /* Update skb & forward the frame accordingly */
++      skb_push(skb, ETH_HLEN);
++
++      skb->pkt_type = PACKET_HOST;
++      skb->dev = ds->ports[port].netdev;
++      skb->protocol = eth_type_trans(skb, skb->dev);
++
++      skb->dev->stats.rx_packets++;
++      skb->dev->stats.rx_bytes += skb->len;
++
++      netif_receive_skb(skb);
++
++      return 0;
++
++out_drop:
++      kfree_skb(skb);
++out:
++      return 0;
++}
++
++const struct dsa_device_ops mtk_netdev_ops = {
++      .xmit   = mtk_tag_xmit,
++      .rcv    = mtk_tag_rcv,
++};
diff --git a/target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch b/target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch
new file mode 100644 (file)
index 0000000..5c7e6e4
--- /dev/null
@@ -0,0 +1,48 @@
+From de3c04b820e1d396bf12e88ea87271a84f6fedb7 Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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
+handled incorrectly by CDM. The setup is also working out for general
+untag packets as well.
+
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -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.
++       */
++      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);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -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
++#define MTK_CDMQ_STAG_EN      BIT(0)
++
+ /* CDMP Exgress Control Register */
+ #define MTK_CDMP_EG_CTRL      0x404
diff --git a/target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch b/target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch
new file mode 100644 (file)
index 0000000..47a0683
--- /dev/null
@@ -0,0 +1,1584 @@
+From 6a0a62dec3c582db4260f411294770448efc3d6c Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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
+includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY.
+Among these ports, The port from 0 to 4 are the user ports connecting
+with the remote devices while the port 5 and 6 are the CPU ports
+connecting into Mediatek Ethernet GMAC.
+
+For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC
+through either the TRGMII or RGMII which could be controlled by phy-mode
+in the dt-bindings to specify which mode is preferred to use. And for
+port 5, only RGMII can be specified. However, currently, only port 6 is
+being supported in this DSA driver.
+
+The driver is made with the reference to qca8k and other existing DSA
+driver. The most of the essential callbacks of the DSA are already
+support in the driver, including tag insert for user port distinguishing,
+port control, bridge offloading, STP setup and ethtool operation to allow
+DSA to model each user port into a standalone netdevice as the other DSA
+driver had done.
+
+Signed-off-by: Sean Wang <sean.wang@mediatek.com>
+Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
+---
+ drivers/net/dsa/Kconfig  |    8 +
+ drivers/net/dsa/Makefile |    2 +-
+ drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/dsa/mt7530.h |  390 ++++++++++++++++
+ 4 files changed, 1525 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/dsa/mt7530.c
+ create mode 100644 drivers/net/dsa/mt7530.h
+
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -34,4 +34,12 @@ config NET_DSA_QCA8K
+         This enables support for the Qualcomm Atheros QCA8K Ethernet
+         switch chips.
++config NET_DSA_MT7530
++      tristate "Mediatek MT7530 Ethernet switch support"
++      depends on NET_DSA
++      select NET_DSA_TAG_MTK
++      ---help---
++        This enables support for the Mediatek MT7530 Ethernet switch
++        chip.
++
+ endmenu
+--- a/drivers/net/dsa/Makefile
++++ b/drivers/net/dsa/Makefile
+@@ -1,6 +1,6 @@
+ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
+ obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
+ obj-$(CONFIG_NET_DSA_QCA8K)   += qca8k.o
+-
++obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
+ obj-y                         += b53/
+ obj-y                         += mv88e6xxx/
+--- /dev/null
++++ b/drivers/net/dsa/mt7530.c
+@@ -0,0 +1,1126 @@
++/*
++ * Mediatek MT7530 DSA Switch driver
++ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#include <linux/etherdevice.h>
++#include <linux/if_bridge.h>
++#include <linux/iopoll.h>
++#include <linux/mdio.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/of_gpio.h>
++#include <linux/of_mdio.h>
++#include <linux/of_net.h>
++#include <linux/of_platform.h>
++#include <linux/phy.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <linux/reset.h>
++#include <net/dsa.h>
++#include <net/switchdev.h>
++
++#include "mt7530.h"
++
++/* String, offset, and register size in bytes if different from 4 bytes */
++static const struct mt7530_mib_desc mt7530_mib[] = {
++      MIB_DESC(1, 0x00, "TxDrop"),
++      MIB_DESC(1, 0x04, "TxCrcErr"),
++      MIB_DESC(1, 0x08, "TxUnicast"),
++      MIB_DESC(1, 0x0c, "TxMulticast"),
++      MIB_DESC(1, 0x10, "TxBroadcast"),
++      MIB_DESC(1, 0x14, "TxCollision"),
++      MIB_DESC(1, 0x18, "TxSingleCollision"),
++      MIB_DESC(1, 0x1c, "TxMultipleCollision"),
++      MIB_DESC(1, 0x20, "TxDeferred"),
++      MIB_DESC(1, 0x24, "TxLateCollision"),
++      MIB_DESC(1, 0x28, "TxExcessiveCollistion"),
++      MIB_DESC(1, 0x2c, "TxPause"),
++      MIB_DESC(1, 0x30, "TxPktSz64"),
++      MIB_DESC(1, 0x34, "TxPktSz65To127"),
++      MIB_DESC(1, 0x38, "TxPktSz128To255"),
++      MIB_DESC(1, 0x3c, "TxPktSz256To511"),
++      MIB_DESC(1, 0x40, "TxPktSz512To1023"),
++      MIB_DESC(1, 0x44, "Tx1024ToMax"),
++      MIB_DESC(2, 0x48, "TxBytes"),
++      MIB_DESC(1, 0x60, "RxDrop"),
++      MIB_DESC(1, 0x64, "RxFiltering"),
++      MIB_DESC(1, 0x6c, "RxMulticast"),
++      MIB_DESC(1, 0x70, "RxBroadcast"),
++      MIB_DESC(1, 0x74, "RxAlignErr"),
++      MIB_DESC(1, 0x78, "RxCrcErr"),
++      MIB_DESC(1, 0x7c, "RxUnderSizeErr"),
++      MIB_DESC(1, 0x80, "RxFragErr"),
++      MIB_DESC(1, 0x84, "RxOverSzErr"),
++      MIB_DESC(1, 0x88, "RxJabberErr"),
++      MIB_DESC(1, 0x8c, "RxPause"),
++      MIB_DESC(1, 0x90, "RxPktSz64"),
++      MIB_DESC(1, 0x94, "RxPktSz65To127"),
++      MIB_DESC(1, 0x98, "RxPktSz128To255"),
++      MIB_DESC(1, 0x9c, "RxPktSz256To511"),
++      MIB_DESC(1, 0xa0, "RxPktSz512To1023"),
++      MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"),
++      MIB_DESC(2, 0xa8, "RxBytes"),
++      MIB_DESC(1, 0xb0, "RxCtrlDrop"),
++      MIB_DESC(1, 0xb4, "RxIngressDrop"),
++      MIB_DESC(1, 0xb8, "RxArlDrop"),
++};
++
++static struct mt7530_priv *lpriv;
++static void mt7530_port_disable(struct dsa_switch *ds, int port,
++                              struct phy_device *phy);
++static int mt7530_cpu_port_enable(struct mt7530_priv *priv,
++                                int port);
++
++static int
++mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
++{
++      int ret;
++
++      ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
++      if (ret < 0)
++              dev_err(priv->dev,
++                      "failed to priv write register\n");
++      return ret;
++}
++
++static u32
++mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
++{
++      int ret;
++      u32 val;
++
++      ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
++      if (ret < 0) {
++              dev_err(priv->dev,
++                      "failed to priv read register\n");
++              return ret;
++      }
++
++      return val;
++}
++
++static void
++mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
++                u32 mask, u32 set)
++{
++      u32 val;
++
++      val = mt7623_trgmii_read(priv, reg);
++      val &= ~mask;
++      val |= set;
++      mt7623_trgmii_write(priv, reg, val);
++}
++
++static void
++mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      mt7623_trgmii_rmw(priv, reg, 0, val);
++}
++
++static void
++mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      mt7623_trgmii_rmw(priv, reg, val, 0);
++}
++
++static int
++core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
++{
++      struct mii_bus *bus = priv->bus;
++      int value, ret;
++
++      /* Write the desired MMD Devad */
++      ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++      if (ret < 0)
++              goto err;
++
++      /* Write the desired MMD register address */
++      ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++      if (ret < 0)
++              goto err;
++
++      /* Select the Function : DATA with no post increment */
++      ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++      if (ret < 0)
++              goto err;
++
++      /* Read the content of the MMD's selected register */
++      value = bus->read(bus, 0, MII_MMD_DATA);
++
++      return value;
++err:
++      dev_err(&bus->dev,  "failed to read mmd register\n");
++
++      return ret;
++}
++
++static int
++core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
++                      int devad, u32 data)
++{
++      struct mii_bus *bus = priv->bus;
++      int ret;
++
++      /* Write the desired MMD Devad */
++      ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++      if (ret < 0)
++              goto err;
++
++      /* Write the desired MMD register address */
++      ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++      if (ret < 0)
++              goto err;
++
++      /* Select the Function : DATA with no post increment */
++      ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++      if (ret < 0)
++              goto err;
++
++      /* Write the data into MMD's selected register */
++      ret = bus->write(bus, 0, MII_MMD_DATA, data);
++err:
++      if (ret < 0)
++              dev_err(&bus->dev,
++                      "failed to write mmd register\n");
++      return ret;
++}
++
++static void
++core_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      struct mii_bus *bus = priv->bus;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++      core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
++
++      mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
++{
++      struct mii_bus *bus = priv->bus;
++      u32 val;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++      val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
++      val &= ~mask;
++      val |= set;
++      core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
++
++      mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++core_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      core_rmw(priv, reg, 0, val);
++}
++
++static void
++core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      core_rmw(priv, reg, val, 0);
++}
++
++static int
++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      struct mii_bus *bus = priv->bus;
++      u16 page, r, lo, hi;
++      int ret;
++
++      page = (reg >> 6) & 0x3ff;
++      r  = (reg >> 2) & 0xf;
++      lo = val & 0xffff;
++      hi = val >> 16;
++
++      /* MT7530 uses 31 as the pseudo port */
++      ret = bus->write(bus, 0x1f, 0x1f, page);
++      if (ret < 0)
++              goto err;
++
++      ret = bus->write(bus, 0x1f, r,  lo);
++      if (ret < 0)
++              goto err;
++
++      ret = bus->write(bus, 0x1f, 0x10, hi);
++err:
++      if (ret < 0)
++              dev_err(&bus->dev,
++                      "failed to write mt7530 register\n");
++      return ret;
++}
++
++static u32
++mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
++{
++      struct mii_bus *bus = priv->bus;
++      u16 page, r, lo, hi;
++      int ret;
++
++      page = (reg >> 6) & 0x3ff;
++      r = (reg >> 2) & 0xf;
++
++      /* MT7530 uses 31 as the pseudo port */
++      ret = bus->write(bus, 0x1f, 0x1f, page);
++      if (ret < 0) {
++              dev_err(&bus->dev,
++                      "failed to read mt7530 register\n");
++              return ret;
++      }
++
++      lo = bus->read(bus, 0x1f, r);
++      hi = bus->read(bus, 0x1f, 0x10);
++
++      return (hi << 16) | (lo & 0xffff);
++}
++
++static void
++mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      struct mii_bus *bus = priv->bus;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++      mt7530_mii_write(priv, reg, val);
++
++      mutex_unlock(&bus->mdio_lock);
++}
++
++static u32
++_mt7530_read(u32 reg)
++{
++      struct mt7530_priv      *priv = lpriv;
++      struct mii_bus          *bus = priv->bus;
++      u32 val;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++      val = mt7530_mii_read(priv, reg);
++
++      mutex_unlock(&bus->mdio_lock);
++
++      return val;
++}
++
++static u32
++mt7530_read(struct mt7530_priv *priv, u32 reg)
++{
++      return _mt7530_read(reg);
++}
++
++static void
++mt7530_rmw(struct mt7530_priv *priv, u32 reg,
++         u32 mask, u32 set)
++{
++      struct mii_bus *bus = priv->bus;
++      u32 val;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++      val = mt7530_mii_read(priv, reg);
++      val &= ~mask;
++      val |= set;
++      mt7530_mii_write(priv, reg, val);
++
++      mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      mt7530_rmw(priv, reg, 0, val);
++}
++
++static void
++mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++      mt7530_rmw(priv, reg, val, 0);
++}
++
++static int
++mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
++{
++      u32 val;
++      int ret;
++
++      /* Set the command operating upon the MAC address entries */
++      val = ATC_BUSY | ATC_MAT(0) | cmd;
++      mt7530_write(priv, MT7530_ATC, val);
++
++      ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val,
++                               !(val & ATC_BUSY), 20, 20000);
++      if (ret < 0) {
++              dev_err(priv->dev, "reset timeout\n");
++              return ret;
++      }
++
++      /* Additional sanity for read command if the specified
++       * entry is invalid
++       */
++      val = mt7530_read(priv, MT7530_ATC);
++      if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
++              return -EINVAL;
++
++      if (rsp)
++              *rsp = val;
++
++      return 0;
++}
++
++static void
++mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
++{
++      u32 reg[3];
++      int i;
++
++      /* Read from ARL table into an array */
++      for (i = 0; i < 3; i++) {
++              reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4));
++
++              dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n",
++                      __func__, __LINE__, i, reg[i]);
++      }
++
++      fdb->vid = (reg[1] >> CVID) & CVID_MASK;
++      fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK;
++      fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK;
++      fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK;
++      fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK;
++      fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK;
++      fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK;
++      fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK;
++      fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK;
++      fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT;
++}
++
++static void
++mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
++               u8 port_mask, const u8 *mac,
++               u8 aging, u8 type)
++{
++      u32 reg[3] = { 0 };
++      int i;
++
++      reg[1] |= vid & CVID_MASK;
++      reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER;
++      reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP;
++      /* STATIC_ENT indicate that entry is static wouldn't
++       * be aged out and STATIC_EMP specified as erasing an
++       * entry
++       */
++      reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS;
++      reg[1] |= mac[5] << MAC_BYTE_5;
++      reg[1] |= mac[4] << MAC_BYTE_4;
++      reg[0] |= mac[3] << MAC_BYTE_3;
++      reg[0] |= mac[2] << MAC_BYTE_2;
++      reg[0] |= mac[1] << MAC_BYTE_1;
++      reg[0] |= mac[0] << MAC_BYTE_0;
++
++      /* Write array into the ARL table */
++      for (i = 0; i < 3; i++)
++              mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
++}
++
++static int
++mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
++{
++      struct mt7530_priv *priv = ds->priv;
++      u32 ncpo1, ssc_delta, trgint, i;
++
++      switch (mode) {
++      case PHY_INTERFACE_MODE_RGMII:
++              trgint = 0;
++              ncpo1 = 0x0c80;
++              ssc_delta = 0x87;
++              break;
++      case PHY_INTERFACE_MODE_TRGMII:
++              trgint = 1;
++              ncpo1 = 0x1400;
++              ssc_delta = 0x57;
++              break;
++      default:
++              dev_err(priv->dev, "xMII mode %d not supported\n", mode);
++              return -EINVAL;
++      }
++
++      mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
++                 P6_INTF_MODE(trgint));
++
++      /* Lower Tx Driving for TRGMII path */
++      for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
++              mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
++                           TD_DM_DRVP(8) | TD_DM_DRVN(8));
++
++      /* Setup core clock for MT7530 */
++      if (!trgint) {
++              /* Disable MT7530 core clock */
++              core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++
++              /* Disable PLL, since phy_device has not yet been created
++               * provided for phy_[read,write]_mmd_indirect is called, we
++               * provide our own core_write_mmd_indirect to complete this
++               * function.
++               */
++              core_write_mmd_indirect(priv,
++                                      CORE_GSWPLL_GRP1,
++                                      MDIO_MMD_VEND2,
++                                      0);
++
++              /* Set core clock into 500Mhz */
++              core_write(priv, CORE_GSWPLL_GRP2,
++                         RG_GSWPLL_POSDIV_500M(1) |
++                         RG_GSWPLL_FBKDIV_500M(25));
++
++              /* Enable PLL */
++              core_write(priv, CORE_GSWPLL_GRP1,
++                         RG_GSWPLL_EN_PRE |
++                         RG_GSWPLL_POSDIV_200M(2) |
++                         RG_GSWPLL_FBKDIV_200M(32));
++
++              /* Enable MT7530 core clock */
++              core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++      }
++
++      /* Setup the MT7530 TRGMII Tx Clock */
++      core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
++      core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
++      core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
++      core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
++      core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
++      core_write(priv, CORE_PLL_GROUP4,
++                 RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
++                 RG_SYSPLL_BIAS_LPF_EN);
++      core_write(priv, CORE_PLL_GROUP2,
++                 RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
++                 RG_SYSPLL_POSDIV(1));
++      core_write(priv, CORE_PLL_GROUP7,
++                 RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
++                 RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
++      core_set(priv, CORE_TRGMII_GSW_CLK_CG,
++               REG_GSWCK_EN | REG_TRGMIICK_EN);
++
++      if (!trgint)
++              for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++                      mt7530_rmw(priv, MT7530_TRGMII_RD(i),
++                                 RD_TAP_MASK, RD_TAP(16));
++      else
++              mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
++
++      return 0;
++}
++
++static int
++mt7623_pad_clk_setup(struct dsa_switch *ds)
++{
++      struct mt7530_priv *priv = ds->priv;
++      int i;
++
++      for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
++              mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
++                                  TD_DM_DRVP(8) | TD_DM_DRVN(8));
++
++      mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
++      mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
++
++      return 0;
++}
++
++static void
++mt7530_mib_reset(struct dsa_switch *ds)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH);
++      mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
++}
++
++static void
++mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
++{
++      u32 mask = PMCR_TX_EN | PMCR_RX_EN;
++
++      if (enable)
++              mt7530_set(priv, MT7530_PMCR_P(port), mask);
++      else
++              mt7530_clear(priv, MT7530_PMCR_P(port), mask);
++}
++
++static int
++mt7530_setup(struct dsa_switch *ds)
++{
++      struct mt7530_priv *priv = ds->priv;
++      int ret, i;
++      u32 id, val;
++      struct device_node *dn;
++
++      /* The parent node of master_netdev which holds the common system
++       * controller also is the container for two GMACs nodes representing
++       * as two netdev instances.
++       */
++      dn = ds->master_netdev->dev.of_node->parent;
++      priv->ethernet = syscon_node_to_regmap(dn);
++      if (IS_ERR(priv->ethernet))
++              return PTR_ERR(priv->ethernet);
++
++      regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
++      ret = regulator_enable(priv->core_pwr);
++      if (ret < 0) {
++              dev_err(priv->dev,
++                      "Failed to enable core power: %d\n", ret);
++              return ret;
++      }
++
++      regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
++      ret = regulator_enable(priv->io_pwr);
++      if (ret < 0) {
++              dev_err(priv->dev, "Failed to enable io pwr: %d\n",
++                      ret);
++              return ret;
++      }
++
++      /* Reset whole chip through gpio pin or memory-mapped registers for
++       * different type of hardware
++       */
++      if (priv->mcm) {
++              reset_control_assert(priv->rstc);
++              usleep_range(1000, 1100);
++              reset_control_deassert(priv->rstc);
++      } else {
++              gpiod_set_value_cansleep(priv->reset, 0);
++              usleep_range(1000, 1100);
++              gpiod_set_value_cansleep(priv->reset, 1);
++      }
++
++      /* Waiting for MT7530 got to stable */
++      ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0,
++                               20, 1000000);
++      if (ret < 0) {
++              dev_err(priv->dev, "reset timeout\n");
++              return ret;
++      }
++
++      id = mt7530_read(priv, MT7530_CREV);
++      id >>= CHIP_NAME_SHIFT;
++      if (id != MT7530_ID) {
++              dev_err(priv->dev, "chip %x can't be supported\n", id);
++              return -ENODEV;
++      }
++
++      /* Reset the switch through internal reset */
++      mt7530_write(priv, MT7530_SYS_CTRL,
++                   SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
++                   SYS_CTRL_REG_RST);
++
++      /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
++      val = mt7530_read(priv, MT7530_MHWTRAP);
++      val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
++      val |= MHWTRAP_MANUAL;
++      mt7530_write(priv, MT7530_MHWTRAP, val);
++
++      /* Enable and reset MIB counters */
++      mt7530_mib_reset(ds);
++
++      mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
++
++      for (i = 0; i < MT7530_NUM_PORTS; i++) {
++              /* Disable forwarding by default on all ports */
++              mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
++                         PCR_MATRIX_CLR);
++
++              if (dsa_is_cpu_port(ds, i))
++                      mt7530_cpu_port_enable(priv, i);
++              else
++                      mt7530_port_disable(ds, i, NULL);
++      }
++
++      /* Flush the FDB table */
++      ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
++      if (ret < 0)
++              return ret;
++
++      return 0;
++}
++
++static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      return mdiobus_read_nested(priv->bus, port, regnum);
++}
++
++int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      return mdiobus_write_nested(priv->bus, port, regnum, val);
++}
++
++static void
++mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
++              strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name,
++                      ETH_GSTRING_LEN);
++}
++
++static void
++mt7530_get_ethtool_stats(struct dsa_switch *ds, int port,
++                       uint64_t *data)
++{
++      struct mt7530_priv *priv = ds->priv;
++      const struct mt7530_mib_desc *mib;
++      u32 reg, i;
++      u64 hi;
++
++      for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) {
++              mib = &mt7530_mib[i];
++              reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset;
++
++              data[i] = mt7530_read(priv, reg);
++              if (mib->size == 2) {
++                      hi = mt7530_read(priv, reg + 4);
++                      data[i] |= hi << 32;
++              }
++      }
++}
++
++static int
++mt7530_get_sset_count(struct dsa_switch *ds)
++{
++      return ARRAY_SIZE(mt7530_mib);
++}
++
++static void mt7530_adjust_link(struct dsa_switch *ds, int port,
++                             struct phy_device *phydev)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      if (phy_is_pseudo_fixed_link(phydev)) {
++              dev_dbg(priv->dev, "phy-mode for master device = %x\n",
++                      phydev->interface);
++
++              /* Setup TX circuit incluing relevant PAD and driving */
++              mt7530_pad_clk_setup(ds, phydev->interface);
++
++              /* Setup RX circuit, relevant PAD and driving on the host
++               * which must be placed after the setup on the device side is
++               * all finished.
++               */
++              mt7623_pad_clk_setup(ds);
++      }
++}
++
++static int
++mt7530_cpu_port_enable(struct mt7530_priv *priv,
++                     int port)
++{
++      /* Enable Mediatek header mode on the cpu port */
++      mt7530_write(priv, MT7530_PVC_P(port),
++                   PORT_SPEC_TAG);
++
++      /* Setup the MAC by default for the cpu port */
++      mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK);
++
++      /* Disable auto learning on the cpu port */
++      mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
++
++      /* Unknown unicast frame fordwarding to the cpu port */
++      mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
++
++      /* CPU port gets connected to all user ports of
++       * the switch
++       */
++      mt7530_write(priv, MT7530_PCR_P(port),
++                   PCR_MATRIX(priv->ds->enabled_port_mask));
++
++      return 0;
++}
++
++static int
++mt7530_port_enable(struct dsa_switch *ds, int port,
++                 struct phy_device *phy)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      mutex_lock(&priv->reg_mutex);
++
++      /* Setup the MAC for the user port */
++      mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK);
++
++      /* Allow the user port gets connected to the cpu port and also
++       * restore the port matrix if the port is the member of a certain
++       * bridge.
++       */
++      priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
++      priv->ports[port].enable = true;
++      mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++                 priv->ports[port].pm);
++      mt7530_port_set_status(priv, port, 1);
++
++      mutex_unlock(&priv->reg_mutex);
++
++      return 0;
++}
++
++static void
++mt7530_port_disable(struct dsa_switch *ds, int port,
++                  struct phy_device *phy)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      mutex_lock(&priv->reg_mutex);
++
++      /* Clear up all port matrix which could be restored in the next
++       * enablement for the port.
++       */
++      priv->ports[port].enable = false;
++      mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++                 PCR_MATRIX_CLR);
++      mt7530_port_set_status(priv, port, 0);
++
++      mutex_unlock(&priv->reg_mutex);
++}
++
++static void
++mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
++{
++      struct mt7530_priv *priv = ds->priv;
++      u32 stp_state;
++
++      switch (state) {
++      case BR_STATE_DISABLED:
++              stp_state = MT7530_STP_DISABLED;
++              break;
++      case BR_STATE_BLOCKING:
++              stp_state = MT7530_STP_BLOCKING;
++              break;
++      case BR_STATE_LISTENING:
++              stp_state = MT7530_STP_LISTENING;
++              break;
++      case BR_STATE_LEARNING:
++              stp_state = MT7530_STP_LEARNING;
++              break;
++      case BR_STATE_FORWARDING:
++      default:
++              stp_state = MT7530_STP_FORWARDING;
++              break;
++      }
++
++      mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state);
++}
++
++static int
++mt7530_port_bridge_join(struct dsa_switch *ds, int port,
++                      struct net_device *bridge)
++{
++      struct mt7530_priv *priv = ds->priv;
++      u32 port_bitmap = BIT(MT7530_CPU_PORT);
++      int i;
++
++      mutex_lock(&priv->reg_mutex);
++
++      for (i = 0; i < MT7530_NUM_PORTS; i++) {
++              /* Add this port to the port matrix of the other ports in the
++               * same bridge. If the port is disabled, port matrix is kept
++               * and not being setup until the port becomes enabled.
++               */
++              if (ds->enabled_port_mask & BIT(i) && i != port) {
++                      if (ds->ports[i].bridge_dev != bridge)
++                              continue;
++                      if (priv->ports[i].enable)
++                              mt7530_set(priv, MT7530_PCR_P(i),
++                                         PCR_MATRIX(BIT(port)));
++                      priv->ports[i].pm |= PCR_MATRIX(BIT(port));
++
++                      port_bitmap |= BIT(i);
++              }
++      }
++
++      /* Add the all other ports to this port matrix. */
++      if (priv->ports[port].enable)
++              mt7530_rmw(priv, MT7530_PCR_P(port),
++                         PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap));
++      priv->ports[port].pm |= PCR_MATRIX(port_bitmap);
++
++      mutex_unlock(&priv->reg_mutex);
++
++      return 0;
++}
++
++static void
++mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
++                       struct net_device *bridge)
++{
++      struct mt7530_priv *priv = ds->priv;
++      int i;
++
++      mutex_lock(&priv->reg_mutex);
++
++      for (i = 0; i < MT7530_NUM_PORTS; i++) {
++              /* Remove this port from the port matrix of the other ports
++               * in the same bridge. If the port is disabled, port matrix
++               * is kept and not being setup until the port becomes enabled.
++               */
++              if (ds->enabled_port_mask & BIT(i) && i != port) {
++                      if (ds->ports[i].bridge_dev != bridge)
++                              continue;
++                      if (priv->ports[i].enable)
++                              mt7530_clear(priv, MT7530_PCR_P(i),
++                                           PCR_MATRIX(BIT(port)));
++                      priv->ports[i].pm &= ~PCR_MATRIX(BIT(port));
++              }
++      }
++
++      /* Set the cpu port to be the only one in the port matrix of
++       * this port.
++       */
++      if (priv->ports[port].enable)
++              mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
++                         PCR_MATRIX(BIT(MT7530_CPU_PORT)));
++      priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
++
++      mutex_unlock(&priv->reg_mutex);
++}
++
++static int
++mt7530_port_fdb_prepare(struct dsa_switch *ds, int port,
++                      const struct switchdev_obj_port_fdb *fdb,
++                      struct switchdev_trans *trans)
++{
++      struct mt7530_priv *priv = ds->priv;
++      int ret;
++
++      /* Because auto-learned entrie shares the same FDB table.
++       * an entry is reserved with no port_mask to make sure fdb_add
++       * is called while the entry is still available.
++       */
++      mutex_lock(&priv->reg_mutex);
++      mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT);
++      ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++      mutex_unlock(&priv->reg_mutex);
++
++      return ret;
++}
++
++static void
++mt7530_port_fdb_add(struct dsa_switch *ds, int port,
++                  const struct switchdev_obj_port_fdb *fdb,
++                  struct switchdev_trans *trans)
++{
++      struct mt7530_priv *priv = ds->priv;
++      u8 port_mask = BIT(port);
++
++      mutex_lock(&priv->reg_mutex);
++      mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT);
++      mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++      mutex_unlock(&priv->reg_mutex);
++}
++
++static int
++mt7530_port_fdb_del(struct dsa_switch *ds, int port,
++                  const struct switchdev_obj_port_fdb *fdb)
++{
++      struct mt7530_priv *priv = ds->priv;
++      int ret;
++      u8 port_mask = BIT(port);
++
++      mutex_lock(&priv->reg_mutex);
++      mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP);
++      ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
++      mutex_unlock(&priv->reg_mutex);
++
++      return ret;
++}
++
++static int
++mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
++                   struct switchdev_obj_port_fdb *fdb,
++                   int (*cb)(struct switchdev_obj *obj))
++{
++      struct mt7530_priv *priv = ds->priv;
++      struct mt7530_fdb _fdb = { 0 };
++      int cnt = MT7530_NUM_FDB_RECORDS;
++      int ret = 0;
++      u32 rsp = 0;
++
++      mutex_lock(&priv->reg_mutex);
++
++      ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp);
++      if (ret < 0)
++              goto err;
++
++      do {
++              if (rsp & ATC_SRCH_HIT) {
++                      mt7530_fdb_read(priv, &_fdb);
++                      if (_fdb.port_mask & BIT(port)) {
++                              ether_addr_copy(fdb->addr, _fdb.mac);
++                              fdb->vid = _fdb.vid;
++                              fdb->ndm_state = _fdb.noarp ?
++                                              NUD_NOARP : NUD_REACHABLE;
++                              ret = cb(&fdb->obj);
++                              if (ret < 0)
++                                      break;
++                      }
++              }
++      } while (--cnt &&
++               !(rsp & ATC_SRCH_END) &&
++               !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp));
++err:
++      mutex_unlock(&priv->reg_mutex);
++
++      return 0;
++}
++
++static enum dsa_tag_protocol
++mtk_get_tag_protocol(struct dsa_switch *ds)
++{
++      struct mt7530_priv *priv = ds->priv;
++
++      if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
++              dev_warn(priv->dev,
++                       "port not matched with tagging CPU port\n");
++              return DSA_TAG_PROTO_NONE;
++      } else {
++              return DSA_TAG_PROTO_MTK;
++      }
++}
++
++static struct dsa_switch_ops mt7530_switch_ops = {
++      .get_tag_protocol       = mtk_get_tag_protocol,
++      .setup                  = mt7530_setup,
++      .get_strings            = mt7530_get_strings,
++      .phy_read               = mt7530_phy_read,
++      .phy_write              = mt7530_phy_write,
++      .get_ethtool_stats      = mt7530_get_ethtool_stats,
++      .get_sset_count         = mt7530_get_sset_count,
++      .adjust_link            = mt7530_adjust_link,
++      .port_enable            = mt7530_port_enable,
++      .port_disable           = mt7530_port_disable,
++      .port_stp_state_set     = mt7530_stp_state_set,
++      .port_bridge_join       = mt7530_port_bridge_join,
++      .port_bridge_leave      = mt7530_port_bridge_leave,
++      .port_fdb_prepare       = mt7530_port_fdb_prepare,
++      .port_fdb_add           = mt7530_port_fdb_add,
++      .port_fdb_del           = mt7530_port_fdb_del,
++      .port_fdb_dump          = mt7530_port_fdb_dump,
++};
++
++static int
++mt7530_probe(struct mdio_device *mdiodev)
++{
++      struct mt7530_priv *priv;
++      struct device_node *dn;
++
++      dn = mdiodev->dev.of_node;
++
++      priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
++      if (!priv)
++              return -ENOMEM;
++
++      priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
++      if (!priv->ds)
++              return -ENOMEM;
++
++      /* Use medatek,mcm property to distinguish hardware type that would
++       * casues a little bit differences on power-on sequence.
++       */
++      priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
++      if (priv->mcm) {
++              dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
++
++              priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
++              if (IS_ERR(priv->rstc)) {
++                      dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
++                      return PTR_ERR(priv->rstc);
++              }
++      }
++
++      priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
++      if (IS_ERR(priv->core_pwr))
++              return PTR_ERR(priv->core_pwr);
++
++      priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
++      if (IS_ERR(priv->io_pwr))
++              return PTR_ERR(priv->io_pwr);
++
++      /* Not MCM that indicates switch works as the remote standalone
++       * integrated circuit so the GPIO pin would be used to complete
++       * the reset, otherwise memory-mapped register accessing used
++       * through syscon provides in the case of MCM.
++       */
++      if (!priv->mcm) {
++              priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
++                                                    GPIOD_OUT_LOW);
++              if (IS_ERR(priv->reset)) {
++                      dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
++                      return PTR_ERR(priv->reset);
++              }
++      }
++
++      priv->bus = mdiodev->bus;
++      priv->dev = &mdiodev->dev;
++      priv->ds->priv = priv;
++      priv->ds->ops = &mt7530_switch_ops;
++      mutex_init(&priv->reg_mutex);
++      lpriv = priv;
++      dev_set_drvdata(&mdiodev->dev, priv);
++
++      return dsa_register_switch(priv->ds, &mdiodev->dev);
++}
++
++static void
++mt7530_remove(struct mdio_device *mdiodev)
++{
++      struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
++      int ret = 0;
++
++      ret = regulator_disable(priv->core_pwr);
++      if (ret < 0)
++              dev_err(priv->dev,
++                      "Failed to disable core power: %d\n", ret);
++
++      ret = regulator_disable(priv->io_pwr);
++      if (ret < 0)
++              dev_err(priv->dev, "Failed to disable io pwr: %d\n",
++                      ret);
++
++      dsa_unregister_switch(priv->ds);
++      mutex_destroy(&priv->reg_mutex);
++}
++
++static const struct of_device_id mt7530_of_match[] = {
++      { .compatible = "mediatek,mt7530" },
++      { /* sentinel */ },
++};
++
++static struct mdio_driver mt7530_mdio_driver = {
++      .probe  = mt7530_probe,
++      .remove = mt7530_remove,
++      .mdiodrv.driver = {
++              .name = "mt7530",
++              .of_match_table = mt7530_of_match,
++      },
++};
++
++mdio_module_driver(mt7530_mdio_driver);
++
++MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:mediatek-mt7530");
+--- /dev/null
++++ b/drivers/net/dsa/mt7530.h
+@@ -0,0 +1,390 @@
++/*
++ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __MT7530_H
++#define __MT7530_H
++
++#define MT7530_NUM_PORTS              7
++#define MT7530_CPU_PORT                       6
++#define MT7530_NUM_FDB_RECORDS                2048
++
++#define       NUM_TRGMII_CTRL                 5
++
++#define TRGMII_BASE(x)                        (0x10000 + (x))
++
++/* Registers to ethsys access */
++#define ETHSYS_CLKCFG0                        0x2c
++#define  ETHSYS_TRGMII_CLK_SEL362_5   BIT(11)
++
++#define SYSC_REG_RSTCTRL              0x34
++#define  RESET_MCM                    BIT(2)
++
++/* Registers to mac forward control for unknown frames */
++#define MT7530_MFC                    0x10
++#define  BC_FFP(x)                    (((x) & 0xff) << 24)
++#define  UNM_FFP(x)                   (((x) & 0xff) << 16)
++#define  UNU_FFP(x)                   (((x) & 0xff) << 8)
++#define  UNU_FFP_MASK                 UNU_FFP(~0)
++
++/* Registers for address table access */
++#define MT7530_ATA1                   0x74
++#define  STATIC_EMP                   0
++#define  STATIC_ENT                   3
++#define MT7530_ATA2                   0x78
++
++/* Register for address table write data */
++#define MT7530_ATWD                   0x7c
++
++/* Register for address table control */
++#define MT7530_ATC                    0x80
++#define  ATC_HASH                     (((x) & 0xfff) << 16)
++#define  ATC_BUSY                     BIT(15)
++#define  ATC_SRCH_END                 BIT(14)
++#define  ATC_SRCH_HIT                 BIT(13)
++#define  ATC_INVALID                  BIT(12)
++#define  ATC_MAT(x)                   (((x) & 0xf) << 8)
++#define  ATC_MAT_MACTAB                       ATC_MAT(0)
++
++enum mt7530_fdb_cmd {
++      MT7530_FDB_READ = 0,
++      MT7530_FDB_WRITE = 1,
++      MT7530_FDB_FLUSH = 2,
++      MT7530_FDB_START = 4,
++      MT7530_FDB_NEXT = 5,
++};
++
++/* Registers for table search read address */
++#define MT7530_TSRA1                  0x84
++#define  MAC_BYTE_0                   24
++#define  MAC_BYTE_1                   16
++#define  MAC_BYTE_2                   8
++#define  MAC_BYTE_3                   0
++#define  MAC_BYTE_MASK                        0xff
++
++#define MT7530_TSRA2                  0x88
++#define  MAC_BYTE_4                   24
++#define  MAC_BYTE_5                   16
++#define  CVID                         0
++#define  CVID_MASK                    0xfff
++
++#define MT7530_ATRD                   0x8C
++#define        AGE_TIMER                      24
++#define  AGE_TIMER_MASK                       0xff
++#define  PORT_MAP                     4
++#define  PORT_MAP_MASK                        0xff
++#define  ENT_STATUS                   2
++#define  ENT_STATUS_MASK              0x3
++
++/* Register for vlan table control */
++#define MT7530_VTCR                   0x90
++#define  VTCR_BUSY                    BIT(31)
++#define  VTCR_FUNC                    (((x) & 0xf) << 12)
++#define  VTCR_FUNC_RD_VID             0x1
++#define  VTCR_FUNC_WR_VID             0x2
++#define  VTCR_FUNC_INV_VID            0x3
++#define  VTCR_FUNC_VAL_VID            0x4
++#define  VTCR_VID                     ((x) & 0xfff)
++
++/* Register for setup vlan and acl write data */
++#define MT7530_VAWD1                  0x94
++#define  PORT_STAG                    BIT(31)
++#define  IVL_MAC                      BIT(30)
++#define  PORT_MEM(x)                  (((x) & 0xff) << 16)
++#define  VALID                                BIT(1)
++
++#define MT7530_VAWD2                  0x98
++
++/* Register for port STP state control */
++#define MT7530_SSP_P(x)                       (0x2000 + ((x) * 0x100))
++#define  FID_PST(x)                   ((x) & 0x3)
++#define  FID_PST_MASK                 FID_PST(0x3)
++
++enum mt7530_stp_state {
++      MT7530_STP_DISABLED = 0,
++      MT7530_STP_BLOCKING = 1,
++      MT7530_STP_LISTENING = 1,
++      MT7530_STP_LEARNING = 2,
++      MT7530_STP_FORWARDING  = 3
++};
++
++/* Register for port control */
++#define MT7530_PCR_P(x)                       (0x2004 + ((x) * 0x100))
++#define  PORT_VLAN(x)                 ((x) & 0x3)
++#define  PCR_MATRIX(x)                        (((x) & 0xff) << 16)
++#define  PORT_PRI(x)                  (((x) & 0x7) << 24)
++#define  EG_TAG(x)                    (((x) & 0x3) << 28)
++#define  PCR_MATRIX_MASK              PCR_MATRIX(0xff)
++#define  PCR_MATRIX_CLR                       PCR_MATRIX(0)
++
++/* Register for port security control */
++#define MT7530_PSC_P(x)                       (0x200c + ((x) * 0x100))
++#define  SA_DIS                               BIT(4)
++
++/* Register for port vlan control */
++#define MT7530_PVC_P(x)                       (0x2010 + ((x) * 0x100))
++#define  PORT_SPEC_TAG                        BIT(5)
++#define  VLAN_ATTR(x)                 (((x) & 0x3) << 6)
++#define  STAG_VPID                    (((x) & 0xffff) << 16)
++
++/* Register for port port-and-protocol based vlan 1 control */
++#define MT7530_PPBV1_P(x)             (0x2014 + ((x) * 0x100))
++
++/* Register for port MAC control register */
++#define MT7530_PMCR_P(x)              (0x3000 + ((x) * 0x100))
++#define  PMCR_IFG_XMIT(x)             (((x) & 0x3) << 18)
++#define  PMCR_MAC_MODE                        BIT(16)
++#define  PMCR_FORCE_MODE              BIT(15)
++#define  PMCR_TX_EN                   BIT(14)
++#define  PMCR_RX_EN                   BIT(13)
++#define  PMCR_BACKOFF_EN              BIT(9)
++#define  PMCR_BACKPR_EN                       BIT(8)
++#define  PMCR_TX_FC_EN                        BIT(5)
++#define  PMCR_RX_FC_EN                        BIT(4)
++#define  PMCR_FORCE_SPEED_1000                BIT(3)
++#define  PMCR_FORCE_FDX                       BIT(1)
++#define  PMCR_FORCE_LNK                       BIT(0)
++#define  PMCR_COMMON_LINK             (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
++                                       PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
++                                       PMCR_TX_EN | PMCR_RX_EN | \
++                                       PMCR_TX_FC_EN | PMCR_RX_FC_EN)
++#define  PMCR_CPUP_LINK                       (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \
++                                       PMCR_FORCE_SPEED_1000 | \
++                                       PMCR_FORCE_FDX | \
++                                       PMCR_FORCE_LNK)
++#define  PMCR_USERP_LINK              PMCR_COMMON_LINK
++#define  PMCR_FIXED_LINK              (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
++                                       PMCR_FORCE_MODE | PMCR_TX_EN | \
++                                       PMCR_RX_EN | PMCR_BACKPR_EN | \
++                                       PMCR_BACKOFF_EN | \
++                                       PMCR_FORCE_SPEED_1000 | \
++                                       PMCR_FORCE_FDX | \
++                                       PMCR_FORCE_LNK)
++#define PMCR_FIXED_LINK_FC            (PMCR_FIXED_LINK | \
++                                       PMCR_TX_FC_EN | PMCR_RX_FC_EN)
++
++#define MT7530_PMSR_P(x)              (0x3008 + (x) * 0x100)
++
++/* Register for MIB */
++#define MT7530_PORT_MIB_COUNTER(x)    (0x4000 + (x) * 0x100)
++#define MT7530_MIB_CCR                        0x4fe0
++#define  CCR_MIB_ENABLE                       BIT(31)
++#define  CCR_RX_OCT_CNT_GOOD          BIT(7)
++#define  CCR_RX_OCT_CNT_BAD           BIT(6)
++#define  CCR_TX_OCT_CNT_GOOD          BIT(5)
++#define  CCR_TX_OCT_CNT_BAD           BIT(4)
++#define  CCR_MIB_FLUSH                        (CCR_RX_OCT_CNT_GOOD | \
++                                       CCR_RX_OCT_CNT_BAD | \
++                                       CCR_TX_OCT_CNT_GOOD | \
++                                       CCR_TX_OCT_CNT_BAD)
++#define  CCR_MIB_ACTIVATE             (CCR_MIB_ENABLE | \
++                                       CCR_RX_OCT_CNT_GOOD | \
++                                       CCR_RX_OCT_CNT_BAD | \
++                                       CCR_TX_OCT_CNT_GOOD | \
++                                       CCR_TX_OCT_CNT_BAD)
++/* Register for system reset */
++#define MT7530_SYS_CTRL                       0x7000
++#define  SYS_CTRL_PHY_RST             BIT(2)
++#define  SYS_CTRL_SW_RST              BIT(1)
++#define  SYS_CTRL_REG_RST             BIT(0)
++
++/* Register for hw trap status */
++#define MT7530_HWTRAP                 0x7800
++
++/* Register for hw trap modification */
++#define MT7530_MHWTRAP                        0x7804
++#define  MHWTRAP_MANUAL                       BIT(16)
++#define  MHWTRAP_P5_MAC_SEL           BIT(13)
++#define  MHWTRAP_P6_DIS                       BIT(8)
++#define  MHWTRAP_P5_RGMII_MODE                BIT(7)
++#define  MHWTRAP_P5_DIS                       BIT(6)
++#define  MHWTRAP_PHY_ACCESS           BIT(5)
++
++/* Register for TOP signal control */
++#define MT7530_TOP_SIG_CTRL           0x7808
++#define  TOP_SIG_CTRL_NORMAL          (BIT(17) | BIT(16))
++
++#define MT7530_IO_DRV_CR              0x7810
++#define  P5_IO_CLK_DRV(x)             ((x) & 0x3)
++#define  P5_IO_DATA_DRV(x)            (((x) & 0x3) << 4)
++
++#define MT7530_P6ECR                  0x7830
++#define  P6_INTF_MODE_MASK            0x3
++#define  P6_INTF_MODE(x)              ((x) & 0x3)
++
++/* Registers for TRGMII on the both side */
++#define MT7530_TRGMII_RCK_CTRL                0x7a00
++#define GSW_TRGMII_RCK_CTRL           0x300
++#define  RX_RST                               BIT(31)
++#define  RXC_DQSISEL                  BIT(30)
++#define  DQSI1_TAP_MASK                       (0x7f << 8)
++#define  DQSI0_TAP_MASK                       0x7f
++#define  DQSI1_TAP(x)                 (((x) & 0x7f) << 8)
++#define  DQSI0_TAP(x)                 ((x) & 0x7f)
++
++#define MT7530_TRGMII_RCK_RTT         0x7a04
++#define GSW_TRGMII_RCK_RTT            0x304
++#define  DQS1_GATE                    BIT(31)
++#define  DQS0_GATE                    BIT(30)
++
++#define MT7530_TRGMII_RD(x)           (0x7a10 + (x) * 8)
++#define GSW_TRGMII_RD(x)              (0x310 + (x) * 8)
++#define  BSLIP_EN                     BIT(31)
++#define  EDGE_CHK                     BIT(30)
++#define  RD_TAP_MASK                  0x7f
++#define  RD_TAP(x)                    ((x) & 0x7f)
++
++#define GSW_TRGMII_TXCTRL             0x340
++#define MT7530_TRGMII_TXCTRL          0x7a40
++#define  TRAIN_TXEN                   BIT(31)
++#define  TXC_INV                      BIT(30)
++#define  TX_RST                               BIT(28)
++
++#define MT7530_TRGMII_TD_ODT(i)               (0x7a54 + 8 * (i))
++#define GSW_TRGMII_TD_ODT(i)          (0x354 + 8 * (i))
++#define  TD_DM_DRVP(x)                        ((x) & 0xf)
++#define  TD_DM_DRVN(x)                        (((x) & 0xf) << 4)
++
++#define GSW_INTF_MODE                 0x390
++#define  INTF_MODE_TRGMII             BIT(1)
++
++#define MT7530_TRGMII_TCK_CTRL                0x7a78
++#define  TCK_TAP(x)                   (((x) & 0xf) << 8)
++
++#define MT7530_P5RGMIIRXCR            0x7b00
++#define  CSR_RGMII_EDGE_ALIGN         BIT(8)
++#define  CSR_RGMII_RXC_0DEG_CFG(x)    ((x) & 0xf)
++
++#define MT7530_P5RGMIITXCR            0x7b04
++#define  CSR_RGMII_TXC_CFG(x)         ((x) & 0x1f)
++
++#define MT7530_CREV                   0x7ffc
++#define  CHIP_NAME_SHIFT              16
++#define  MT7530_ID                    0x7530
++
++/* Registers for core PLL access through mmd indirect */
++#define CORE_PLL_GROUP2                       0x401
++#define  RG_SYSPLL_EN_NORMAL          BIT(15)
++#define  RG_SYSPLL_VODEN              BIT(14)
++#define  RG_SYSPLL_LF                 BIT(13)
++#define  RG_SYSPLL_RST_DLY(x)         (((x) & 0x3) << 12)
++#define  RG_SYSPLL_LVROD_EN           BIT(10)
++#define  RG_SYSPLL_PREDIV(x)          (((x) & 0x3) << 8)
++#define  RG_SYSPLL_POSDIV(x)          (((x) & 0x3) << 5)
++#define  RG_SYSPLL_FBKSEL             BIT(4)
++#define  RT_SYSPLL_EN_AFE_OLT         BIT(0)
++
++#define CORE_PLL_GROUP4                       0x403
++#define  RG_SYSPLL_DDSFBK_EN          BIT(12)
++#define  RG_SYSPLL_BIAS_EN            BIT(11)
++#define  RG_SYSPLL_BIAS_LPF_EN                BIT(10)
++
++#define CORE_PLL_GROUP5                       0x404
++#define  RG_LCDDS_PCW_NCPO1(x)                ((x) & 0xffff)
++
++#define CORE_PLL_GROUP6                       0x405
++#define  RG_LCDDS_PCW_NCPO0(x)                ((x) & 0xffff)
++
++#define CORE_PLL_GROUP7                       0x406
++#define  RG_LCDDS_PWDB                        BIT(15)
++#define  RG_LCDDS_ISO_EN              BIT(13)
++#define  RG_LCCDS_C(x)                        (((x) & 0x7) << 4)
++#define  RG_LCDDS_PCW_NCPO_CHG                BIT(3)
++
++#define CORE_PLL_GROUP10              0x409
++#define  RG_LCDDS_SSC_DELTA(x)                ((x) & 0xfff)
++
++#define CORE_PLL_GROUP11              0x40a
++#define  RG_LCDDS_SSC_DELTA1(x)               ((x) & 0xfff)
++
++#define CORE_GSWPLL_GRP1              0x40d
++#define  RG_GSWPLL_PREDIV(x)          (((x) & 0x3) << 14)
++#define  RG_GSWPLL_POSDIV_200M(x)     (((x) & 0x3) << 12)
++#define  RG_GSWPLL_EN_PRE             BIT(11)
++#define  RG_GSWPLL_FBKSEL             BIT(10)
++#define  RG_GSWPLL_BP                 BIT(9)
++#define  RG_GSWPLL_BR                 BIT(8)
++#define  RG_GSWPLL_FBKDIV_200M(x)     ((x) & 0xff)
++
++#define CORE_GSWPLL_GRP2              0x40e
++#define  RG_GSWPLL_POSDIV_500M(x)     (((x) & 0x3) << 8)
++#define  RG_GSWPLL_FBKDIV_500M(x)     ((x) & 0xff)
++
++#define CORE_TRGMII_GSW_CLK_CG                0x410
++#define  REG_GSWCK_EN                 BIT(0)
++#define  REG_TRGMIICK_EN              BIT(1)
++
++#define MIB_DESC(_s, _o, _n)  \
++      {                       \
++              .size = (_s),   \
++              .offset = (_o), \
++              .name = (_n),   \
++      }
++
++struct mt7530_mib_desc {
++      unsigned int size;
++      unsigned int offset;
++      const char *name;
++};
++
++struct mt7530_fdb {
++      u16 vid;
++      u8 port_mask;
++      u8 aging;
++      u8 mac[6];
++      bool noarp;
++};
++
++struct mt7530_port {
++      bool enable;
++      u32 pm;
++};
++
++/* struct mt7530_priv -       This is the main data structure for holding the state
++ *                    of the driver
++ * @dev:              The device pointer
++ * @ds:                       The pointer to the dsa core structure
++ * @bus:              The bus used for the device and built-in PHY
++ * @rstc:             The pointer to reset control used by MCM
++ * @ethernet:         The regmap used for access TRGMII-based registers
++ * @core_pwr:         The power supplied into the core
++ * @io_pwr:           The power supplied into the I/O
++ * @reset:            The descriptor for GPIO line tied to its reset pin
++ * @mcm:              Flag for distinguishing if standalone IC or module
++ *                    coupling
++ * @ports:            Holding the state among ports
++ * @reg_mutex:                The lock for protecting among process accessing
++ *                    registers
++ */
++struct mt7530_priv {
++      struct device           *dev;
++      struct dsa_switch       *ds;
++      struct mii_bus          *bus;
++      struct reset_control    *rstc;
++      struct regmap           *ethernet;
++      struct regulator        *core_pwr;
++      struct regulator        *io_pwr;
++      struct gpio_desc        *reset;
++      bool                    mcm;
++
++      struct mt7530_port      ports[MT7530_NUM_PORTS];
++      /* protect among processes for registers access*/
++      struct mutex reg_mutex;
++};
++
++struct mt7530_hw_stats {
++      const char      *string;
++      u16             reg;
++      u8              sizeof_stat;
++};
++
++#endif /* __MT7530_H */
diff --git a/target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch b/target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch
new file mode 100644 (file)
index 0000000..9e52be8
--- /dev/null
@@ -0,0 +1,106 @@
+From a319687ac18dcc557a88054282508e061ad8495f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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
+       int i;
+       mutex_lock(&priv->reg_mutex);
++      priv->bridge_dev[port] = bridge;
+       for (i = 0; i < MT7530_NUM_PORTS; i++) {
+               /* Add this port to the port matrix of the other ports in the
+@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc
+                * and not being setup until the port becomes enabled.
+                */
+               if (ds->enabled_port_mask & BIT(i) && i != port) {
+-                      if (ds->ports[i].bridge_dev != bridge)
++                      if (priv->bridge_dev[i] != bridge)
+                               continue;
+                       if (priv->ports[i].enable)
+                               mt7530_set(priv, MT7530_PCR_P(i),
+@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc
+ }
+ static void
+-mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
+-                       struct net_device *bridge)
++mt7530_port_bridge_leave(struct dsa_switch *ds, int port)
+ {
+       struct mt7530_priv *priv = ds->priv;
+       int i;
+@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit
+                * is kept and not being setup until the port becomes enabled.
+                */
+               if (ds->enabled_port_mask & BIT(i) && i != port) {
+-                      if (ds->ports[i].bridge_dev != bridge)
++                      if (priv->bridge_dev[i] != priv->bridge_dev[port])
+                               continue;
+                       if (priv->ports[i].enable)
+                               mt7530_clear(priv, MT7530_PCR_P(i),
+@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit
+       /* Set the cpu port to be the only one in the port matrix of
+        * this port.
+        */
++      priv->bridge_dev[port] = NULL;
+       if (priv->ports[port].enable)
+               mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+                          PCR_MATRIX(BIT(MT7530_CPU_PORT)));
+@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev
+       if (!priv)
+               return -ENOMEM;
+-      priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
++      priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
+       if (!priv->ds)
+               return -ENOMEM;
+@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev
+       priv->bus = mdiodev->bus;
+       priv->dev = &mdiodev->dev;
+       priv->ds->priv = priv;
++      priv->ds->dev = &mdiodev->dev;
+       priv->ds->ops = &mt7530_switch_ops;
+       mutex_init(&priv->reg_mutex);
+       lpriv = priv;
+       dev_set_drvdata(&mdiodev->dev, priv);
+-      return dsa_register_switch(priv->ds, &mdiodev->dev);
++      return dsa_register_switch(priv->ds, priv->ds->dev->of_node);
+ }
+ static void
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -379,6 +379,8 @@ struct mt7530_priv {
+       struct mt7530_port      ports[MT7530_NUM_PORTS];
+       /* protect among processes for registers access*/
+       struct mutex reg_mutex;
++
++      struct net_device *bridge_dev[MT7530_NUM_PORTS];
+ };
+ struct mt7530_hw_stats {
+--- a/net/dsa/tag_mtk.c
++++ b/net/dsa/tag_mtk.c
+@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru
+       /* Build the tag after the MAC Source Address */
+       mtk_tag = skb->data + 2 * ETH_ALEN;
+       mtk_tag[0] = 0;
+-      mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
++      mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK;
+       mtk_tag[2] = 0;
+       mtk_tag[3] = 0;
diff --git a/target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch b/target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch
new file mode 100644 (file)
index 0000000..6c96b06
--- /dev/null
@@ -0,0 +1,38 @@
+From 52e9ce30a2b3c414e0efb20632fefa7cfc5096e6 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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)
+       val = mt7530_read(priv, MT7530_MHWTRAP);
+       val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
+       val |= MHWTRAP_MANUAL;
++      if (!dsa_is_cpu_port(ds, 5)) {
++              val |= MHWTRAP_P5_DIS;
++              val |= MHWTRAP_P5_MAC_SEL;
++              val |= MHWTRAP_P5_RGMII_MODE;
++      }
+       mt7530_write(priv, MT7530_MHWTRAP, val);
+       /* Enable and reset MIB counters */
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -221,6 +221,9 @@ static void mtk_phy_link_adjust(struct n
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
++
++      if (!of_phy_is_fixed_link(mac->of_node))
++              phy_print_status(dev->phydev);
+ }
+ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
diff --git a/target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch b/target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch
new file mode 100644 (file)
index 0000000..8ff2bed
--- /dev/null
@@ -0,0 +1,272 @@
+From cce5dd6034ed1651ee25c910edee708e6b84a44a Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 14:45:08 +0200
+Subject: [PATCH 33/57] net: dsa: add multi gmac support
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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:
+ static enum dsa_tag_protocol
+ mtk_get_tag_protocol(struct dsa_switch *ds)
+ {
+-      struct mt7530_priv *priv = ds->priv;
+-
+-      if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
+-              dev_warn(priv->dev,
+-                       "port not matched with tagging CPU port\n");
+-              return DSA_TAG_PROTO_NONE;
+-      } else {
+-              return DSA_TAG_PROTO_MTK;
+-      }
++      return DSA_TAG_PROTO_MTK;
+ }
+ static struct dsa_switch_ops mt7530_switch_ops = {
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -145,6 +145,8 @@ struct dsa_port {
+       struct device_node      *dn;
+       unsigned int            ageing_time;
+       u8                      stp_state;
++      struct net_device       *ethernet;
++      int                     upstream;
+ };
+ struct dsa_switch {
+@@ -205,7 +207,7 @@ struct dsa_switch {
+ static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
+ {
+-      return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
++      return !!(ds->cpu_port_mask & (1 << p));
+ }
+ static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p)
+@@ -218,6 +220,11 @@ static inline bool dsa_is_port_initializ
+       return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev;
+ }
++static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p)
++{
++      return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p);
++}
++
+ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
+ {
+       struct dsa_switch_tree *dst = ds->dst;
+@@ -234,6 +241,18 @@ static inline u8 dsa_upstream_port(struc
+               return ds->rtable[dst->cpu_switch];
+ }
++static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port)
++{
++      /*
++       * If this port has a specific upstream cpu port, use it,
++       * otherwise use the switch default.
++       */
++      if (ds->ports[port].upstream)
++              return ds->ports[port].upstream;
++      else
++              return dsa_upstream_port(ds);
++}
++
+ struct switchdev_trans;
+ struct switchdev_obj;
+ struct switchdev_obj_port_fdb;
+--- a/net/dsa/dsa2.c
++++ b/net/dsa/dsa2.c
+@@ -248,8 +248,6 @@ static int dsa_cpu_port_apply(struct dev
+               return err;
+       }
+-      ds->cpu_port_mask |= BIT(index);
+-
+       return 0;
+ }
+@@ -259,6 +257,10 @@ static void dsa_cpu_port_unapply(struct
+       dsa_cpu_dsa_destroy(port);
+       ds->cpu_port_mask &= ~BIT(index);
++      if (ds->ports[index].ethernet) {
++              dev_put(ds->ports[index].ethernet);
++              ds->ports[index].ethernet = NULL;
++      }
+ }
+ static int dsa_user_port_apply(struct device_node *port, u32 index,
+@@ -479,6 +481,29 @@ static int dsa_cpu_parse(struct device_n
+       dst->rcv = dst->tag_ops->rcv;
++      dev_hold(ethernet_dev);
++      ds->ports[index].ethernet = ethernet_dev;
++      ds->cpu_port_mask |= BIT(index);
++
++      return 0;
++}
++
++static int dsa_user_parse(struct device_node *port, u32 index,
++                        struct dsa_switch *ds)
++{
++      struct device_node *cpu_port;
++      const unsigned int *cpu_port_reg;
++      int cpu_port_index;
++
++      cpu_port = of_parse_phandle(port, "cpu", 0);
++      if (cpu_port) {
++              cpu_port_reg = of_get_property(cpu_port, "reg", NULL);
++              if (!cpu_port_reg)
++                      return -EINVAL;
++              cpu_port_index = be32_to_cpup(cpu_port_reg);
++              ds->ports[index].upstream = cpu_port_index;
++      }
++
+       return 0;
+ }
+@@ -486,18 +511,19 @@ static int dsa_ds_parse(struct dsa_switc
+ {
+       struct device_node *port;
+       u32 index;
+-      int err;
++      int err = 0;
+       for (index = 0; index < DSA_MAX_PORTS; index++) {
+               port = ds->ports[index].dn;
+               if (!port)
+                       continue;
+-              if (dsa_port_is_cpu(port)) {
++              if (dsa_port_is_cpu(port))
+                       err = dsa_cpu_parse(port, index, dst, ds);
+-                      if (err)
+-                              return err;
+-              }
++              else if (!dsa_port_is_dsa(port))
++                      err = dsa_user_parse(port, index,  ds);
++              if (err)
++                      return err;
+       }
+       pr_info("DSA: switch %d %d parsed\n", dst->tree, ds->index);
+--- a/net/dsa/dsa_priv.h
++++ b/net/dsa/dsa_priv.h
+@@ -43,6 +43,7 @@ struct dsa_slave_priv {
+       int                     old_duplex;
+       struct net_device       *bridge_dev;
++      struct net_device       *master;
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+       struct netpoll          *netpoll;
+ #endif
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -61,7 +61,7 @@ static int dsa_slave_get_iflink(const st
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      return p->parent->dst->master_netdev->ifindex;
++      return p->master->ifindex;
+ }
+ static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
+@@ -96,7 +96,7 @@ static void dsa_port_set_stp_state(struc
+ static int dsa_slave_open(struct net_device *dev)
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      struct net_device *master = p->parent->dst->master_netdev;
++      struct net_device *master = p->master;
+       struct dsa_switch *ds = p->parent;
+       u8 stp_state = dsa_port_is_bridged(p) ?
+                       BR_STATE_BLOCKING : BR_STATE_FORWARDING;
+@@ -151,7 +151,7 @@ out:
+ static int dsa_slave_close(struct net_device *dev)
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      struct net_device *master = p->parent->dst->master_netdev;
++      struct net_device *master = p->master;
+       struct dsa_switch *ds = p->parent;
+       if (p->phy)
+@@ -178,7 +178,7 @@ static int dsa_slave_close(struct net_de
+ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      struct net_device *master = p->parent->dst->master_netdev;
++      struct net_device *master = p->master;
+       if (change & IFF_ALLMULTI)
+               dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
+@@ -189,7 +189,7 @@ static void dsa_slave_change_rx_flags(st
+ static void dsa_slave_set_rx_mode(struct net_device *dev)
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      struct net_device *master = p->parent->dst->master_netdev;
++      struct net_device *master = p->master;
+       dev_mc_sync(master, dev);
+       dev_uc_sync(master, dev);
+@@ -198,7 +198,7 @@ static void dsa_slave_set_rx_mode(struct
+ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+-      struct net_device *master = p->parent->dst->master_netdev;
++      struct net_device *master = p->master;
+       struct sockaddr *addr = a;
+       int err;
+@@ -633,7 +633,7 @@ static netdev_tx_t dsa_slave_xmit(struct
+       /* Queue the SKB for transmission on the parent interface, but
+        * do not modify its EtherType
+        */
+-      nskb->dev = p->parent->dst->master_netdev;
++      nskb->dev = p->master;
+       dev_queue_xmit(nskb);
+       return NETDEV_TX_OK;
+@@ -945,7 +945,7 @@ static int dsa_slave_netpoll_setup(struc
+ {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+-      struct net_device *master = ds->dst->master_netdev;
++      struct net_device *master = p->master;
+       struct netpoll *netpoll;
+       int err = 0;
+@@ -1233,11 +1233,16 @@ int dsa_slave_create(struct dsa_switch *
+       struct net_device *master;
+       struct net_device *slave_dev;
+       struct dsa_slave_priv *p;
++      int port_cpu = ds->ports[port].upstream;
+       int ret;
+-      master = ds->dst->master_netdev;
+-      if (ds->master_netdev)
++      if (port_cpu && ds->ports[port_cpu].ethernet)
++              master = ds->ports[port_cpu].ethernet;
++      else if (ds->master_netdev)
+               master = ds->master_netdev;
++      else
++              master = ds->dst->master_netdev;
++      master->dsa_ptr = (void *)ds->dst;
+       slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
+                                NET_NAME_UNKNOWN, ether_setup);
+@@ -1263,6 +1268,7 @@ int dsa_slave_create(struct dsa_switch *
+       p->parent = ds;
+       p->port = port;
+       p->xmit = dst->tag_ops->xmit;
++      p->master = master;
+       p->old_pause = -1;
+       p->old_link = -1;
diff --git a/target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch b/target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch
new file mode 100644 (file)
index 0000000..ae06146
--- /dev/null
@@ -0,0 +1,91 @@
+From dcb751a52b2ee69c16db2fef8f92a96ab13b6bb4 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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)
+       /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
+       val = mt7530_read(priv, MT7530_MHWTRAP);
+-      val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
++      val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
+       val |= MHWTRAP_MANUAL;
+       if (!dsa_is_cpu_port(ds, 5)) {
+               val |= MHWTRAP_P5_DIS;
+@@ -735,6 +735,9 @@ static int
+ mt7530_cpu_port_enable(struct mt7530_priv *priv,
+                      int port)
+ {
++      u8 port_mask = 0;
++      int i;
++
+       /* Enable Mediatek header mode on the cpu port */
+       mt7530_write(priv, MT7530_PVC_P(port),
+                    PORT_SPEC_TAG);
+@@ -751,8 +754,12 @@ mt7530_cpu_port_enable(struct mt7530_pri
+       /* CPU port gets connected to all user ports of
+        * the switch
+        */
++      for (i = 0; i < MT7530_NUM_PORTS; i++)
++              if ((priv->ds->enabled_port_mask & BIT(i)) &&
++                  (dsa_port_upstream_port(priv->ds, i) == port))
++                      port_mask |= BIT(i);
+       mt7530_write(priv, MT7530_PCR_P(port),
+-                   PCR_MATRIX(priv->ds->enabled_port_mask));
++                   PCR_MATRIX(port_mask));
+       return 0;
+ }
+@@ -762,6 +769,7 @@ mt7530_port_enable(struct dsa_switch *ds
+                  struct phy_device *phy)
+ {
+       struct mt7530_priv *priv = ds->priv;
++      u8 upstream = dsa_port_upstream_port(ds, port);
+       mutex_lock(&priv->reg_mutex);
+@@ -772,7 +780,7 @@ mt7530_port_enable(struct dsa_switch *ds
+        * restore the port matrix if the port is the member of a certain
+        * bridge.
+        */
+-      priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
++      priv->ports[port].pm |= PCR_MATRIX(BIT(upstream));
+       priv->ports[port].enable = true;
+       mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+                  priv->ports[port].pm);
+@@ -835,7 +843,8 @@ mt7530_port_bridge_join(struct dsa_switc
+                       struct net_device *bridge)
+ {
+       struct mt7530_priv *priv = ds->priv;
+-      u32 port_bitmap = BIT(MT7530_CPU_PORT);
++      u8 upstream = dsa_port_upstream_port(ds, port);
++      u32 port_bitmap = BIT(upstream);
+       int i;
+       mutex_lock(&priv->reg_mutex);
+@@ -873,6 +882,7 @@ static void
+ mt7530_port_bridge_leave(struct dsa_switch *ds, int port)
+ {
+       struct mt7530_priv *priv = ds->priv;
++      u8 upstream = dsa_port_upstream_port(ds, port);
+       int i;
+       mutex_lock(&priv->reg_mutex);
+@@ -898,8 +908,8 @@ mt7530_port_bridge_leave(struct dsa_swit
+       priv->bridge_dev[port] = NULL;
+       if (priv->ports[port].enable)
+               mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+-                         PCR_MATRIX(BIT(MT7530_CPU_PORT)));
+-      priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
++                         PCR_MATRIX(BIT(upstream)));
++      priv->ports[port].pm = PCR_MATRIX(BIT(upstream));
+       mutex_unlock(&priv->reg_mutex);
+ }
diff --git a/target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch b/target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch
new file mode 100644 (file)
index 0000000..36321c5
--- /dev/null
@@ -0,0 +1,47 @@
+From 35b83b85e752a6660b92f08c0fb912308f25cf6d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:56:40 +0200
+Subject: [PATCH 35/57] net: mediatek: disable RX VLan offloading
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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)
diff --git a/target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch b/target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch
new file mode 100644 (file)
index 0000000..e96374f
--- /dev/null
@@ -0,0 +1,25 @@
+From bf25fbdc7dfb256f267725336e29e232aadd5123 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch b/target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch
new file mode 100644 (file)
index 0000000..9d6a089
--- /dev/null
@@ -0,0 +1,128 @@
+From 047a4e7b17322c1b32d8db32a0df9899cb4963a3 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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;
diff --git a/target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch b/target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch
new file mode 100644 (file)
index 0000000..cb1c1b9
--- /dev/null
@@ -0,0 +1,46 @@
+From b58bf0220f666705e63fe8d361f37c913aee2d8f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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);
diff --git a/target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch b/target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch
new file mode 100644 (file)
index 0000000..ebc52c8
--- /dev/null
@@ -0,0 +1,32 @@
+From 22e8b65ea4bf8a1fa757137bdcbdefe505fa4044 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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 {
diff --git a/target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch b/target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch
new file mode 100644 (file)
index 0000000..da98a21
--- /dev/null
@@ -0,0 +1,39 @@
+From 9d6806e16e5ea68a49225da1ab065ef0b5d7704b Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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,
+ };
diff --git a/target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch b/target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch
new file mode 100644 (file)
index 0000000..5435962
--- /dev/null
@@ -0,0 +1,65 @@
+From 04c825484d6ecdcc8ce09b350235c9077eaca6e3 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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)
diff --git a/target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch b/target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch
new file mode 100644 (file)
index 0000000..4f2c7b2
--- /dev/null
@@ -0,0 +1,50 @@
+From a306af3b97c56b9e224a2f9ee04838a2d32ff60b Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch b/target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch
new file mode 100644 (file)
index 0000000..2256325
--- /dev/null
@@ -0,0 +1,41 @@
+From 53e3d9af39805a7e1ba81a047a9ab433be0e82f5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch b/target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch
new file mode 100644 (file)
index 0000000..51204d4
--- /dev/null
@@ -0,0 +1,43 @@
+From 6a5932028a4f3217ed7c9d602f269611d95dd8ca Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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)
diff --git a/target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch b/target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch
new file mode 100644 (file)
index 0000000..c263b07
--- /dev/null
@@ -0,0 +1,79 @@
+From 1e33784f665cb95c2af5481d3e776d2d3099921b Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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 <sean.wang@mediatek.com>");
+ MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
diff --git a/target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch b/target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch
new file mode 100644 (file)
index 0000000..47c3980
--- /dev/null
@@ -0,0 +1,56 @@
+From 6e081074df96bf3762c2e6438c383f11a56b0a7e Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:58:04 +0200
+Subject: [PATCH 46/57] net: mediatek: add irq delay
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 ++++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 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 <igvtee@gmail.com>
+  */
++#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
diff --git a/target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch b/target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch
new file mode 100644 (file)
index 0000000..27a78a6
--- /dev/null
@@ -0,0 +1,208 @@
+From 5afceece38fa30e3c71e7ed9ac62aa70ba8cfbb1 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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];
diff --git a/target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch b/target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch
new file mode 100644 (file)
index 0000000..20d0e43
--- /dev/null
@@ -0,0 +1,90 @@
+From 3e969c9695b45e1a052d43b367096ec99f2f0aac Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:58:29 +0200
+Subject: [PATCH 48/57] net: core: add RPS balancer
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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
diff --git a/target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch b/target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch
new file mode 100644 (file)
index 0000000..0146a9d
--- /dev/null
@@ -0,0 +1,20 @@
+From 066b30a76a0d13cbd2c0d463f9a1e87efc352679 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:58:46 +0200
+Subject: [PATCH 49/57] net: mediatek: add rx queue
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -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;
diff --git a/target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch b/target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch
new file mode 100644 (file)
index 0000000..3d7df70
--- /dev/null
@@ -0,0 +1,21 @@
+From 67c4af99af02d86b627a8cde2e99cc4c9699d2ce Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 15:59:08 +0200
+Subject: [PATCH 50/57] net: mediatek: add trgmii clock
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -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]);
diff --git a/target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch b/target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch
new file mode 100644 (file)
index 0000000..3de3e73
--- /dev/null
@@ -0,0 +1,21 @@
+From 5cbf53c7e5eac5bacc409461888789accdaf8eec Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 16:00:06 +0200
+Subject: [PATCH 51/57] net: mediatek: increase tx_timeout
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -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;
diff --git a/target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch
deleted file mode 100644 (file)
index 7c786be..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-From 5238c5d1d38661955ed3b52f45c46e00bfc9eb6e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 7 Apr 2016 07:18:35 +0200
-Subject: [PATCH 052/102] clk: dont disable unused clocks
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/clk/clk.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/clk/clk.c
-+++ b/drivers/clk/clk.c
-@@ -796,7 +796,7 @@ unlock_out:
-               clk_core_disable_unprepare(core->parent);
- }
--static bool clk_ignore_unused;
-+static bool clk_ignore_unused = true;
- static int __init clk_ignore_unused_setup(char *__unused)
- {
-       clk_ignore_unused = true;
diff --git a/target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch b/target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch
new file mode 100644 (file)
index 0000000..89f730b
--- /dev/null
@@ -0,0 +1,21 @@
+From 18b2169d84b47a3414164e5e40f23fb7e875707c Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 16:00:28 +0200
+Subject: [PATCH 52/57] net: phy: add FC
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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,
diff --git a/target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch
deleted file mode 100644 (file)
index 3993900..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-From c8fd103d6c07af5db47f061b70759b7c69169656 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 06:46:51 +0200
-Subject: [PATCH 053/102] clk: mediatek: enable critical clocks
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/clk/mediatek/clk-mt2701.c |   22 ++++++++++++++++++++--
- 1 file changed, 20 insertions(+), 2 deletions(-)
-
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[]
-       GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
- };
-+static struct clk_onecell_data *mt7623_top_clk_data __initdata;
-+static struct clk_onecell_data *mt7623_pll_clk_data __initdata;
-+
-+static void __init mtk_clk_enable_critical(void)
-+{
-+      if (!mt7623_top_clk_data || !mt7623_pll_clk_data)
-+              return;
-+
-+      clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]);
-+      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]);
-+      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]);
-+      clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]);
-+}
-+
- static void __init mtk_topckgen_init(struct device_node *node)
- {
-       struct clk_onecell_data *clk_data;
-@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str
-               return;
-       }
--      clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
-+      mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
-       mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
-                                                               clk_data);
-@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_clk_enable_critical();
- }
- CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
-@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s
-       struct clk_onecell_data *clk_data;
-       int r;
--      clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
-+      mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
-       if (!clk_data)
-               return;
-@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
-                       __func__, r);
-+
-+      mtk_clk_enable_critical();
- }
- CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
-                                                       mtk_apmixedsys_init);
diff --git a/target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch b/target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch
new file mode 100644 (file)
index 0000000..a41bcb0
--- /dev/null
@@ -0,0 +1,68 @@
+From 53eec2c3580e63fdebfc25ae324f30cd8aa4403b Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <john@phrozen.org>
+---
+ 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 | \
diff --git a/target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
deleted file mode 100644 (file)
index a22cb99..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-From 1387d4f0ebf4b48c09f2ea0d27a02936c3fa0010 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 02:26:37 +0200
-Subject: [PATCH 054/102] clk: mediatek: Export CPU mux clocks for CPU
- frequency control
-
-This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
-for intermediate clock source switching.
-
-Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
----
- drivers/clk/mediatek/Makefile          |    2 +-
- drivers/clk/mediatek/clk-cpumux.c      |  127 ++++++++++++++++++++++++++++++++
- drivers/clk/mediatek/clk-cpumux.h      |   22 ++++++
- drivers/clk/mediatek/clk-mt2701.c      |    8 ++
- drivers/clk/mediatek/clk-mt8173.c      |   23 ++++++
- include/dt-bindings/clock/mt2701-clk.h |    3 +-
- include/dt-bindings/clock/mt8173-clk.h |    4 +-
- 7 files changed, 186 insertions(+), 3 deletions(-)
- create mode 100644 drivers/clk/mediatek/clk-cpumux.c
- create mode 100644 drivers/clk/mediatek/clk-cpumux.h
-
---- a/drivers/clk/mediatek/Makefile
-+++ b/drivers/clk/mediatek/Makefile
-@@ -1,4 +1,4 @@
--obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o
-+obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o
- obj-$(CONFIG_RESET_CONTROLLER) += reset.o
- obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
- obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
---- /dev/null
-+++ b/drivers/clk/mediatek/clk-cpumux.c
-@@ -0,0 +1,127 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk-provider.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/slab.h>
-+
-+#include "clk-mtk.h"
-+#include "clk-cpumux.h"
-+
-+struct mtk_clk_cpumux {
-+      struct clk_hw   hw;
-+      struct regmap   *regmap;
-+      u32             reg;
-+      u32             mask;
-+      u8              shift;
-+};
-+
-+static inline struct mtk_clk_cpumux *to_mtk_clk_mux(struct clk_hw *_hw)
-+{
-+      return container_of(_hw, struct mtk_clk_cpumux, hw);
-+}
-+
-+static u8 clk_cpumux_get_parent(struct clk_hw *hw)
-+{
-+      struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw);
-+      int num_parents = clk_hw_get_num_parents(hw);
-+      unsigned int val;
-+
-+      regmap_read(mux->regmap, mux->reg, &val);
-+
-+      val >>= mux->shift;
-+      val &= mux->mask;
-+
-+      if (val >= num_parents)
-+              return -EINVAL;
-+
-+      return val;
-+}
-+
-+static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index)
-+{
-+      struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw);
-+      u32 mask, val;
-+
-+      val = index << mux->shift;
-+      mask = mux->mask << mux->shift;
-+
-+      return regmap_update_bits(mux->regmap, mux->reg, mask, val);
-+}
-+
-+static const struct clk_ops clk_cpumux_ops = {
-+      .get_parent = clk_cpumux_get_parent,
-+      .set_parent = clk_cpumux_set_parent,
-+};
-+
-+static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux,
-+                                         struct regmap *regmap)
-+{
-+      struct mtk_clk_cpumux *cpumux;
-+      struct clk *clk;
-+      struct clk_init_data init;
-+
-+      cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL);
-+      if (!cpumux)
-+              return ERR_PTR(-ENOMEM);
-+
-+      init.name = mux->name;
-+      init.ops = &clk_cpumux_ops;
-+      init.parent_names = mux->parent_names;
-+      init.num_parents = mux->num_parents;
-+      init.flags = mux->flags;
-+
-+      cpumux->reg = mux->mux_reg;
-+      cpumux->shift = mux->mux_shift;
-+      cpumux->mask = BIT(mux->mux_width) - 1;
-+      cpumux->regmap = regmap;
-+      cpumux->hw.init = &init;
-+
-+      clk = clk_register(NULL, &cpumux->hw);
-+      if (IS_ERR(clk))
-+              kfree(cpumux);
-+
-+      return clk;
-+}
-+
-+int __init mtk_clk_register_cpumuxes(struct device_node *node,
-+                            const struct mtk_composite *clks, int num,
-+                            struct clk_onecell_data *clk_data)
-+{
-+      int i;
-+      struct clk *clk;
-+      struct regmap *regmap;
-+
-+      regmap = syscon_node_to_regmap(node);
-+      if (IS_ERR(regmap)) {
-+              pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
-+                     PTR_ERR(regmap));
-+              return PTR_ERR(regmap);
-+      }
-+
-+      for (i = 0; i < num; i++) {
-+              const struct mtk_composite *mux = &clks[i];
-+
-+              clk = mtk_clk_register_cpumux(mux, regmap);
-+              if (IS_ERR(clk)) {
-+                      pr_err("Failed to register clk %s: %ld\n",
-+                             mux->name, PTR_ERR(clk));
-+                      continue;
-+              }
-+
-+              clk_data->clks[mux->id] = clk;
-+      }
-+
-+      return 0;
-+}
---- /dev/null
-+++ b/drivers/clk/mediatek/clk-cpumux.h
-@@ -0,0 +1,22 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __DRV_CLK_CPUMUX_H
-+#define __DRV_CLK_CPUMUX_H
-+
-+int mtk_clk_register_cpumuxes(struct device_node *node,
-+                            const struct mtk_composite *clks, int num,
-+                            struct clk_onecell_data *clk_data);
-+
-+#endif /* __DRV_CLK_CPUMUX_H */
---- a/drivers/clk/mediatek/clk-mt2701.c
-+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -18,6 +18,7 @@
- #include "clk-mtk.h"
- #include "clk-gate.h"
-+#include "clk-cpumux.h"
- #include <dt-bindings/clock/mt2701-clk.h>
-@@ -465,6 +466,10 @@ static const char * const cpu_parents[]
-       "mmpll"
- };
-+static const struct mtk_composite cpu_muxes[] __initconst = {
-+      MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2),
-+};
-+
- static const struct mtk_composite top_muxes[] __initconst = {
-       MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
-               0x0040, 0, 3, INVALID_MUX_GATE_BIT),
-@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str
-       mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
-                                               clk_data);
-+      mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
-+                                              clk_data);
-+
-       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
---- a/drivers/clk/mediatek/clk-mt8173.c
-+++ b/drivers/clk/mediatek/clk-mt8173.c
-@@ -18,6 +18,7 @@
- #include "clk-mtk.h"
- #include "clk-gate.h"
-+#include "clk-cpumux.h"
- #include <dt-bindings/clock/mt8173-clk.h>
-@@ -525,6 +526,25 @@ static const char * const i2s3_b_ck_pare
-       "apll2_div5"
- };
-+static const char * const ca53_parents[] __initconst = {
-+      "clk26m",
-+      "armca7pll",
-+      "mainpll",
-+      "univpll"
-+};
-+
-+static const char * const ca57_parents[] __initconst = {
-+      "clk26m",
-+      "armca15pll",
-+      "mainpll",
-+      "univpll"
-+};
-+
-+static const struct mtk_composite cpu_muxes[] __initconst = {
-+      MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
-+      MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
-+};
-+
- static const struct mtk_composite top_muxes[] __initconst = {
-       /* CLK_CFG_0 */
-       MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
-@@ -948,6 +968,9 @@ static void __init mtk_infrasys_init(str
-                                               clk_data);
-       mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
-+      mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes),
-+                                              clk_data);
-+
-       r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
-       if (r)
-               pr_err("%s(): could not register clock provider: %d\n",
---- a/include/dt-bindings/clock/mt2701-clk.h
-+++ b/include/dt-bindings/clock/mt2701-clk.h
-@@ -221,7 +221,8 @@
- #define CLK_INFRA_PMICWRAP                    17
- #define CLK_INFRA_DDCCI                               18
- #define CLK_INFRA_CLK_13M                     19
--#define CLK_INFRA_NR                          20
-+#define CLK_INFRA_CPUSEL                      20
-+#define CLK_INFRA_NR                          21
- /* PERICFG */
---- a/include/dt-bindings/clock/mt8173-clk.h
-+++ b/include/dt-bindings/clock/mt8173-clk.h
-@@ -193,7 +193,9 @@
- #define CLK_INFRA_PMICSPI             10
- #define CLK_INFRA_PMICWRAP            11
- #define CLK_INFRA_CLK_13M             12
--#define CLK_INFRA_NR_CLK              13
-+#define CLK_INFRA_CA53SEL             13
-+#define CLK_INFRA_CA57SEL             14
-+#define CLK_INFRA_NR_CLK              15
- /* PERI_SYS */
diff --git a/target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch b/target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch
new file mode 100644 (file)
index 0000000..2900531
--- /dev/null
@@ -0,0 +1,105 @@
+From 746bf1c3e561aba396cd40e6540245646461117d Mon Sep 17 00:00:00 2001
+From: Sean Wang <sean.wang@mediatek.com>
+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 <sean.wang@mediatek.com>
+---
+ 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);
+               }
+       }
diff --git a/target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch
deleted file mode 100644 (file)
index 4e7c059..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-From 60f4e41b367bdb29530468c91c1e613b17a37755 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 30 Mar 2016 23:48:53 +0200
-Subject: [PATCH 055/102] cpufreq: mediatek: add driver
-
-Signed-off-by: John Crispin <john@phrozen.org>
----
- drivers/cpufreq/Kconfig.arm      |    9 +
- drivers/cpufreq/Makefile         |    1 +
- drivers/cpufreq/mt7623-cpufreq.c |  389 ++++++++++++++++++++++++++++++++++++++
- 3 files changed, 399 insertions(+)
- create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
-
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -74,6 +74,15 @@ config ARM_KIRKWOOD_CPUFREQ
-         This adds the CPUFreq driver for Marvell Kirkwood
-         SoCs.
-+config ARM_MT7623_CPUFREQ
-+      bool "Mediatek MT7623 CPUFreq support"
-+      depends on ARCH_MEDIATEK && REGULATOR
-+      depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
-+      depends on !CPU_THERMAL || THERMAL=y
-+      select PM_OPP
-+      help
-+        This adds the CPUFreq driver support for Mediatek MT7623 SoC.
-+
- config ARM_MT8173_CPUFREQ
-       tristate "Mediatek MT8173 CPUFreq support"
-       depends on ARCH_MEDIATEK && REGULATOR
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -58,6 +58,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)   += hi
- obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)               += imx6q-cpufreq.o
- obj-$(CONFIG_ARM_INTEGRATOR)          += integrator-cpufreq.o
- obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ)    += kirkwood-cpufreq.o
-+obj-$(CONFIG_ARM_MT7623_CPUFREQ)      += mt7623-cpufreq.o
- obj-$(CONFIG_ARM_MT8173_CPUFREQ)      += mt8173-cpufreq.o
- obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)   += omap-cpufreq.o
- obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)      += pxa2xx-cpufreq.o
---- /dev/null
-+++ b/drivers/cpufreq/mt7623-cpufreq.c
-@@ -0,0 +1,389 @@
-+/*
-+ * Copyright (c) 2015 Linaro Ltd.
-+ * Author: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/cpu.h>
-+#include <linux/cpu_cooling.h>
-+#include <linux/cpufreq.h>
-+#include <linux/cpumask.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/thermal.h>
-+
-+#define VOLT_TOL              (10000)
-+
-+/*
-+ * When scaling the clock frequency of a CPU clock domain, the clock source
-+ * needs to be switched to another stable PLL clock temporarily until
-+ * the original PLL becomes stable at target frequency.
-+ */
-+struct mtk_cpu_dvfs_info {
-+      struct device *cpu_dev;
-+      struct regulator *proc_reg;
-+      struct clk *cpu_clk;
-+      struct clk *inter_clk;
-+      struct thermal_cooling_device *cdev;
-+      int intermediate_voltage;
-+};
-+
-+static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
-+{
-+      return regulator_set_voltage(info->proc_reg, vproc,
-+                                   vproc + VOLT_TOL);
-+}
-+
-+static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
-+                                unsigned int index)
-+{
-+      struct cpufreq_frequency_table *freq_table = policy->freq_table;
-+      struct clk *cpu_clk = policy->clk;
-+      struct clk *armpll = clk_get_parent(cpu_clk);
-+      struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+      struct device *cpu_dev = info->cpu_dev;
-+      struct dev_pm_opp *opp;
-+      long freq_hz, old_freq_hz;
-+      int vproc, old_vproc, inter_vproc, target_vproc, ret;
-+
-+      inter_vproc = info->intermediate_voltage;
-+
-+      old_freq_hz = clk_get_rate(cpu_clk);
-+      old_vproc = regulator_get_voltage(info->proc_reg);
-+
-+      freq_hz = freq_table[index].frequency * 1000;
-+
-+      rcu_read_lock();
-+      opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
-+      if (IS_ERR(opp)) {
-+              rcu_read_unlock();
-+              pr_err("cpu%d: failed to find OPP for %ld\n",
-+                     policy->cpu, freq_hz);
-+              return PTR_ERR(opp);
-+      }
-+      vproc = dev_pm_opp_get_voltage(opp);
-+      rcu_read_unlock();
-+
-+      /*
-+       * If the new voltage or the intermediate voltage is higher than the
-+       * current voltage, scale up voltage first.
-+       */
-+      target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc;
-+      if (old_vproc < target_vproc) {
-+              ret = mtk_cpufreq_set_voltage(info, target_vproc);
-+              if (ret) {
-+                      pr_err("cpu%d: failed to scale up voltage!\n",
-+                             policy->cpu);
-+                      mtk_cpufreq_set_voltage(info, old_vproc);
-+                      return ret;
-+              }
-+      }
-+
-+      /* Reparent the CPU clock to intermediate clock. */
-+      ret = clk_set_parent(cpu_clk, info->inter_clk);
-+      if (ret) {
-+              pr_err("cpu%d: failed to re-parent cpu clock!\n",
-+                     policy->cpu);
-+              mtk_cpufreq_set_voltage(info, old_vproc);
-+              WARN_ON(1);
-+              return ret;
-+      }
-+
-+      /* Set the original PLL to target rate. */
-+      ret = clk_set_rate(armpll, freq_hz);
-+      if (ret) {
-+              pr_err("cpu%d: failed to scale cpu clock rate!\n",
-+                     policy->cpu);
-+              clk_set_parent(cpu_clk, armpll);
-+              mtk_cpufreq_set_voltage(info, old_vproc);
-+              return ret;
-+      }
-+
-+      /* Set parent of CPU clock back to the original PLL. */
-+      ret = clk_set_parent(cpu_clk, armpll);
-+      if (ret) {
-+              pr_err("cpu%d: failed to re-parent cpu clock!\n",
-+                     policy->cpu);
-+              mtk_cpufreq_set_voltage(info, inter_vproc);
-+              WARN_ON(1);
-+              return ret;
-+      }
-+
-+      /*
-+       * If the new voltage is lower than the intermediate voltage or the
-+       * original voltage, scale down to the new voltage.
-+       */
-+      if (vproc < inter_vproc || vproc < old_vproc) {
-+              ret = mtk_cpufreq_set_voltage(info, vproc);
-+              if (ret) {
-+                      pr_err("cpu%d: failed to scale down voltage!\n",
-+                             policy->cpu);
-+                      clk_set_parent(cpu_clk, info->inter_clk);
-+                      clk_set_rate(armpll, old_freq_hz);
-+                      clk_set_parent(cpu_clk, armpll);
-+                      return ret;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
-+{
-+      struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+      struct device_node *np = of_node_get(info->cpu_dev->of_node);
-+
-+      if (WARN_ON(!np))
-+              return;
-+
-+      if (of_find_property(np, "#cooling-cells", NULL)) {
-+              info->cdev = of_cpufreq_cooling_register(np,
-+                                                       policy->related_cpus);
-+
-+              if (IS_ERR(info->cdev)) {
-+                      dev_err(info->cpu_dev,
-+                              "running cpufreq without cooling device: %ld\n",
-+                              PTR_ERR(info->cdev));
-+
-+                      info->cdev = NULL;
-+              }
-+      }
-+
-+      of_node_put(np);
-+}
-+
-+static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
-+{
-+      struct device *cpu_dev;
-+      struct regulator *proc_reg = ERR_PTR(-ENODEV);
-+      struct clk *cpu_clk = ERR_PTR(-ENODEV);
-+      struct clk *inter_clk = ERR_PTR(-ENODEV);
-+      struct dev_pm_opp *opp;
-+      unsigned long rate;
-+      int ret;
-+
-+      cpu_dev = get_cpu_device(cpu);
-+      if (!cpu_dev) {
-+              pr_err("failed to get cpu%d device\n", cpu);
-+              return -ENODEV;
-+      }
-+
-+      cpu_clk = clk_get(cpu_dev, "cpu");
-+      if (IS_ERR(cpu_clk)) {
-+              if (PTR_ERR(cpu_clk) == -EPROBE_DEFER)
-+                      pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu);
-+              else
-+                      pr_err("failed to get cpu clk for cpu%d\n", cpu);
-+
-+              ret = PTR_ERR(cpu_clk);
-+              return ret;
-+      }
-+
-+      inter_clk = clk_get(cpu_dev, "intermediate");
-+      if (IS_ERR(inter_clk)) {
-+              if (PTR_ERR(inter_clk) == -EPROBE_DEFER)
-+                      pr_warn("intermediate clk for cpu%d not ready, retry.\n",
-+                              cpu);
-+              else
-+                      pr_err("failed to get intermediate clk for cpu%d\n",
-+                             cpu);
-+
-+              ret = PTR_ERR(inter_clk);
-+              goto out_free_resources;
-+      }
-+
-+      proc_reg = regulator_get_exclusive(cpu_dev, "proc");
-+      if (IS_ERR(proc_reg)) {
-+              if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
-+                      pr_warn("proc regulator for cpu%d not ready, retry.\n",
-+                              cpu);
-+              else
-+                      pr_err("failed to get proc regulator for cpu%d\n",
-+                             cpu);
-+
-+              ret = PTR_ERR(proc_reg);
-+              goto out_free_resources;
-+      }
-+
-+      ret = dev_pm_opp_of_add_table(cpu_dev);
-+      if (ret) {
-+              pr_warn("no OPP table for cpu%d\n", cpu);
-+              goto out_free_resources;
-+      }
-+
-+      /* Search a safe voltage for intermediate frequency. */
-+      rate = clk_get_rate(inter_clk);
-+      rcu_read_lock();
-+      opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
-+      if (IS_ERR(opp)) {
-+              rcu_read_unlock();
-+              pr_err("failed to get intermediate opp for cpu%d\n", cpu);
-+              ret = PTR_ERR(opp);
-+              goto out_free_opp_table;
-+      }
-+      info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
-+      rcu_read_unlock();
-+
-+      info->cpu_dev = cpu_dev;
-+      info->proc_reg = proc_reg;
-+      info->cpu_clk = cpu_clk;
-+      info->inter_clk = inter_clk;
-+
-+      return 0;
-+
-+out_free_opp_table:
-+      dev_pm_opp_of_remove_table(cpu_dev);
-+
-+out_free_resources:
-+      if (!IS_ERR(proc_reg))
-+              regulator_put(proc_reg);
-+      if (!IS_ERR(cpu_clk))
-+              clk_put(cpu_clk);
-+      if (!IS_ERR(inter_clk))
-+              clk_put(inter_clk);
-+
-+      return ret;
-+}
-+
-+static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
-+{
-+      if (!IS_ERR(info->proc_reg))
-+              regulator_put(info->proc_reg);
-+      if (!IS_ERR(info->cpu_clk))
-+              clk_put(info->cpu_clk);
-+      if (!IS_ERR(info->inter_clk))
-+              clk_put(info->inter_clk);
-+
-+      dev_pm_opp_of_remove_table(info->cpu_dev);
-+}
-+
-+static int mtk_cpufreq_init(struct cpufreq_policy *policy)
-+{
-+      struct mtk_cpu_dvfs_info *info;
-+      struct cpufreq_frequency_table *freq_table;
-+      int ret;
-+
-+      info = kzalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return -ENOMEM;
-+
-+      ret = mtk_cpu_dvfs_info_init(info, policy->cpu);
-+      if (ret) {
-+              pr_err("%s failed to initialize dvfs info for cpu%d\n",
-+                     __func__, policy->cpu);
-+              goto out_free_dvfs_info;
-+      }
-+
-+      ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
-+      if (ret) {
-+              pr_err("failed to init cpufreq table for cpu%d: %d\n",
-+                     policy->cpu, ret);
-+              goto out_release_dvfs_info;
-+      }
-+
-+      ret = cpufreq_table_validate_and_show(policy, freq_table);
-+      if (ret) {
-+              pr_err("%s: invalid frequency table: %d\n", __func__, ret);
-+              goto out_free_cpufreq_table;
-+      }
-+
-+      /* CPUs in the same cluster share a clock and power domain. */
-+      cpumask_setall(policy->cpus);
-+      policy->driver_data = info;
-+      policy->clk = info->cpu_clk;
-+
-+      return 0;
-+
-+out_free_cpufreq_table:
-+      dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table);
-+
-+out_release_dvfs_info:
-+      mtk_cpu_dvfs_info_release(info);
-+
-+out_free_dvfs_info:
-+      kfree(info);
-+
-+      return ret;
-+}
-+
-+static int mtk_cpufreq_exit(struct cpufreq_policy *policy)
-+{
-+      struct mtk_cpu_dvfs_info *info = policy->driver_data;
-+
-+      cpufreq_cooling_unregister(info->cdev);
-+      dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table);
-+      mtk_cpu_dvfs_info_release(info);
-+      kfree(info);
-+
-+      return 0;
-+}
-+
-+static struct cpufreq_driver mt7623_cpufreq_driver = {
-+      .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
-+      .verify = cpufreq_generic_frequency_table_verify,
-+      .target_index = mtk_cpufreq_set_target,
-+      .get = cpufreq_generic_get,
-+      .init = mtk_cpufreq_init,
-+      .exit = mtk_cpufreq_exit,
-+      .ready = mtk_cpufreq_ready,
-+      .name = "mtk-cpufreq",
-+      .attr = cpufreq_generic_attr,
-+};
-+
-+static int mt7623_cpufreq_probe(struct platform_device *pdev)
-+{
-+      int ret;
-+
-+      ret = cpufreq_register_driver(&mt7623_cpufreq_driver);
-+      if (ret)
-+              pr_err("failed to register mtk cpufreq driver\n");
-+
-+      return ret;
-+}
-+
-+static struct platform_driver mt7623_cpufreq_platdrv = {
-+      .driver = {
-+              .name   = "mt7623-cpufreq",
-+      },
-+      .probe          = mt7623_cpufreq_probe,
-+};
-+
-+static int mt7623_cpufreq_driver_init(void)
-+{
-+      struct platform_device *pdev;
-+      int err;
-+
-+      if (!of_machine_is_compatible("mediatek,mt7623"))
-+              return -ENODEV;
-+
-+      err = platform_driver_register(&mt7623_cpufreq_platdrv);
-+      if (err)
-+              return err;
-+
-+      /*
-+       * Since there's no place to hold device registration code and no
-+       * device tree based way to match cpufreq driver yet, both the driver
-+       * and the device registration codes are put here to handle defer
-+       * probing.
-+       */
-+      pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0);
-+      if (IS_ERR(pdev)) {
-+              pr_err("failed to register mtk-cpufreq platform device\n");
-+              return PTR_ERR(pdev);
-+      }
-+
-+      return 0;
-+}
-+device_initcall(mt7623_cpufreq_driver_init);
diff --git a/target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch b/target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch
new file mode 100644 (file)
index 0000000..6598e82
--- /dev/null
@@ -0,0 +1,31 @@
+From a3360b3543b9fb833ba691019e396e72293a313f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+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 <sean.wang@mediatek.com>
+Acked-by: John Crispin <john@phrozen.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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)))
diff --git a/target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch b/target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch
new file mode 100644 (file)
index 0000000..d1d6ed4
--- /dev/null
@@ -0,0 +1,119 @@
+From 043efc0e619e04661be2b1889382db2fdd378145 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 16:34:36 +0200
+Subject: [PATCH 56/57] net: mediatek: add hw nat support
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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.
+        */
diff --git a/target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch b/target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch
new file mode 100644 (file)
index 0000000..f628458
--- /dev/null
@@ -0,0 +1,121 @@
+From 660c13dfbacbf37f090a66a2b14f0c5ce7cbec81 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 10 Aug 2017 16:38:27 +0200
+Subject: [PATCH 57/57] net: mediatek: add HW QoS support
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ 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)
diff --git a/target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch b/target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch
new file mode 100644 (file)
index 0000000..3174b80
--- /dev/null
@@ -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 <blogic@openwrt.org>
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- */
+-
+-#include <dt-bindings/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)
diff --git a/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch b/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch
new file mode 100644 (file)
index 0000000..61b4b26
--- /dev/null
@@ -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 */
diff --git a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch
deleted file mode 100644 (file)
index 19be772..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-From 6f5941c93bdf7649f392f1263b9068d360ceab4d Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Fri, 6 May 2016 02:55:48 +0200
-Subject: [PATCH 071/102] pwm: add pwm-mediatek
-
-Signed-off-by: John Crispin <john@phrozen.org>
----
- arch/arm/boot/dts/mt7623-evb.dts |   17 +++
- arch/arm/boot/dts/mt7623.dtsi    |   22 ++++
- drivers/pwm/Kconfig              |    9 ++
- drivers/pwm/Makefile             |    1 +
- drivers/pwm/pwm-mediatek.c       |  230 ++++++++++++++++++++++++++++++++++++++
- 5 files changed, 279 insertions(+)
- create mode 100644 drivers/pwm/pwm-mediatek.c
-
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -282,6 +282,15 @@ config PWM_MTK_DISP
-         To compile this driver as a module, choose M here: the module
-         will be called pwm-mtk-disp.
-+config PWM_MEDIATEK
-+      tristate "MediaTek PWM support"
-+      depends on ARCH_MEDIATEK || COMPILE_TEST
-+      help
-+        Generic PWM framework driver for Mediatek ARM SoC.
-+
-+        To compile this driver as a module, choose M here: the module
-+        will be called pwm-mxs.
-+
- config PWM_MXS
-       tristate "Freescale MXS PWM support"
-       depends on ARCH_MXS && OF
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS)               += pwm-lpss.o
- obj-$(CONFIG_PWM_LPSS_PCI)    += pwm-lpss-pci.o
- obj-$(CONFIG_PWM_LPSS_PLATFORM)       += pwm-lpss-platform.o
- obj-$(CONFIG_PWM_MESON)               += pwm-meson.o
-+obj-$(CONFIG_PWM_MEDIATEK)    += pwm-mediatek.o
- obj-$(CONFIG_PWM_MTK_DISP)    += pwm-mtk-disp.o
- obj-$(CONFIG_PWM_MXS)         += pwm-mxs.o
- obj-$(CONFIG_PWM_OMAP_DMTIMER)        += pwm-omap-dmtimer.o
---- /dev/null
-+++ b/drivers/pwm/pwm-mediatek.c
-@@ -0,0 +1,230 @@
-+/*
-+ * Mediatek Pulse Width Modulator driver
-+ *
-+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/clk.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#define NUM_PWM               5
-+
-+/* PWM registers and bits definitions */
-+#define PWMCON                        0x00
-+#define PWMHDUR                       0x04
-+#define PWMLDUR                       0x08
-+#define PWMGDUR                       0x0c
-+#define PWMWAVENUM            0x28
-+#define PWMDWIDTH             0x2c
-+#define PWMTHRES              0x30
-+
-+/**
-+ * struct mtk_pwm_chip - struct representing pwm chip
-+ *
-+ * @mmio_base: base address of pwm chip
-+ * @chip: linux pwm chip representation
-+ */
-+struct mtk_pwm_chip {
-+      void __iomem *mmio_base;
-+      struct pwm_chip chip;
-+      struct clk *clk_top;
-+      struct clk *clk_main;
-+      struct clk *clk_pwm[NUM_PWM];
-+};
-+
-+static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
-+{
-+      return container_of(chip, struct mtk_pwm_chip, chip);
-+}
-+
-+static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
-+                                unsigned long offset)
-+{
-+      return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
-+}
-+
-+static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
-+                                  unsigned int num, unsigned long offset,
-+                                  unsigned long val)
-+{
-+      iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
-+}
-+
-+static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-+                          int duty_ns, int period_ns)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 resolution = 100 / 4;
-+      u32 clkdiv = 0;
-+
-+      resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm]));
-+
-+      while (period_ns / resolution  > 8191) {
-+              clkdiv++;
-+              resolution *= 2;
-+      }
-+
-+      if (clkdiv > 7)
-+              return -1;
-+
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
-+      return 0;
-+}
-+
-+static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 val;
-+      int ret;
-+
-+      ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]);
-+      if (ret < 0)
-+              return ret;
-+
-+      val = ioread32(pc->mmio_base);
-+      val |= BIT(pwm->hwpwm);
-+      iowrite32(val, pc->mmio_base);
-+
-+      return 0;
-+}
-+
-+static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 val;
-+
-+      val = ioread32(pc->mmio_base);
-+      val &= ~BIT(pwm->hwpwm);
-+      iowrite32(val, pc->mmio_base);
-+        clk_unprepare(pc->clk_pwm[pwm->hwpwm]);
-+}
-+
-+static const struct pwm_ops mtk_pwm_ops = {
-+      .config = mtk_pwm_config,
-+      .enable = mtk_pwm_enable,
-+      .disable = mtk_pwm_disable,
-+      .owner = THIS_MODULE,
-+};
-+
-+static int mtk_pwm_probe(struct platform_device *pdev)
-+{
-+      struct mtk_pwm_chip *pc;
-+      struct resource *r;
-+      int ret;
-+
-+      pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-+      if (!pc)
-+              return -ENOMEM;
-+
-+      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-+      if (IS_ERR(pc->mmio_base))
-+              return PTR_ERR(pc->mmio_base);
-+
-+      pc->clk_main = devm_clk_get(&pdev->dev, "main");
-+        if (IS_ERR(pc->clk_main))
-+              return PTR_ERR(pc->clk_main);
-+
-+      pc->clk_top = devm_clk_get(&pdev->dev, "top");
-+        if (IS_ERR(pc->clk_top))
-+              return PTR_ERR(pc->clk_top);
-+
-+      pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1");
-+        if (IS_ERR(pc->clk_pwm[0]))
-+              return PTR_ERR(pc->clk_pwm[0]);
-+
-+      pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2");
-+        if (IS_ERR(pc->clk_pwm[1]))
-+              return PTR_ERR(pc->clk_pwm[1]);
-+
-+      pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3");
-+        if (IS_ERR(pc->clk_pwm[2]))
-+              return PTR_ERR(pc->clk_pwm[2]);
-+
-+      pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4");
-+        if (IS_ERR(pc->clk_pwm[3]))
-+              return PTR_ERR(pc->clk_pwm[3]);
-+
-+      pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5");
-+        if (IS_ERR(pc->clk_pwm[4]))
-+              return PTR_ERR(pc->clk_pwm[4]);
-+
-+      ret = clk_prepare(pc->clk_top);
-+        if (ret < 0)
-+              return ret;
-+
-+      ret = clk_prepare(pc->clk_main);
-+      if (ret < 0)
-+              goto disable_clk_top;
-+
-+      platform_set_drvdata(pdev, pc);
-+
-+      pc->chip.dev = &pdev->dev;
-+      pc->chip.ops = &mtk_pwm_ops;
-+      pc->chip.base = -1;
-+      pc->chip.npwm = NUM_PWM;
-+
-+      ret = pwmchip_add(&pc->chip);
-+      if (ret < 0) {
-+              dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
-+              goto disable_clk_main;
-+      }
-+
-+      return 0;
-+
-+disable_clk_main:
-+      clk_unprepare(pc->clk_main);
-+disable_clk_top:
-+      clk_unprepare(pc->clk_top);
-+
-+      return ret;
-+}
-+
-+static int mtk_pwm_remove(struct platform_device *pdev)
-+{
-+      struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
-+      int i;
-+
-+      for (i = 0; i < NUM_PWM; i++)
-+              pwm_disable(&pc->chip.pwms[i]);
-+
-+      return pwmchip_remove(&pc->chip);
-+}
-+
-+static const struct of_device_id mtk_pwm_of_match[] = {
-+      { .compatible = "mediatek,mt7623-pwm" },
-+      { }
-+};
-+
-+MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
-+
-+static struct platform_driver mtk_pwm_driver = {
-+      .driver = {
-+              .name = "mtk-pwm",
-+              .owner = THIS_MODULE,
-+              .of_match_table = mtk_pwm_of_match,
-+      },
-+      .probe = mtk_pwm_probe,
-+      .remove = mtk_pwm_remove,
-+};
-+
-+module_platform_driver(mtk_pwm_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
-+MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch
deleted file mode 100644 (file)
index f743e10..0000000
+++ /dev/null
@@ -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: sean.wang@mediatek.com
-X-Patchwork-Id: 9591021
-Message-Id: <1487962041-6548-5-git-send-email-sean.wang@mediatek.com>
-To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
- <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
- <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
- Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
- linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org
-Date: Sat, 25 Feb 2017 02:47:21 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-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 <sean.wang@mediatek.com>
----
- 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[] = {
diff --git a/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch
deleted file mode 100644 (file)
index dee31cd..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9633073
-Message-Id: <1489992447-13007-2-git-send-email-sean.wang@mediatek.com>
-To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
- <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
- <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
- Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
- linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org
-Date: Mon, 20 Mar 2017 14:47:24 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-This patch adds documentation for devicetree bindings for LED support on
-MT6323 PMIC.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
----
- .../devicetree/bindings/leds/leds-mt6323.txt       | 60 ++++++++++++++++++++++
- 1 file changed, 60 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt
-@@ -0,0 +1,60 @@
-+Device Tree Bindings for LED support on MT6323 PMIC
-+
-+MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED
-+controllers are defined as the subnode of the function node provided by MT6323
-+PMIC controller that is being defined as one kind of Muti-Function Device (MFD)
-+using shared bus called PMIC wrapper for each subfunction to access remote
-+MT6323 PMIC hardware.
-+
-+For MT6323 MFD bindings see:
-+Documentation/devicetree/bindings/mfd/mt6397.txt
-+For MediaTek PMIC wrapper bindings see:
-+Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
-+
-+Required properties:
-+- compatible : Must be "mediatek,mt6323-led"
-+- address-cells : Must be 1
-+- size-cells : Must be 0
-+
-+Each led is represented as a child node of the mediatek,mt6323-led that
-+describes the initial behavior for each LED physically and currently only four
-+LED child nodes can be supported.
-+
-+Required properties for the LED child node:
-+- reg : LED channel number (0..3)
-+
-+Optional properties for the LED child node:
-+- label : See Documentation/devicetree/bindings/leds/common.txt
-+- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt
-+- default-state: See Documentation/devicetree/bindings/leds/common.txt
-+
-+Example:
-+
-+      mt6323: pmic {
-+              compatible = "mediatek,mt6323";
-+
-+              ...
-+
-+              mt6323led: leds {
-+                      compatible = "mediatek,mt6323-led";
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+
-+                      led@0 {
-+                              reg = <0>;
-+                              label = "LED0";
-+                              linux,default-trigger = "timer";
-+                              default-state = "on";
-+                      };
-+                      led@1 {
-+                              reg = <1>;
-+                              label = "LED1";
-+                              default-state = "off";
-+                      };
-+                      led@2 {
-+                              reg = <2>;
-+                              label = "LED2";
-+                              default-state = "on";
-+                      };
-+              };
-+      };
diff --git a/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch
deleted file mode 100644 (file)
index 2edb4ba..0000000
+++ /dev/null
@@ -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: sean.wang@mediatek.com
-X-Patchwork-Id: 9633089
-Message-Id: <1489992447-13007-3-git-send-email-sean.wang@mediatek.com>
-To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
- <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
- <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
- Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
- linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org
-Date: Mon, 20 Mar 2017 14:47:25 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-This patch adds description for LED as the sub-module on MT6397/MT6323
-multifunction device.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
----
- 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.
diff --git a/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch
deleted file mode 100644 (file)
index f0d706c..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9633081
-Message-Id: <1489992447-13007-4-git-send-email-sean.wang@mediatek.com>
-To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
- <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
- <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
- Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
- linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org
-Date: Mon, 20 Mar 2017 14:47:26 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-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
-and/or blinked with the controller.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
-Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
----
- drivers/leds/Kconfig       |   8 +
- drivers/leds/Makefile      |   1 +
- drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 511 insertions(+)
- create mode 100644 drivers/leds/leds-mt6323.c
-
---- a/drivers/leds/Kconfig
-+++ b/drivers/leds/Kconfig
-@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532
-         This option enables support for the so called "User LED" of
-         Mikrotik's Routerboard 532.
-+config LEDS_MT6323
-+      tristate "LED Support for Mediatek MT6323 PMIC"
-+      depends on LEDS_CLASS
-+      depends on MFD_MT6397
-+      help
-+        This option enables support for on-chip LED drivers found on
-+        Mediatek MT6323 PMIC.
-+
- config LEDS_S3C24XX
-       tristate "LED Support for Samsung S3C24XX GPIO LEDs"
-       depends on LEDS_CLASS
---- /dev/null
-+++ b/drivers/leds/leds-mt6323.c
-@@ -0,0 +1,502 @@
-+/*
-+ * LED driver for Mediatek MT6323 PMIC
-+ *
-+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of
-+ * the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/leds.h>
-+#include <linux/mfd/mt6323/registers.h>
-+#include <linux/mfd/mt6397/core.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/regmap.h>
-+
-+/*
-+ * Register field for MT6323_TOP_CKPDN0 to enable
-+ * 32K clock common for LED device.
-+ */
-+#define MT6323_RG_DRV_32K_CK_PDN      BIT(11)
-+#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
-+
-+/*
-+ * Register field for MT6323_TOP_CKPDN2 to enable
-+ * individual clock for LED device.
-+ */
-+#define MT6323_RG_ISINK_CK_PDN(i)     BIT(i)
-+#define MT6323_RG_ISINK_CK_PDN_MASK(i)        BIT(i)
-+
-+/*
-+ * Register field for MT6323_TOP_CKCON1 to select
-+ * clock source.
-+ */
-+#define MT6323_RG_ISINK_CK_SEL_MASK(i)        (BIT(10) << (i))
-+
-+/*
-+ * Register for MT6323_ISINK_CON0 to setup the
-+ * duty cycle of the blink.
-+ */
-+#define MT6323_ISINK_CON0(i)          (MT6323_ISINK0_CON0 + 0x8 * (i))
-+#define MT6323_ISINK_DIM_DUTY_MASK    (0x1f << 8)
-+#define MT6323_ISINK_DIM_DUTY(i)      (((i) << 8) & \
-+                                      MT6323_ISINK_DIM_DUTY_MASK)
-+
-+/* Register to setup the period of the blink. */
-+#define MT6323_ISINK_CON1(i)          (MT6323_ISINK0_CON1 + 0x8 * (i))
-+#define MT6323_ISINK_DIM_FSEL_MASK    (0xffff)
-+#define MT6323_ISINK_DIM_FSEL(i)      ((i) & MT6323_ISINK_DIM_FSEL_MASK)
-+
-+/* Register to control the brightness. */
-+#define MT6323_ISINK_CON2(i)          (MT6323_ISINK0_CON2 + 0x8 * (i))
-+#define MT6323_ISINK_CH_STEP_SHIFT    12
-+#define MT6323_ISINK_CH_STEP_MASK     (0x7 << 12)
-+#define MT6323_ISINK_CH_STEP(i)               (((i) << 12) & \
-+                                      MT6323_ISINK_CH_STEP_MASK)
-+#define MT6323_ISINK_SFSTR0_TC_MASK   (0x3 << 1)
-+#define MT6323_ISINK_SFSTR0_TC(i)     (((i) << 1) & \
-+                                      MT6323_ISINK_SFSTR0_TC_MASK)
-+#define MT6323_ISINK_SFSTR0_EN_MASK   BIT(0)
-+#define MT6323_ISINK_SFSTR0_EN                BIT(0)
-+
-+/* Register to LED channel enablement. */
-+#define MT6323_ISINK_CH_EN_MASK(i)    BIT(i)
-+#define MT6323_ISINK_CH_EN(i)         BIT(i)
-+
-+#define MT6323_MAX_PERIOD             10000
-+#define MT6323_MAX_LEDS                       4
-+#define MT6323_MAX_BRIGHTNESS         6
-+#define MT6323_UNIT_DUTY              3125
-+#define MT6323_CAL_HW_DUTY(o, p)      DIV_ROUND_CLOSEST((o) * 100000ul,\
-+                                      (p) * MT6323_UNIT_DUTY)
-+
-+struct mt6323_leds;
-+
-+/**
-+ * struct mt6323_led - state container for the LED device
-+ * @id:                       the identifier in MT6323 LED device
-+ * @parent:           the pointer to MT6323 LED controller
-+ * @cdev:             LED class device for this LED device
-+ * @current_brightness: current state of the LED device
-+ */
-+struct mt6323_led {
-+      int                     id;
-+      struct mt6323_leds      *parent;
-+      struct led_classdev     cdev;
-+      enum led_brightness     current_brightness;
-+};
-+
-+/**
-+ * struct mt6323_leds -       state container for holding LED controller
-+ *                    of the driver
-+ * @dev:              the device pointer
-+ * @hw:                       the underlying hardware providing shared
-+ *                    bus for the register operations
-+ * @lock:             the lock among process context
-+ * @led:              the array that contains the state of individual
-+ *                    LED device
-+ */
-+struct mt6323_leds {
-+      struct device           *dev;
-+      struct mt6397_chip      *hw;
-+      /* protect among process context */
-+      struct mutex            lock;
-+      struct mt6323_led       *led[MT6323_MAX_LEDS];
-+};
-+
-+static int mt6323_led_hw_brightness(struct led_classdev *cdev,
-+                                  enum led_brightness brightness)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      struct regmap *regmap = leds->hw->regmap;
-+      u32 con2_mask = 0, con2_val = 0;
-+      int ret;
-+
-+      /*
-+       * Setup current output for the corresponding
-+       * brightness level.
-+       */
-+      con2_mask |= MT6323_ISINK_CH_STEP_MASK |
-+                   MT6323_ISINK_SFSTR0_TC_MASK |
-+                   MT6323_ISINK_SFSTR0_EN_MASK;
-+      con2_val |=  MT6323_ISINK_CH_STEP(brightness - 1) |
-+                   MT6323_ISINK_SFSTR0_TC(2) |
-+                   MT6323_ISINK_SFSTR0_EN;
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
-+                               con2_mask, con2_val);
-+      return ret;
-+}
-+
-+static int mt6323_led_hw_off(struct led_classdev *cdev)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      struct regmap *regmap = leds->hw->regmap;
-+      unsigned int status;
-+      int ret;
-+
-+      status = MT6323_ISINK_CH_EN(led->id);
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
-+                               MT6323_ISINK_CH_EN_MASK(led->id), ~status);
-+      if (ret < 0)
-+              return ret;
-+
-+      usleep_range(100, 300);
-+      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
-+                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
-+                               MT6323_RG_ISINK_CK_PDN(led->id));
-+      if (ret < 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static enum led_brightness
-+mt6323_get_led_hw_brightness(struct led_classdev *cdev)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      struct regmap *regmap = leds->hw->regmap;
-+      unsigned int status;
-+      int ret;
-+
-+      ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
-+      if (ret < 0)
-+              return ret;
-+
-+      if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
-+              return 0;
-+
-+      ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
-+      if (ret < 0)
-+              return ret;
-+
-+      if (!(status & MT6323_ISINK_CH_EN(led->id)))
-+              return 0;
-+
-+      ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
-+      if (ret < 0)
-+              return ret;
-+
-+      return  ((status & MT6323_ISINK_CH_STEP_MASK)
-+                >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
-+}
-+
-+static int mt6323_led_hw_on(struct led_classdev *cdev,
-+                          enum led_brightness brightness)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      struct regmap *regmap = leds->hw->regmap;
-+      unsigned int status;
-+      int ret;
-+
-+      /*
-+       * Setup required clock source, enable the corresponding
-+       * clock and channel and let work with continuous blink as
-+       * the default.
-+       */
-+      ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
-+                               MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
-+      if (ret < 0)
-+              return ret;
-+
-+      status = MT6323_RG_ISINK_CK_PDN(led->id);
-+      ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
-+                               MT6323_RG_ISINK_CK_PDN_MASK(led->id),
-+                               ~status);
-+      if (ret < 0)
-+              return ret;
-+
-+      usleep_range(100, 300);
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
-+                               MT6323_ISINK_CH_EN_MASK(led->id),
-+                               MT6323_ISINK_CH_EN(led->id));
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = mt6323_led_hw_brightness(cdev, brightness);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
-+                               MT6323_ISINK_DIM_DUTY_MASK,
-+                               MT6323_ISINK_DIM_DUTY(31));
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
-+                               MT6323_ISINK_DIM_FSEL_MASK,
-+                               MT6323_ISINK_DIM_FSEL(1000));
-+      if (ret < 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static int mt6323_led_set_blink(struct led_classdev *cdev,
-+                              unsigned long *delay_on,
-+                              unsigned long *delay_off)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      struct regmap *regmap = leds->hw->regmap;
-+      unsigned long period;
-+      u8 duty_hw;
-+      int ret;
-+
-+      /*
-+       * Units are in ms, if over the hardware able
-+       * to support, fallback into software blink
-+       */
-+      period = *delay_on + *delay_off;
-+
-+      if (period > MT6323_MAX_PERIOD)
-+              return -EINVAL;
-+
-+      /*
-+       * LED subsystem requires a default user
-+       * friendly blink pattern for the LED so using
-+       * 1Hz duty cycle 50% here if without specific
-+       * value delay_on and delay off being assigned.
-+       */
-+      if (!*delay_on && !*delay_off) {
-+              *delay_on = 500;
-+              *delay_off = 500;
-+      }
-+
-+      /*
-+       * Calculate duty_hw based on the percentage of period during
-+       * which the led is ON.
-+       */
-+      duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
-+
-+      /* hardware doesn't support zero duty cycle. */
-+      if (!duty_hw)
-+              return -EINVAL;
-+
-+      mutex_lock(&leds->lock);
-+      /*
-+       * Set max_brightness as the software blink behavior
-+       * when no blink brightness.
-+       */
-+      if (!led->current_brightness) {
-+              ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
-+              if (ret < 0)
-+                      goto out;
-+              led->current_brightness = cdev->max_brightness;
-+      }
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
-+                               MT6323_ISINK_DIM_DUTY_MASK,
-+                               MT6323_ISINK_DIM_DUTY(duty_hw - 1));
-+      if (ret < 0)
-+              goto out;
-+
-+      ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
-+                               MT6323_ISINK_DIM_FSEL_MASK,
-+                               MT6323_ISINK_DIM_FSEL(period - 1));
-+out:
-+      mutex_unlock(&leds->lock);
-+
-+      return ret;
-+}
-+
-+static int mt6323_led_set_brightness(struct led_classdev *cdev,
-+                                   enum led_brightness brightness)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      struct mt6323_leds *leds = led->parent;
-+      int ret;
-+
-+      mutex_lock(&leds->lock);
-+
-+      if (!led->current_brightness && brightness) {
-+              ret = mt6323_led_hw_on(cdev, brightness);
-+              if (ret < 0)
-+                      goto out;
-+      } else if (brightness) {
-+              ret = mt6323_led_hw_brightness(cdev, brightness);
-+              if (ret < 0)
-+                      goto out;
-+      } else {
-+              ret = mt6323_led_hw_off(cdev);
-+              if (ret < 0)
-+                      goto out;
-+      }
-+
-+      led->current_brightness = brightness;
-+out:
-+      mutex_unlock(&leds->lock);
-+
-+      return ret;
-+}
-+
-+static int mt6323_led_set_dt_default(struct led_classdev *cdev,
-+                                   struct device_node *np)
-+{
-+      struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
-+      const char *state;
-+      int ret = 0;
-+
-+      led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
-+      led->cdev.default_trigger = of_get_property(np,
-+                                                  "linux,default-trigger",
-+                                                  NULL);
-+
-+      state = of_get_property(np, "default-state", NULL);
-+      if (state) {
-+              if (!strcmp(state, "keep")) {
-+                      ret = mt6323_get_led_hw_brightness(cdev);
-+                      if (ret < 0)
-+                              return ret;
-+                      led->current_brightness = ret;
-+                      ret = 0;
-+              } else if (!strcmp(state, "on")) {
-+                      ret =
-+                      mt6323_led_set_brightness(cdev, cdev->max_brightness);
-+              } else  {
-+                      ret = mt6323_led_set_brightness(cdev, LED_OFF);
-+              }
-+      }
-+
-+      return ret;
-+}
-+
-+static int mt6323_led_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct device_node *np = pdev->dev.of_node;
-+      struct device_node *child;
-+      struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent);
-+      struct mt6323_leds *leds;
-+      struct mt6323_led *led;
-+      int ret;
-+      unsigned int status;
-+      u32 reg;
-+
-+      leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
-+      if (!leds)
-+              return -ENOMEM;
-+
-+      platform_set_drvdata(pdev, leds);
-+      leds->dev = dev;
-+
-+      /*
-+       * leds->hw points to the underlying bus for the register
-+       * controlled.
-+       */
-+      leds->hw = hw;
-+      mutex_init(&leds->lock);
-+
-+      status = MT6323_RG_DRV_32K_CK_PDN;
-+      ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
-+                               MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
-+      if (ret < 0) {
-+              dev_err(leds->dev,
-+                      "Failed to update MT6323_TOP_CKPDN0 Register\n");
-+              return ret;
-+      }
-+
-+      for_each_available_child_of_node(np, child) {
-+              ret = of_property_read_u32(child, "reg", &reg);
-+              if (ret) {
-+                      dev_err(dev, "Failed to read led 'reg' property\n");
-+                      goto put_child_node;
-+              }
-+
-+              if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) {
-+                      dev_err(dev, "Invalid led reg %u\n", reg);
-+                      ret = -EINVAL;
-+                      goto put_child_node;
-+              }
-+
-+              led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
-+              if (!led) {
-+                      ret = -ENOMEM;
-+                      goto put_child_node;
-+              }
-+
-+              leds->led[reg] = led;
-+              leds->led[reg]->id = reg;
-+              leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
-+              leds->led[reg]->cdev.brightness_set_blocking =
-+                                      mt6323_led_set_brightness;
-+              leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
-+              leds->led[reg]->cdev.brightness_get =
-+                                      mt6323_get_led_hw_brightness;
-+              leds->led[reg]->parent = leds;
-+
-+              ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
-+              if (ret < 0) {
-+                      dev_err(leds->dev,
-+                              "Failed to LED set default from devicetree\n");
-+                      goto put_child_node;
-+              }
-+
-+              ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev);
-+              if (ret) {
-+                      dev_err(&pdev->dev, "Failed to register LED: %d\n",
-+                              ret);
-+                      goto put_child_node;
-+              }
-+              leds->led[reg]->cdev.dev->of_node = child;
-+      }
-+
-+      return 0;
-+
-+put_child_node:
-+      of_node_put(child);
-+      return ret;
-+}
-+
-+static int mt6323_led_remove(struct platform_device *pdev)
-+{
-+      struct mt6323_leds *leds = platform_get_drvdata(pdev);
-+      int i;
-+
-+      /* Turn the LEDs off on driver removal. */
-+      for (i = 0 ; leds->led[i] ; i++)
-+              mt6323_led_hw_off(&leds->led[i]->cdev);
-+
-+      regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
-+                         MT6323_RG_DRV_32K_CK_PDN_MASK,
-+                         MT6323_RG_DRV_32K_CK_PDN);
-+
-+      mutex_destroy(&leds->lock);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id mt6323_led_dt_match[] = {
-+      { .compatible = "mediatek,mt6323-led" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
-+
-+static struct platform_driver mt6323_led_driver = {
-+      .probe          = mt6323_led_probe,
-+      .remove         = mt6323_led_remove,
-+      .driver         = {
-+              .name   = "mt6323-led",
-+              .of_match_table = mt6323_led_dt_match,
-+      },
-+};
-+
-+module_platform_driver(mt6323_led_driver);
-+
-+MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
-+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch
deleted file mode 100644 (file)
index 888218b..0000000
+++ /dev/null
@@ -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: sean.wang@mediatek.com
-X-Patchwork-Id: 9633079
-Message-Id: <1489992447-13007-5-git-send-email-sean.wang@mediatek.com>
-To: <rpurdie@rpsys.net>, <jacek.anaszewski@gmail.com>, <lee.jones@linaro.org>, 
- <matthias.bgg@gmail.com>, <pavel@ucw.cz>, <robh+dt@kernel.org>,
- <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, keyhaede@gmail.com,
- Sean Wang <sean.wang@mediatek.com>, linux-kernel@vger.kernel.org,
- linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org
-Date: Mon, 20 Mar 2017 14:47:27 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-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 <sean.wang@mediatek.com>
-Acked-by: Lee Jones <lee.jones@linaro.org>
----
- 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"
-       },
diff --git a/target/linux/mediatek/patches-4.9/0091-dsa1.patch b/target/linux/mediatek/patches-4.9/0091-dsa1.patch
deleted file mode 100644 (file)
index ffc63dc..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9651093
-Message-Id: <1490780303-18598-2-git-send-email-sean.wang@mediatek.com>
-To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
- <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
- <robh+dt@kernel.org>, <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
- netdev@vger.kernel.org, sean.wang@mediatek.com,
- linux-kernel@vger.kernel.org, 
- linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
-Date: Wed, 29 Mar 2017 17:38:19 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-Add device-tree binding for Mediatek MT7530 switch.
-
-Cc: devicetree@vger.kernel.org
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
-Acked-by: Rob Herring <robh@kernel.org>
----
- .../devicetree/bindings/net/dsa/mt7530.txt         | 92 ++++++++++++++++++++++
- 1 file changed, 92 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt
-@@ -0,0 +1,92 @@
-+Mediatek MT7530 Ethernet switch
-+================================
-+
-+Required properties:
-+
-+- compatible: Must be compatible = "mediatek,mt7530";
-+- #address-cells: Must be 1.
-+- #size-cells: Must be 0.
-+- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
-+      on multi-chip module belong to MT7623A has or the remotely standalone
-+      chip as the function MT7623N reference board provided for.
-+- core-supply: Phandle to the regulator node necessary for the core power.
-+- io-supply: Phandle to the regulator node necessary for the I/O power.
-+      See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-+      for details for the regulator setup on these boards.
-+
-+If the property mediatek,mcm isn't defined, following property is required
-+
-+- reset-gpios: Should be a gpio specifier for a reset line.
-+
-+Else, following properties are required
-+
-+- resets : Phandle pointing to the system reset controller with
-+      line index for the ethsys.
-+- reset-names : Should be set to "mcm".
-+
-+Required properties for the child nodes within ports container:
-+
-+- reg: Port address described must be 6 for CPU port and from 0 to 5 for
-+      user ports.
-+- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
-+       "cpu".
-+
-+See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional
-+required, optional properties and how the integrated switch subnodes must
-+be specified.
-+
-+Example:
-+
-+      &mdio0 {
-+              switch@0 {
-+                      compatible = "mediatek,mt7530";
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+                      reg = <0>;
-+
-+                      core-supply = <&mt6323_vpa_reg>;
-+                      io-supply = <&mt6323_vemc3v3_reg>;
-+                      reset-gpios = <&pio 33 0>;
-+
-+                      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@4 {
-+                                      reg = <4>;
-+                                      label = "wan";
-+                              };
-+
-+                              port@6 {
-+                                      reg = <6>;
-+                                      label = "cpu";
-+                                      ethernet = <&gmac0>;
-+                                      phy-mode = "trgmii";
-+                                      fixed-link {
-+                                              speed = <1000>;
-+                                              full-duplex;
-+                                      };
-+                              };
-+                      };
-+              };
-+      };
diff --git a/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch
deleted file mode 100644 (file)
index 6e65d27..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
-From: John Crispin <john@phrozen.org>
-Date: Sat, 23 Apr 2016 11:57:21 +0200
-Subject: [PATCH 081/102] net-next: mediatek: fix DQL support
-
-The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The
-current code will assign the TX traffic of each MAC to its own DQL. This
-results in the amount of data, that DQL says is in the queue incorrect. As
-the data from multiple devices is infact enqueued. This makes any decision
-based on these value non deterministic. Fix this by tracking all TX
-traffic, regardless of the MAC it belongs to in the DQL of all devices
-using the DMA.
-
-Signed-off-by: John Crispin <john@phrozen.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c |   33 ++++++++++++++++-----------
- 1 file changed, 20 insertions(+), 13 deletions(-)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -706,7 +706,16 @@ static int mtk_tx_map(struct sk_buff *sk
-       WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
-                               (!nr_frags * TX_DMA_LS0)));
--      netdev_sent_queue(dev, skb->len);
-+      /* we have a single DMA ring so BQL needs to be updated for all devices
-+       * sitting on this ring
-+       */
-+      for (i = 0; i < MTK_MAC_COUNT; i++) {
-+              if (!eth->netdev[i])
-+                      continue;
-+
-+              netdev_sent_queue(eth->netdev[i], skb->len);
-+      }
-+
-       skb_tx_timestamp(skb);
-       ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-@@ -998,21 +1007,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;
--      unsigned int done[MTK_MAX_DEVS];
--      unsigned int bytes[MTK_MAX_DEVS];
-+      int total = 0, done = 0;
-+      unsigned int bytes = 0;
-       u32 cpu, dma;
-       static int condition;
--      int total = 0, i;
--
--      memset(done, 0, sizeof(done));
--      memset(bytes, 0, sizeof(bytes));
-+      int i;
-       cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
-       dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
-       desc = mtk_qdma_phys_to_virt(ring, cpu);
--      while ((cpu != dma) && budget) {
-+      while ((cpu != dma) && done < budget) {
-               u32 next_cpu = desc->txd2;
-               int mac;
-@@ -1032,9 +1038,8 @@ static int mtk_poll_tx(struct mtk_eth *e
-               }
-               if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
--                      bytes[mac] += skb->len;
--                      done[mac]++;
--                      budget--;
-+                      bytes += skb->len;
-+                      done++;
-               }
-               mtk_tx_unmap(eth, tx_buf);
-@@ -1046,11 +1051,13 @@ static int mtk_poll_tx(struct mtk_eth *e
-       mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
-+      /* we have a single DMA ring so BQL needs to be updated for all devices
-+       * sitting on this ring
-+       */
-       for (i = 0; i < MTK_MAC_COUNT; i++) {
--              if (!eth->netdev[i] || !done[i])
-+              if (!eth->netdev[i])
-                       continue;
--              netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
--              total += done[i];
-+              netdev_completed_queue(eth->netdev[i], done, bytes);
-       }
-       if (mtk_queue_stopped(eth) &&
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa2.patch b/target/linux/mediatek/patches-4.9/0092-dsa2.patch
deleted file mode 100644 (file)
index a5b4242..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9651099
-Message-Id: <1490780303-18598-3-git-send-email-sean.wang@mediatek.com>
-To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
- <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
- <robh+dt@kernel.org>, <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
- netdev@vger.kernel.org, sean.wang@mediatek.com,
- linux-kernel@vger.kernel.org, 
- linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
-Date: Wed, 29 Mar 2017 17:38:20 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-Add the support for the 4-bytes tag for DSA port distinguishing inserted
-allowing receiving and transmitting the packet via the particular port.
-The tag is being added after the source MAC address in the ethernet
-header.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
-Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
----
- include/net/dsa.h  |   1 +
- net/dsa/Kconfig    |   2 +
- net/dsa/Makefile   |   1 +
- net/dsa/dsa.c      |   3 ++
- net/dsa/dsa_priv.h |   3 ++
- net/dsa/tag_mtk.c  | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 6 files changed, 127 insertions(+)
- create mode 100644 net/dsa/tag_mtk.c
-
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -27,6 +27,7 @@ enum dsa_tag_protocol {
-       DSA_TAG_PROTO_EDSA,
-       DSA_TAG_PROTO_BRCM,
-       DSA_TAG_PROTO_QCA,
-+      DSA_TAG_PROTO_MTK,
-       DSA_TAG_LAST,           /* MUST BE LAST */
- };
---- a/net/dsa/Kconfig
-+++ b/net/dsa/Kconfig
-@@ -41,4 +41,6 @@ config NET_DSA_TAG_TRAILER
- config NET_DSA_TAG_QCA
-       bool
-+config NET_DSA_TAG_MTK
-+      bool
- endif
---- a/net/dsa/Makefile
-+++ b/net/dsa/Makefile
-@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += ta
- dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
- dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
- dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
-+dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
---- a/net/dsa/dsa.c
-+++ b/net/dsa/dsa.c
-@@ -57,6 +57,9 @@ const struct dsa_device_ops *dsa_device_
- #ifdef CONFIG_NET_DSA_TAG_QCA
-       [DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
- #endif
-+#ifdef CONFIG_NET_DSA_TAG_MTK
-+      [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops,
-+#endif
-       [DSA_TAG_PROTO_NONE] = &none_ops,
- };
---- a/net/dsa/dsa_priv.h
-+++ b/net/dsa/dsa_priv.h
-@@ -84,4 +84,7 @@ extern const struct dsa_device_ops brcm_
- /* tag_qca.c */
- extern const struct dsa_device_ops qca_netdev_ops;
-+/* tag_mtk.c */
-+extern const struct dsa_device_ops mtk_netdev_ops;
-+
- #endif
---- /dev/null
-+++ b/net/dsa/tag_mtk.c
-@@ -0,0 +1,117 @@
-+/*
-+ * Mediatek DSA Tag support
-+ * Copyright (C) 2017 Landen Chao <landen.chao@mediatek.com>
-+ *                  Sean Wang <sean.wang@mediatek.com>
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/etherdevice.h>
-+#include "dsa_priv.h"
-+
-+#define MTK_HDR_LEN           4
-+#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0)
-+#define MTK_HDR_XMIT_DP_BIT_MASK      GENMASK(5, 0)
-+
-+static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,
-+                                  struct net_device *dev)
-+{
-+      struct dsa_slave_priv *p = netdev_priv(dev);
-+      u8 *mtk_tag;
-+
-+      if (skb_cow_head(skb, MTK_HDR_LEN) < 0)
-+              goto out_free;
-+
-+      skb_push(skb, MTK_HDR_LEN);
-+
-+      memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN);
-+
-+      /* Build the tag after the MAC Source Address */
-+      mtk_tag = skb->data + 2 * ETH_ALEN;
-+      mtk_tag[0] = 0;
-+      mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
-+      mtk_tag[2] = 0;
-+      mtk_tag[3] = 0;
-+
-+      return skb;
-+
-+out_free:
-+      kfree_skb(skb);
-+      return NULL;
-+}
-+
-+static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
-+                     struct packet_type *pt, struct net_device *orig_dev)
-+{
-+      struct dsa_switch_tree *dst = dev->dsa_ptr;
-+      struct dsa_switch *ds;
-+      int port;
-+      __be16 *phdr, hdr;
-+
-+      if (unlikely(!dst))
-+              goto out_drop;
-+
-+      skb = skb_unshare(skb, GFP_ATOMIC);
-+      if (!skb)
-+              goto out;
-+
-+      if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
-+              goto out_drop;
-+
-+      /* The MTK header is added by the switch between src addr
-+       * and ethertype at this point, skb->data points to 2 bytes
-+       * after src addr so header should be 2 bytes right before.
-+       */
-+      phdr = (__be16 *)(skb->data - 2);
-+      hdr = ntohs(*phdr);
-+
-+      /* Remove MTK tag and recalculate checksum. */
-+      skb_pull_rcsum(skb, MTK_HDR_LEN);
-+
-+      memmove(skb->data - ETH_HLEN,
-+              skb->data - ETH_HLEN - MTK_HDR_LEN,
-+              2 * ETH_ALEN);
-+
-+      /* This protocol doesn't support cascading multiple
-+       * switches so it's safe to assume the switch is first
-+       * in the tree.
-+       */
-+      ds = dst->ds[0];
-+      if (!ds)
-+              goto out_drop;
-+
-+      /* Get source port information */
-+      port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
-+      if (!ds->ports[port].netdev)
-+              goto out_drop;
-+
-+      /* Update skb & forward the frame accordingly */
-+      skb_push(skb, ETH_HLEN);
-+
-+      skb->pkt_type = PACKET_HOST;
-+      skb->dev = ds->ports[port].netdev;
-+      skb->protocol = eth_type_trans(skb, skb->dev);
-+
-+      skb->dev->stats.rx_packets++;
-+      skb->dev->stats.rx_bytes += skb->len;
-+
-+      netif_receive_skb(skb);
-+
-+      return 0;
-+
-+out_drop:
-+      kfree_skb(skb);
-+out:
-+      return 0;
-+}
-+
-+const struct dsa_device_ops mtk_netdev_ops = {
-+      .xmit   = mtk_tag_xmit,
-+      .rcv    = mtk_tag_rcv,
-+};
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa3.patch b/target/linux/mediatek/patches-4.9/0092-dsa3.patch
deleted file mode 100644 (file)
index 385add1..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9651091
-Message-Id: <1490780303-18598-4-git-send-email-sean.wang@mediatek.com>
-To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
- <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
- <robh+dt@kernel.org>, <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
- netdev@vger.kernel.org, sean.wang@mediatek.com,
- linux-kernel@vger.kernel.org, 
- linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
-Date: Wed, 29 Mar 2017 17:38:21 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-The patch adds the setup for allowing CDM can recognize these packets with
-carrying port-distinguishing tag. Otherwise, these tagging packets will be
-handled incorrectly by CDM. The setup is also working out for general
-untag packets as well.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
-Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++
- 2 files changed, 10 insertions(+)
-
---- 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));
-+      /* 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);
---- 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
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa4.patch b/target/linux/mediatek/patches-4.9/0092-dsa4.patch
deleted file mode 100644 (file)
index 4daebfb..0000000
+++ /dev/null
@@ -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: sean.wang@mediatek.com
-X-Patchwork-Id: 9651097
-Message-Id: <1490780303-18598-5-git-send-email-sean.wang@mediatek.com>
-To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
- <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
- <robh+dt@kernel.org>, <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
- netdev@vger.kernel.org, sean.wang@mediatek.com,
- linux-kernel@vger.kernel.org, 
- linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
-Date: Wed, 29 Mar 2017 17:38:22 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-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 <sean.wang@mediatek.com>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++
- 1 file changed, 2 insertions(+)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -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:
diff --git a/target/linux/mediatek/patches-4.9/0092-dsa5.patch b/target/linux/mediatek/patches-4.9/0092-dsa5.patch
deleted file mode 100644 (file)
index 63a40d0..0000000
+++ /dev/null
@@ -1,1598 +0,0 @@
-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: sean.wang@mediatek.com
-X-Patchwork-Id: 9651095
-Message-Id: <1490780303-18598-6-git-send-email-sean.wang@mediatek.com>
-To: <andrew@lunn.ch>, <f.fainelli@gmail.com>,
- <vivien.didelot@savoirfairelinux.com>, <matthias.bgg@gmail.com>,
- <robh+dt@kernel.org>, <mark.rutland@arm.com>
-Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, 
- netdev@vger.kernel.org, sean.wang@mediatek.com,
- linux-kernel@vger.kernel.org, 
- linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net
-Date: Wed, 29 Mar 2017 17:38:23 +0800
-
-From: Sean Wang <sean.wang@mediatek.com>
-
-MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on
-Mediatek router platforms such as MT7623A or MT7623N platform which
-includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY.
-Among these ports, The port from 0 to 4 are the user ports connecting
-with the remote devices while the port 5 and 6 are the CPU ports
-connecting into Mediatek Ethernet GMAC.
-
-For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC
-through either the TRGMII or RGMII which could be controlled by phy-mode
-in the dt-bindings to specify which mode is preferred to use. And for
-port 5, only RGMII can be specified. However, currently, only port 6 is
-being supported in this DSA driver.
-
-The driver is made with the reference to qca8k and other existing DSA
-driver. The most of the essential callbacks of the DSA are already
-support in the driver, including tag insert for user port distinguishing,
-port control, bridge offloading, STP setup and ethtool operation to allow
-DSA to model each user port into a standalone netdevice as the other DSA
-driver had done.
-
-Signed-off-by: Sean Wang <sean.wang@mediatek.com>
-Signed-off-by: Landen Chao <Landen.Chao@mediatek.com>
----
- drivers/net/dsa/Kconfig  |    8 +
- drivers/net/dsa/Makefile |    2 +-
- drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++
- drivers/net/dsa/mt7530.h |  390 ++++++++++++++++
- 4 files changed, 1525 insertions(+), 1 deletion(-)
- create mode 100644 drivers/net/dsa/mt7530.c
- create mode 100644 drivers/net/dsa/mt7530.h
-
---- a/drivers/net/dsa/Kconfig
-+++ b/drivers/net/dsa/Kconfig
-@@ -34,4 +34,12 @@ config NET_DSA_QCA8K
-         This enables support for the Qualcomm Atheros QCA8K Ethernet
-         switch chips.
-+config NET_DSA_MT7530
-+      tristate "Mediatek MT7530 Ethernet switch support"
-+      depends on NET_DSA
-+      select NET_DSA_TAG_MTK
-+      ---help---
-+        This enables support for the Mediatek MT7530 Ethernet switch
-+        chip.
-+
- endmenu
---- a/drivers/net/dsa/Makefile
-+++ b/drivers/net/dsa/Makefile
-@@ -1,6 +1,6 @@
- obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
- obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o
- obj-$(CONFIG_NET_DSA_QCA8K)   += qca8k.o
--
-+obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
- obj-y                         += b53/
- obj-y                         += mv88e6xxx/
---- /dev/null
-+++ b/drivers/net/dsa/mt7530.c
-@@ -0,0 +1,1126 @@
-+/*
-+ * Mediatek MT7530 DSA Switch driver
-+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+#include <linux/etherdevice.h>
-+#include <linux/if_bridge.h>
-+#include <linux/iopoll.h>
-+#include <linux/mdio.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/of_gpio.h>
-+#include <linux/of_mdio.h>
-+#include <linux/of_net.h>
-+#include <linux/of_platform.h>
-+#include <linux/phy.h>
-+#include <linux/regmap.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/reset.h>
-+#include <net/dsa.h>
-+#include <net/switchdev.h>
-+
-+#include "mt7530.h"
-+
-+/* String, offset, and register size in bytes if different from 4 bytes */
-+static const struct mt7530_mib_desc mt7530_mib[] = {
-+      MIB_DESC(1, 0x00, "TxDrop"),
-+      MIB_DESC(1, 0x04, "TxCrcErr"),
-+      MIB_DESC(1, 0x08, "TxUnicast"),
-+      MIB_DESC(1, 0x0c, "TxMulticast"),
-+      MIB_DESC(1, 0x10, "TxBroadcast"),
-+      MIB_DESC(1, 0x14, "TxCollision"),
-+      MIB_DESC(1, 0x18, "TxSingleCollision"),
-+      MIB_DESC(1, 0x1c, "TxMultipleCollision"),
-+      MIB_DESC(1, 0x20, "TxDeferred"),
-+      MIB_DESC(1, 0x24, "TxLateCollision"),
-+      MIB_DESC(1, 0x28, "TxExcessiveCollistion"),
-+      MIB_DESC(1, 0x2c, "TxPause"),
-+      MIB_DESC(1, 0x30, "TxPktSz64"),
-+      MIB_DESC(1, 0x34, "TxPktSz65To127"),
-+      MIB_DESC(1, 0x38, "TxPktSz128To255"),
-+      MIB_DESC(1, 0x3c, "TxPktSz256To511"),
-+      MIB_DESC(1, 0x40, "TxPktSz512To1023"),
-+      MIB_DESC(1, 0x44, "Tx1024ToMax"),
-+      MIB_DESC(2, 0x48, "TxBytes"),
-+      MIB_DESC(1, 0x60, "RxDrop"),
-+      MIB_DESC(1, 0x64, "RxFiltering"),
-+      MIB_DESC(1, 0x6c, "RxMulticast"),
-+      MIB_DESC(1, 0x70, "RxBroadcast"),
-+      MIB_DESC(1, 0x74, "RxAlignErr"),
-+      MIB_DESC(1, 0x78, "RxCrcErr"),
-+      MIB_DESC(1, 0x7c, "RxUnderSizeErr"),
-+      MIB_DESC(1, 0x80, "RxFragErr"),
-+      MIB_DESC(1, 0x84, "RxOverSzErr"),
-+      MIB_DESC(1, 0x88, "RxJabberErr"),
-+      MIB_DESC(1, 0x8c, "RxPause"),
-+      MIB_DESC(1, 0x90, "RxPktSz64"),
-+      MIB_DESC(1, 0x94, "RxPktSz65To127"),
-+      MIB_DESC(1, 0x98, "RxPktSz128To255"),
-+      MIB_DESC(1, 0x9c, "RxPktSz256To511"),
-+      MIB_DESC(1, 0xa0, "RxPktSz512To1023"),
-+      MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"),
-+      MIB_DESC(2, 0xa8, "RxBytes"),
-+      MIB_DESC(1, 0xb0, "RxCtrlDrop"),
-+      MIB_DESC(1, 0xb4, "RxIngressDrop"),
-+      MIB_DESC(1, 0xb8, "RxArlDrop"),
-+};
-+
-+static struct mt7530_priv *lpriv;
-+static void mt7530_port_disable(struct dsa_switch *ds, int port,
-+                              struct phy_device *phy);
-+static int mt7530_cpu_port_enable(struct mt7530_priv *priv,
-+                                int port);
-+
-+static int
-+mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
-+{
-+      int ret;
-+
-+      ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
-+      if (ret < 0)
-+              dev_err(priv->dev,
-+                      "failed to priv write register\n");
-+      return ret;
-+}
-+
-+static u32
-+mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
-+{
-+      int ret;
-+      u32 val;
-+
-+      ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
-+      if (ret < 0) {
-+              dev_err(priv->dev,
-+                      "failed to priv read register\n");
-+              return ret;
-+      }
-+
-+      return val;
-+}
-+
-+static void
-+mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
-+                u32 mask, u32 set)
-+{
-+      u32 val;
-+
-+      val = mt7623_trgmii_read(priv, reg);
-+      val &= ~mask;
-+      val |= set;
-+      mt7623_trgmii_write(priv, reg, val);
-+}
-+
-+static void
-+mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      mt7623_trgmii_rmw(priv, reg, 0, val);
-+}
-+
-+static void
-+mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      mt7623_trgmii_rmw(priv, reg, val, 0);
-+}
-+
-+static int
-+core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      int value, ret;
-+
-+      /* Write the desired MMD Devad */
-+      ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Write the desired MMD register address */
-+      ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Select the Function : DATA with no post increment */
-+      ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Read the content of the MMD's selected register */
-+      value = bus->read(bus, 0, MII_MMD_DATA);
-+
-+      return value;
-+err:
-+      dev_err(&bus->dev,  "failed to read mmd register\n");
-+
-+      return ret;
-+}
-+
-+static int
-+core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
-+                      int devad, u32 data)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      int ret;
-+
-+      /* Write the desired MMD Devad */
-+      ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Write the desired MMD register address */
-+      ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Select the Function : DATA with no post increment */
-+      ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
-+      if (ret < 0)
-+              goto err;
-+
-+      /* Write the data into MMD's selected register */
-+      ret = bus->write(bus, 0, MII_MMD_DATA, data);
-+err:
-+      if (ret < 0)
-+              dev_err(&bus->dev,
-+                      "failed to write mmd register\n");
-+      return ret;
-+}
-+
-+static void
-+core_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      struct mii_bus *bus = priv->bus;
-+
-+      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+      core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
-+
-+      mutex_unlock(&bus->mdio_lock);
-+}
-+
-+static void
-+core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      u32 val;
-+
-+      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+      val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
-+      val &= ~mask;
-+      val |= set;
-+      core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
-+
-+      mutex_unlock(&bus->mdio_lock);
-+}
-+
-+static void
-+core_set(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      core_rmw(priv, reg, 0, val);
-+}
-+
-+static void
-+core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      core_rmw(priv, reg, val, 0);
-+}
-+
-+static int
-+mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      u16 page, r, lo, hi;
-+      int ret;
-+
-+      page = (reg >> 6) & 0x3ff;
-+      r  = (reg >> 2) & 0xf;
-+      lo = val & 0xffff;
-+      hi = val >> 16;
-+
-+      /* MT7530 uses 31 as the pseudo port */
-+      ret = bus->write(bus, 0x1f, 0x1f, page);
-+      if (ret < 0)
-+              goto err;
-+
-+      ret = bus->write(bus, 0x1f, r,  lo);
-+      if (ret < 0)
-+              goto err;
-+
-+      ret = bus->write(bus, 0x1f, 0x10, hi);
-+err:
-+      if (ret < 0)
-+              dev_err(&bus->dev,
-+                      "failed to write mt7530 register\n");
-+      return ret;
-+}
-+
-+static u32
-+mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      u16 page, r, lo, hi;
-+      int ret;
-+
-+      page = (reg >> 6) & 0x3ff;
-+      r = (reg >> 2) & 0xf;
-+
-+      /* MT7530 uses 31 as the pseudo port */
-+      ret = bus->write(bus, 0x1f, 0x1f, page);
-+      if (ret < 0) {
-+              dev_err(&bus->dev,
-+                      "failed to read mt7530 register\n");
-+              return ret;
-+      }
-+
-+      lo = bus->read(bus, 0x1f, r);
-+      hi = bus->read(bus, 0x1f, 0x10);
-+
-+      return (hi << 16) | (lo & 0xffff);
-+}
-+
-+static void
-+mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      struct mii_bus *bus = priv->bus;
-+
-+      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+      mt7530_mii_write(priv, reg, val);
-+
-+      mutex_unlock(&bus->mdio_lock);
-+}
-+
-+static u32
-+_mt7530_read(u32 reg)
-+{
-+      struct mt7530_priv      *priv = lpriv;
-+      struct mii_bus          *bus = priv->bus;
-+      u32 val;
-+
-+      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+      val = mt7530_mii_read(priv, reg);
-+
-+      mutex_unlock(&bus->mdio_lock);
-+
-+      return val;
-+}
-+
-+static u32
-+mt7530_read(struct mt7530_priv *priv, u32 reg)
-+{
-+      return _mt7530_read(reg);
-+}
-+
-+static void
-+mt7530_rmw(struct mt7530_priv *priv, u32 reg,
-+         u32 mask, u32 set)
-+{
-+      struct mii_bus *bus = priv->bus;
-+      u32 val;
-+
-+      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+
-+      val = mt7530_mii_read(priv, reg);
-+      val &= ~mask;
-+      val |= set;
-+      mt7530_mii_write(priv, reg, val);
-+
-+      mutex_unlock(&bus->mdio_lock);
-+}
-+
-+static void
-+mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      mt7530_rmw(priv, reg, 0, val);
-+}
-+
-+static void
-+mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+      mt7530_rmw(priv, reg, val, 0);
-+}
-+
-+static int
-+mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp)
-+{
-+      u32 val;
-+      int ret;
-+
-+      /* Set the command operating upon the MAC address entries */
-+      val = ATC_BUSY | ATC_MAT(0) | cmd;
-+      mt7530_write(priv, MT7530_ATC, val);
-+
-+      ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val,
-+                               !(val & ATC_BUSY), 20, 20000);
-+      if (ret < 0) {
-+              dev_err(priv->dev, "reset timeout\n");
-+              return ret;
-+      }
-+
-+      /* Additional sanity for read command if the specified
-+       * entry is invalid
-+       */
-+      val = mt7530_read(priv, MT7530_ATC);
-+      if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID))
-+              return -EINVAL;
-+
-+      if (rsp)
-+              *rsp = val;
-+
-+      return 0;
-+}
-+
-+static void
-+mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb)
-+{
-+      u32 reg[3];
-+      int i;
-+
-+      /* Read from ARL table into an array */
-+      for (i = 0; i < 3; i++) {
-+              reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4));
-+
-+              dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n",
-+                      __func__, __LINE__, i, reg[i]);
-+      }
-+
-+      fdb->vid = (reg[1] >> CVID) & CVID_MASK;
-+      fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK;
-+      fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK;
-+      fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK;
-+      fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK;
-+      fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK;
-+      fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK;
-+      fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK;
-+      fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK;
-+      fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT;
-+}
-+
-+static void
-+mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
-+               u8 port_mask, const u8 *mac,
-+               u8 aging, u8 type)
-+{
-+      u32 reg[3] = { 0 };
-+      int i;
-+
-+      reg[1] |= vid & CVID_MASK;
-+      reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER;
-+      reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP;
-+      /* STATIC_ENT indicate that entry is static wouldn't
-+       * be aged out and STATIC_EMP specified as erasing an
-+       * entry
-+       */
-+      reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS;
-+      reg[1] |= mac[5] << MAC_BYTE_5;
-+      reg[1] |= mac[4] << MAC_BYTE_4;
-+      reg[0] |= mac[3] << MAC_BYTE_3;
-+      reg[0] |= mac[2] << MAC_BYTE_2;
-+      reg[0] |= mac[1] << MAC_BYTE_1;
-+      reg[0] |= mac[0] << MAC_BYTE_0;
-+
-+      /* Write array into the ARL table */
-+      for (i = 0; i < 3; i++)
-+              mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
-+}
-+
-+static int
-+mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      u32 ncpo1, ssc_delta, trgint, i;
-+
-+      switch (mode) {
-+      case PHY_INTERFACE_MODE_RGMII:
-+              trgint = 0;
-+              ncpo1 = 0x0c80;
-+              ssc_delta = 0x87;
-+              break;
-+      case PHY_INTERFACE_MODE_TRGMII:
-+              trgint = 1;
-+              ncpo1 = 0x1400;
-+              ssc_delta = 0x57;
-+              break;
-+      default:
-+              dev_err(priv->dev, "xMII mode %d not supported\n", mode);
-+              return -EINVAL;
-+      }
-+
-+      mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
-+                 P6_INTF_MODE(trgint));
-+
-+      /* Lower Tx Driving for TRGMII path */
-+      for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
-+              mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
-+                           TD_DM_DRVP(8) | TD_DM_DRVN(8));
-+
-+      /* Setup core clock for MT7530 */
-+      if (!trgint) {
-+              /* Disable MT7530 core clock */
-+              core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
-+
-+              /* Disable PLL, since phy_device has not yet been created
-+               * provided for phy_[read,write]_mmd_indirect is called, we
-+               * provide our own core_write_mmd_indirect to complete this
-+               * function.
-+               */
-+              core_write_mmd_indirect(priv,
-+                                      CORE_GSWPLL_GRP1,
-+                                      MDIO_MMD_VEND2,
-+                                      0);
-+
-+              /* Set core clock into 500Mhz */
-+              core_write(priv, CORE_GSWPLL_GRP2,
-+                         RG_GSWPLL_POSDIV_500M(1) |
-+                         RG_GSWPLL_FBKDIV_500M(25));
-+
-+              /* Enable PLL */
-+              core_write(priv, CORE_GSWPLL_GRP1,
-+                         RG_GSWPLL_EN_PRE |
-+                         RG_GSWPLL_POSDIV_200M(2) |
-+                         RG_GSWPLL_FBKDIV_200M(32));
-+
-+              /* Enable MT7530 core clock */
-+              core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
-+      }
-+
-+      /* Setup the MT7530 TRGMII Tx Clock */
-+      core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
-+      core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
-+      core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
-+      core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
-+      core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
-+      core_write(priv, CORE_PLL_GROUP4,
-+                 RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
-+                 RG_SYSPLL_BIAS_LPF_EN);
-+      core_write(priv, CORE_PLL_GROUP2,
-+                 RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
-+                 RG_SYSPLL_POSDIV(1));
-+      core_write(priv, CORE_PLL_GROUP7,
-+                 RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
-+                 RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
-+      core_set(priv, CORE_TRGMII_GSW_CLK_CG,
-+               REG_GSWCK_EN | REG_TRGMIICK_EN);
-+
-+      if (!trgint)
-+              for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-+                      mt7530_rmw(priv, MT7530_TRGMII_RD(i),
-+                                 RD_TAP_MASK, RD_TAP(16));
-+      else
-+              mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
-+
-+      return 0;
-+}
-+
-+static int
-+mt7623_pad_clk_setup(struct dsa_switch *ds)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      int i;
-+
-+      for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-+              mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
-+                                  TD_DM_DRVP(8) | TD_DM_DRVN(8));
-+
-+      mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
-+      mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
-+
-+      return 0;
-+}
-+
-+static void
-+mt7530_mib_reset(struct dsa_switch *ds)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH);
-+      mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
-+}
-+
-+static void
-+mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
-+{
-+      u32 mask = PMCR_TX_EN | PMCR_RX_EN;
-+
-+      if (enable)
-+              mt7530_set(priv, MT7530_PMCR_P(port), mask);
-+      else
-+              mt7530_clear(priv, MT7530_PMCR_P(port), mask);
-+}
-+
-+static int
-+mt7530_setup(struct dsa_switch *ds)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      int ret, i;
-+      u32 id, val;
-+      struct device_node *dn;
-+
-+      /* The parent node of master_netdev which holds the common system
-+       * controller also is the container for two GMACs nodes representing
-+       * as two netdev instances.
-+       */
-+      dn = ds->master_netdev->dev.of_node->parent;
-+      priv->ethernet = syscon_node_to_regmap(dn);
-+      if (IS_ERR(priv->ethernet))
-+              return PTR_ERR(priv->ethernet);
-+
-+      regulator_set_voltage(priv->core_pwr, 1000000, 1000000);
-+      ret = regulator_enable(priv->core_pwr);
-+      if (ret < 0) {
-+              dev_err(priv->dev,
-+                      "Failed to enable core power: %d\n", ret);
-+              return ret;
-+      }
-+
-+      regulator_set_voltage(priv->io_pwr, 3300000, 3300000);
-+      ret = regulator_enable(priv->io_pwr);
-+      if (ret < 0) {
-+              dev_err(priv->dev, "Failed to enable io pwr: %d\n",
-+                      ret);
-+              return ret;
-+      }
-+
-+      /* Reset whole chip through gpio pin or memory-mapped registers for
-+       * different type of hardware
-+       */
-+      if (priv->mcm) {
-+              reset_control_assert(priv->rstc);
-+              usleep_range(1000, 1100);
-+              reset_control_deassert(priv->rstc);
-+      } else {
-+              gpiod_set_value_cansleep(priv->reset, 0);
-+              usleep_range(1000, 1100);
-+              gpiod_set_value_cansleep(priv->reset, 1);
-+      }
-+
-+      /* Waiting for MT7530 got to stable */
-+      ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0,
-+                               20, 1000000);
-+      if (ret < 0) {
-+              dev_err(priv->dev, "reset timeout\n");
-+              return ret;
-+      }
-+
-+      id = mt7530_read(priv, MT7530_CREV);
-+      id >>= CHIP_NAME_SHIFT;
-+      if (id != MT7530_ID) {
-+              dev_err(priv->dev, "chip %x can't be supported\n", id);
-+              return -ENODEV;
-+      }
-+
-+      /* Reset the switch through internal reset */
-+      mt7530_write(priv, MT7530_SYS_CTRL,
-+                   SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
-+                   SYS_CTRL_REG_RST);
-+
-+      /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
-+      val = mt7530_read(priv, MT7530_MHWTRAP);
-+      val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
-+      val |= MHWTRAP_MANUAL;
-+      mt7530_write(priv, MT7530_MHWTRAP, val);
-+
-+      /* Enable and reset MIB counters */
-+      mt7530_mib_reset(ds);
-+
-+      mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK);
-+
-+      for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+              /* Disable forwarding by default on all ports */
-+              mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
-+                         PCR_MATRIX_CLR);
-+
-+              if (dsa_is_cpu_port(ds, i))
-+                      mt7530_cpu_port_enable(priv, i);
-+              else
-+                      mt7530_port_disable(ds, i, NULL);
-+      }
-+
-+      /* Flush the FDB table */
-+      ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0);
-+      if (ret < 0)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      return mdiobus_read_nested(priv->bus, port, regnum);
-+}
-+
-+int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      return mdiobus_write_nested(priv->bus, port, regnum, val);
-+}
-+
-+static void
-+mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
-+{
-+      int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
-+              strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name,
-+                      ETH_GSTRING_LEN);
-+}
-+
-+static void
-+mt7530_get_ethtool_stats(struct dsa_switch *ds, int port,
-+                       uint64_t *data)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      const struct mt7530_mib_desc *mib;
-+      u32 reg, i;
-+      u64 hi;
-+
-+      for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) {
-+              mib = &mt7530_mib[i];
-+              reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset;
-+
-+              data[i] = mt7530_read(priv, reg);
-+              if (mib->size == 2) {
-+                      hi = mt7530_read(priv, reg + 4);
-+                      data[i] |= hi << 32;
-+              }
-+      }
-+}
-+
-+static int
-+mt7530_get_sset_count(struct dsa_switch *ds)
-+{
-+      return ARRAY_SIZE(mt7530_mib);
-+}
-+
-+static void mt7530_adjust_link(struct dsa_switch *ds, int port,
-+                             struct phy_device *phydev)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      if (phy_is_pseudo_fixed_link(phydev)) {
-+              dev_dbg(priv->dev, "phy-mode for master device = %x\n",
-+                      phydev->interface);
-+
-+              /* Setup TX circuit incluing relevant PAD and driving */
-+              mt7530_pad_clk_setup(ds, phydev->interface);
-+
-+              /* Setup RX circuit, relevant PAD and driving on the host
-+               * which must be placed after the setup on the device side is
-+               * all finished.
-+               */
-+              mt7623_pad_clk_setup(ds);
-+      }
-+}
-+
-+static int
-+mt7530_cpu_port_enable(struct mt7530_priv *priv,
-+                     int port)
-+{
-+      /* Enable Mediatek header mode on the cpu port */
-+      mt7530_write(priv, MT7530_PVC_P(port),
-+                   PORT_SPEC_TAG);
-+
-+      /* Setup the MAC by default for the cpu port */
-+      mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK);
-+
-+      /* Disable auto learning on the cpu port */
-+      mt7530_set(priv, MT7530_PSC_P(port), SA_DIS);
-+
-+      /* Unknown unicast frame fordwarding to the cpu port */
-+      mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port)));
-+
-+      /* CPU port gets connected to all user ports of
-+       * the switch
-+       */
-+      mt7530_write(priv, MT7530_PCR_P(port),
-+                   PCR_MATRIX(priv->ds->enabled_port_mask));
-+
-+      return 0;
-+}
-+
-+static int
-+mt7530_port_enable(struct dsa_switch *ds, int port,
-+                 struct phy_device *phy)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      mutex_lock(&priv->reg_mutex);
-+
-+      /* Setup the MAC for the user port */
-+      mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK);
-+
-+      /* Allow the user port gets connected to the cpu port and also
-+       * restore the port matrix if the port is the member of a certain
-+       * bridge.
-+       */
-+      priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
-+      priv->ports[port].enable = true;
-+      mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-+                 priv->ports[port].pm);
-+      mt7530_port_set_status(priv, port, 1);
-+
-+      mutex_unlock(&priv->reg_mutex);
-+
-+      return 0;
-+}
-+
-+static void
-+mt7530_port_disable(struct dsa_switch *ds, int port,
-+                  struct phy_device *phy)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      mutex_lock(&priv->reg_mutex);
-+
-+      /* Clear up all port matrix which could be restored in the next
-+       * enablement for the port.
-+       */
-+      priv->ports[port].enable = false;
-+      mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-+                 PCR_MATRIX_CLR);
-+      mt7530_port_set_status(priv, port, 0);
-+
-+      mutex_unlock(&priv->reg_mutex);
-+}
-+
-+static void
-+mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      u32 stp_state;
-+
-+      switch (state) {
-+      case BR_STATE_DISABLED:
-+              stp_state = MT7530_STP_DISABLED;
-+              break;
-+      case BR_STATE_BLOCKING:
-+              stp_state = MT7530_STP_BLOCKING;
-+              break;
-+      case BR_STATE_LISTENING:
-+              stp_state = MT7530_STP_LISTENING;
-+              break;
-+      case BR_STATE_LEARNING:
-+              stp_state = MT7530_STP_LEARNING;
-+              break;
-+      case BR_STATE_FORWARDING:
-+      default:
-+              stp_state = MT7530_STP_FORWARDING;
-+              break;
-+      }
-+
-+      mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state);
-+}
-+
-+static int
-+mt7530_port_bridge_join(struct dsa_switch *ds, int port,
-+                      struct net_device *bridge)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      u32 port_bitmap = BIT(MT7530_CPU_PORT);
-+      int i;
-+
-+      mutex_lock(&priv->reg_mutex);
-+
-+      for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+              /* Add this port to the port matrix of the other ports in the
-+               * same bridge. If the port is disabled, port matrix is kept
-+               * and not being setup until the port becomes enabled.
-+               */
-+              if (ds->enabled_port_mask & BIT(i) && i != port) {
-+                      if (ds->ports[i].bridge_dev != bridge)
-+                              continue;
-+                      if (priv->ports[i].enable)
-+                              mt7530_set(priv, MT7530_PCR_P(i),
-+                                         PCR_MATRIX(BIT(port)));
-+                      priv->ports[i].pm |= PCR_MATRIX(BIT(port));
-+
-+                      port_bitmap |= BIT(i);
-+              }
-+      }
-+
-+      /* Add the all other ports to this port matrix. */
-+      if (priv->ports[port].enable)
-+              mt7530_rmw(priv, MT7530_PCR_P(port),
-+                         PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap));
-+      priv->ports[port].pm |= PCR_MATRIX(port_bitmap);
-+
-+      mutex_unlock(&priv->reg_mutex);
-+
-+      return 0;
-+}
-+
-+static void
-+mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
-+                       struct net_device *bridge)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      int i;
-+
-+      mutex_lock(&priv->reg_mutex);
-+
-+      for (i = 0; i < MT7530_NUM_PORTS; i++) {
-+              /* Remove this port from the port matrix of the other ports
-+               * in the same bridge. If the port is disabled, port matrix
-+               * is kept and not being setup until the port becomes enabled.
-+               */
-+              if (ds->enabled_port_mask & BIT(i) && i != port) {
-+                      if (ds->ports[i].bridge_dev != bridge)
-+                              continue;
-+                      if (priv->ports[i].enable)
-+                              mt7530_clear(priv, MT7530_PCR_P(i),
-+                                           PCR_MATRIX(BIT(port)));
-+                      priv->ports[i].pm &= ~PCR_MATRIX(BIT(port));
-+              }
-+      }
-+
-+      /* Set the cpu port to be the only one in the port matrix of
-+       * this port.
-+       */
-+      if (priv->ports[port].enable)
-+              mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-+                         PCR_MATRIX(BIT(MT7530_CPU_PORT)));
-+      priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
-+
-+      mutex_unlock(&priv->reg_mutex);
-+}
-+
-+static int
-+mt7530_port_fdb_prepare(struct dsa_switch *ds, int port,
-+                      const struct switchdev_obj_port_fdb *fdb,
-+                      struct switchdev_trans *trans)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      int ret;
-+
-+      /* Because auto-learned entrie shares the same FDB table.
-+       * an entry is reserved with no port_mask to make sure fdb_add
-+       * is called while the entry is still available.
-+       */
-+      mutex_lock(&priv->reg_mutex);
-+      mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT);
-+      ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
-+      mutex_unlock(&priv->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static void
-+mt7530_port_fdb_add(struct dsa_switch *ds, int port,
-+                  const struct switchdev_obj_port_fdb *fdb,
-+                  struct switchdev_trans *trans)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      u8 port_mask = BIT(port);
-+
-+      mutex_lock(&priv->reg_mutex);
-+      mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT);
-+      mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
-+      mutex_unlock(&priv->reg_mutex);
-+}
-+
-+static int
-+mt7530_port_fdb_del(struct dsa_switch *ds, int port,
-+                  const struct switchdev_obj_port_fdb *fdb)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      int ret;
-+      u8 port_mask = BIT(port);
-+
-+      mutex_lock(&priv->reg_mutex);
-+      mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP);
-+      ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0);
-+      mutex_unlock(&priv->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static int
-+mt7530_port_fdb_dump(struct dsa_switch *ds, int port,
-+                   struct switchdev_obj_port_fdb *fdb,
-+                   int (*cb)(struct switchdev_obj *obj))
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+      struct mt7530_fdb _fdb = { 0 };
-+      int cnt = MT7530_NUM_FDB_RECORDS;
-+      int ret = 0;
-+      u32 rsp = 0;
-+
-+      mutex_lock(&priv->reg_mutex);
-+
-+      ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp);
-+      if (ret < 0)
-+              goto err;
-+
-+      do {
-+              if (rsp & ATC_SRCH_HIT) {
-+                      mt7530_fdb_read(priv, &_fdb);
-+                      if (_fdb.port_mask & BIT(port)) {
-+                              ether_addr_copy(fdb->addr, _fdb.mac);
-+                              fdb->vid = _fdb.vid;
-+                              fdb->ndm_state = _fdb.noarp ?
-+                                              NUD_NOARP : NUD_REACHABLE;
-+                              ret = cb(&fdb->obj);
-+                              if (ret < 0)
-+                                      break;
-+                      }
-+              }
-+      } while (--cnt &&
-+               !(rsp & ATC_SRCH_END) &&
-+               !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp));
-+err:
-+      mutex_unlock(&priv->reg_mutex);
-+
-+      return 0;
-+}
-+
-+static enum dsa_tag_protocol
-+mtk_get_tag_protocol(struct dsa_switch *ds)
-+{
-+      struct mt7530_priv *priv = ds->priv;
-+
-+      if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
-+              dev_warn(priv->dev,
-+                       "port not matched with tagging CPU port\n");
-+              return DSA_TAG_PROTO_NONE;
-+      } else {
-+              return DSA_TAG_PROTO_MTK;
-+      }
-+}
-+
-+static struct dsa_switch_ops mt7530_switch_ops = {
-+      .get_tag_protocol       = mtk_get_tag_protocol,
-+      .setup                  = mt7530_setup,
-+      .get_strings            = mt7530_get_strings,
-+      .phy_read               = mt7530_phy_read,
-+      .phy_write              = mt7530_phy_write,
-+      .get_ethtool_stats      = mt7530_get_ethtool_stats,
-+      .get_sset_count         = mt7530_get_sset_count,
-+      .adjust_link            = mt7530_adjust_link,
-+      .port_enable            = mt7530_port_enable,
-+      .port_disable           = mt7530_port_disable,
-+      .port_stp_state_set     = mt7530_stp_state_set,
-+      .port_bridge_join       = mt7530_port_bridge_join,
-+      .port_bridge_leave      = mt7530_port_bridge_leave,
-+      .port_fdb_prepare       = mt7530_port_fdb_prepare,
-+      .port_fdb_add           = mt7530_port_fdb_add,
-+      .port_fdb_del           = mt7530_port_fdb_del,
-+      .port_fdb_dump          = mt7530_port_fdb_dump,
-+};
-+
-+static int
-+mt7530_probe(struct mdio_device *mdiodev)
-+{
-+      struct mt7530_priv *priv;
-+      struct device_node *dn;
-+
-+      dn = mdiodev->dev.of_node;
-+
-+      priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
-+      if (!priv)
-+              return -ENOMEM;
-+
-+      priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
-+      if (!priv->ds)
-+              return -ENOMEM;
-+
-+      /* Use medatek,mcm property to distinguish hardware type that would
-+       * casues a little bit differences on power-on sequence.
-+       */
-+      priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
-+      if (priv->mcm) {
-+              dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
-+
-+              priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
-+              if (IS_ERR(priv->rstc)) {
-+                      dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
-+                      return PTR_ERR(priv->rstc);
-+              }
-+      }
-+
-+      priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
-+      if (IS_ERR(priv->core_pwr))
-+              return PTR_ERR(priv->core_pwr);
-+
-+      priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
-+      if (IS_ERR(priv->io_pwr))
-+              return PTR_ERR(priv->io_pwr);
-+
-+      /* Not MCM that indicates switch works as the remote standalone
-+       * integrated circuit so the GPIO pin would be used to complete
-+       * the reset, otherwise memory-mapped register accessing used
-+       * through syscon provides in the case of MCM.
-+       */
-+      if (!priv->mcm) {
-+              priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
-+                                                    GPIOD_OUT_LOW);
-+              if (IS_ERR(priv->reset)) {
-+                      dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
-+                      return PTR_ERR(priv->reset);
-+              }
-+      }
-+
-+      priv->bus = mdiodev->bus;
-+      priv->dev = &mdiodev->dev;
-+      priv->ds->priv = priv;
-+      priv->ds->ops = &mt7530_switch_ops;
-+      mutex_init(&priv->reg_mutex);
-+      lpriv = priv;
-+      dev_set_drvdata(&mdiodev->dev, priv);
-+
-+      return dsa_register_switch(priv->ds, &mdiodev->dev);
-+}
-+
-+static void
-+mt7530_remove(struct mdio_device *mdiodev)
-+{
-+      struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
-+      int ret = 0;
-+
-+      ret = regulator_disable(priv->core_pwr);
-+      if (ret < 0)
-+              dev_err(priv->dev,
-+                      "Failed to disable core power: %d\n", ret);
-+
-+      ret = regulator_disable(priv->io_pwr);
-+      if (ret < 0)
-+              dev_err(priv->dev, "Failed to disable io pwr: %d\n",
-+                      ret);
-+
-+      dsa_unregister_switch(priv->ds);
-+      mutex_destroy(&priv->reg_mutex);
-+}
-+
-+static const struct of_device_id mt7530_of_match[] = {
-+      { .compatible = "mediatek,mt7530" },
-+      { /* sentinel */ },
-+};
-+
-+static struct mdio_driver mt7530_mdio_driver = {
-+      .probe  = mt7530_probe,
-+      .remove = mt7530_remove,
-+      .mdiodrv.driver = {
-+              .name = "mt7530",
-+              .of_match_table = mt7530_of_match,
-+      },
-+};
-+
-+mdio_module_driver(mt7530_mdio_driver);
-+
-+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
-+MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:mediatek-mt7530");
---- /dev/null
-+++ b/drivers/net/dsa/mt7530.h
-@@ -0,0 +1,390 @@
-+/*
-+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __MT7530_H
-+#define __MT7530_H
-+
-+#define MT7530_NUM_PORTS              7
-+#define MT7530_CPU_PORT                       6
-+#define MT7530_NUM_FDB_RECORDS                2048
-+
-+#define       NUM_TRGMII_CTRL                 5
-+
-+#define TRGMII_BASE(x)                        (0x10000 + (x))
-+
-+/* Registers to ethsys access */
-+#define ETHSYS_CLKCFG0                        0x2c
-+#define  ETHSYS_TRGMII_CLK_SEL362_5   BIT(11)
-+
-+#define SYSC_REG_RSTCTRL              0x34
-+#define  RESET_MCM                    BIT(2)
-+
-+/* Registers to mac forward control for unknown frames */
-+#define MT7530_MFC                    0x10
-+#define  BC_FFP(x)                    (((x) & 0xff) << 24)
-+#define  UNM_FFP(x)                   (((x) & 0xff) << 16)
-+#define  UNU_FFP(x)                   (((x) & 0xff) << 8)
-+#define  UNU_FFP_MASK                 UNU_FFP(~0)
-+
-+/* Registers for address table access */
-+#define MT7530_ATA1                   0x74
-+#define  STATIC_EMP                   0
-+#define  STATIC_ENT                   3
-+#define MT7530_ATA2                   0x78
-+
-+/* Register for address table write data */
-+#define MT7530_ATWD                   0x7c
-+
-+/* Register for address table control */
-+#define MT7530_ATC                    0x80
-+#define  ATC_HASH                     (((x) & 0xfff) << 16)
-+#define  ATC_BUSY                     BIT(15)
-+#define  ATC_SRCH_END                 BIT(14)
-+#define  ATC_SRCH_HIT                 BIT(13)
-+#define  ATC_INVALID                  BIT(12)
-+#define  ATC_MAT(x)                   (((x) & 0xf) << 8)
-+#define  ATC_MAT_MACTAB                       ATC_MAT(0)
-+
-+enum mt7530_fdb_cmd {
-+      MT7530_FDB_READ = 0,
-+      MT7530_FDB_WRITE = 1,
-+      MT7530_FDB_FLUSH = 2,
-+      MT7530_FDB_START = 4,
-+      MT7530_FDB_NEXT = 5,
-+};
-+
-+/* Registers for table search read address */
-+#define MT7530_TSRA1                  0x84
-+#define  MAC_BYTE_0                   24
-+#define  MAC_BYTE_1                   16
-+#define  MAC_BYTE_2                   8
-+#define  MAC_BYTE_3                   0
-+#define  MAC_BYTE_MASK                        0xff
-+
-+#define MT7530_TSRA2                  0x88
-+#define  MAC_BYTE_4                   24
-+#define  MAC_BYTE_5                   16
-+#define  CVID                         0
-+#define  CVID_MASK                    0xfff
-+
-+#define MT7530_ATRD                   0x8C
-+#define        AGE_TIMER                      24
-+#define  AGE_TIMER_MASK                       0xff
-+#define  PORT_MAP                     4
-+#define  PORT_MAP_MASK                        0xff
-+#define  ENT_STATUS                   2
-+#define  ENT_STATUS_MASK              0x3
-+
-+/* Register for vlan table control */
-+#define MT7530_VTCR                   0x90
-+#define  VTCR_BUSY                    BIT(31)
-+#define  VTCR_FUNC                    (((x) & 0xf) << 12)
-+#define  VTCR_FUNC_RD_VID             0x1
-+#define  VTCR_FUNC_WR_VID             0x2
-+#define  VTCR_FUNC_INV_VID            0x3
-+#define  VTCR_FUNC_VAL_VID            0x4
-+#define  VTCR_VID                     ((x) & 0xfff)
-+
-+/* Register for setup vlan and acl write data */
-+#define MT7530_VAWD1                  0x94
-+#define  PORT_STAG                    BIT(31)
-+#define  IVL_MAC                      BIT(30)
-+#define  PORT_MEM(x)                  (((x) & 0xff) << 16)
-+#define  VALID                                BIT(1)
-+
-+#define MT7530_VAWD2                  0x98
-+
-+/* Register for port STP state control */
-+#define MT7530_SSP_P(x)                       (0x2000 + ((x) * 0x100))
-+#define  FID_PST(x)                   ((x) & 0x3)
-+#define  FID_PST_MASK                 FID_PST(0x3)
-+
-+enum mt7530_stp_state {
-+      MT7530_STP_DISABLED = 0,
-+      MT7530_STP_BLOCKING = 1,
-+      MT7530_STP_LISTENING = 1,
-+      MT7530_STP_LEARNING = 2,
-+      MT7530_STP_FORWARDING  = 3
-+};
-+
-+/* Register for port control */
-+#define MT7530_PCR_P(x)                       (0x2004 + ((x) * 0x100))
-+#define  PORT_VLAN(x)                 ((x) & 0x3)
-+#define  PCR_MATRIX(x)                        (((x) & 0xff) << 16)
-+#define  PORT_PRI(x)                  (((x) & 0x7) << 24)
-+#define  EG_TAG(x)                    (((x) & 0x3) << 28)
-+#define  PCR_MATRIX_MASK              PCR_MATRIX(0xff)
-+#define  PCR_MATRIX_CLR                       PCR_MATRIX(0)
-+
-+/* Register for port security control */
-+#define MT7530_PSC_P(x)                       (0x200c + ((x) * 0x100))
-+#define  SA_DIS                               BIT(4)
-+
-+/* Register for port vlan control */
-+#define MT7530_PVC_P(x)                       (0x2010 + ((x) * 0x100))
-+#define  PORT_SPEC_TAG                        BIT(5)
-+#define  VLAN_ATTR(x)                 (((x) & 0x3) << 6)
-+#define  STAG_VPID                    (((x) & 0xffff) << 16)
-+
-+/* Register for port port-and-protocol based vlan 1 control */
-+#define MT7530_PPBV1_P(x)             (0x2014 + ((x) * 0x100))
-+
-+/* Register for port MAC control register */
-+#define MT7530_PMCR_P(x)              (0x3000 + ((x) * 0x100))
-+#define  PMCR_IFG_XMIT(x)             (((x) & 0x3) << 18)
-+#define  PMCR_MAC_MODE                        BIT(16)
-+#define  PMCR_FORCE_MODE              BIT(15)
-+#define  PMCR_TX_EN                   BIT(14)
-+#define  PMCR_RX_EN                   BIT(13)
-+#define  PMCR_BACKOFF_EN              BIT(9)
-+#define  PMCR_BACKPR_EN                       BIT(8)
-+#define  PMCR_TX_FC_EN                        BIT(5)
-+#define  PMCR_RX_FC_EN                        BIT(4)
-+#define  PMCR_FORCE_SPEED_1000                BIT(3)
-+#define  PMCR_FORCE_FDX                       BIT(1)
-+#define  PMCR_FORCE_LNK                       BIT(0)
-+#define  PMCR_COMMON_LINK             (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
-+                                       PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
-+                                       PMCR_TX_EN | PMCR_RX_EN | \
-+                                       PMCR_TX_FC_EN | PMCR_RX_FC_EN)
-+#define  PMCR_CPUP_LINK                       (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \
-+                                       PMCR_FORCE_SPEED_1000 | \
-+                                       PMCR_FORCE_FDX | \
-+                                       PMCR_FORCE_LNK)
-+#define  PMCR_USERP_LINK              PMCR_COMMON_LINK
-+#define  PMCR_FIXED_LINK              (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
-+                                       PMCR_FORCE_MODE | PMCR_TX_EN | \
-+                                       PMCR_RX_EN | PMCR_BACKPR_EN | \
-+                                       PMCR_BACKOFF_EN | \
-+                                       PMCR_FORCE_SPEED_1000 | \
-+                                       PMCR_FORCE_FDX | \
-+                                       PMCR_FORCE_LNK)
-+#define PMCR_FIXED_LINK_FC            (PMCR_FIXED_LINK | \
-+                                       PMCR_TX_FC_EN | PMCR_RX_FC_EN)
-+
-+#define MT7530_PMSR_P(x)              (0x3008 + (x) * 0x100)
-+
-+/* Register for MIB */
-+#define MT7530_PORT_MIB_COUNTER(x)    (0x4000 + (x) * 0x100)
-+#define MT7530_MIB_CCR                        0x4fe0
-+#define  CCR_MIB_ENABLE                       BIT(31)
-+#define  CCR_RX_OCT_CNT_GOOD          BIT(7)
-+#define  CCR_RX_OCT_CNT_BAD           BIT(6)
-+#define  CCR_TX_OCT_CNT_GOOD          BIT(5)
-+#define  CCR_TX_OCT_CNT_BAD           BIT(4)
-+#define  CCR_MIB_FLUSH                        (CCR_RX_OCT_CNT_GOOD | \
-+                                       CCR_RX_OCT_CNT_BAD | \
-+                                       CCR_TX_OCT_CNT_GOOD | \
-+                                       CCR_TX_OCT_CNT_BAD)
-+#define  CCR_MIB_ACTIVATE             (CCR_MIB_ENABLE | \
-+                                       CCR_RX_OCT_CNT_GOOD | \
-+                                       CCR_RX_OCT_CNT_BAD | \
-+                                       CCR_TX_OCT_CNT_GOOD | \
-+                                       CCR_TX_OCT_CNT_BAD)
-+/* Register for system reset */
-+#define MT7530_SYS_CTRL                       0x7000
-+#define  SYS_CTRL_PHY_RST             BIT(2)
-+#define  SYS_CTRL_SW_RST              BIT(1)
-+#define  SYS_CTRL_REG_RST             BIT(0)
-+
-+/* Register for hw trap status */
-+#define MT7530_HWTRAP                 0x7800
-+
-+/* Register for hw trap modification */
-+#define MT7530_MHWTRAP                        0x7804
-+#define  MHWTRAP_MANUAL                       BIT(16)
-+#define  MHWTRAP_P5_MAC_SEL           BIT(13)
-+#define  MHWTRAP_P6_DIS                       BIT(8)
-+#define  MHWTRAP_P5_RGMII_MODE                BIT(7)
-+#define  MHWTRAP_P5_DIS                       BIT(6)
-+#define  MHWTRAP_PHY_ACCESS           BIT(5)
-+
-+/* Register for TOP signal control */
-+#define MT7530_TOP_SIG_CTRL           0x7808
-+#define  TOP_SIG_CTRL_NORMAL          (BIT(17) | BIT(16))
-+
-+#define MT7530_IO_DRV_CR              0x7810
-+#define  P5_IO_CLK_DRV(x)             ((x) & 0x3)
-+#define  P5_IO_DATA_DRV(x)            (((x) & 0x3) << 4)
-+
-+#define MT7530_P6ECR                  0x7830
-+#define  P6_INTF_MODE_MASK            0x3
-+#define  P6_INTF_MODE(x)              ((x) & 0x3)
-+
-+/* Registers for TRGMII on the both side */
-+#define MT7530_TRGMII_RCK_CTRL                0x7a00
-+#define GSW_TRGMII_RCK_CTRL           0x300
-+#define  RX_RST                               BIT(31)
-+#define  RXC_DQSISEL                  BIT(30)
-+#define  DQSI1_TAP_MASK                       (0x7f << 8)
-+#define  DQSI0_TAP_MASK                       0x7f
-+#define  DQSI1_TAP(x)                 (((x) & 0x7f) << 8)
-+#define  DQSI0_TAP(x)                 ((x) & 0x7f)
-+
-+#define MT7530_TRGMII_RCK_RTT         0x7a04
-+#define GSW_TRGMII_RCK_RTT            0x304
-+#define  DQS1_GATE                    BIT(31)
-+#define  DQS0_GATE                    BIT(30)
-+
-+#define MT7530_TRGMII_RD(x)           (0x7a10 + (x) * 8)
-+#define GSW_TRGMII_RD(x)              (0x310 + (x) * 8)
-+#define  BSLIP_EN                     BIT(31)
-+#define  EDGE_CHK                     BIT(30)
-+#define  RD_TAP_MASK                  0x7f
-+#define  RD_TAP(x)                    ((x) & 0x7f)
-+
-+#define GSW_TRGMII_TXCTRL             0x340
-+#define MT7530_TRGMII_TXCTRL          0x7a40
-+#define  TRAIN_TXEN                   BIT(31)
-+#define  TXC_INV                      BIT(30)
-+#define  TX_RST                               BIT(28)
-+
-+#define MT7530_TRGMII_TD_ODT(i)               (0x7a54 + 8 * (i))
-+#define GSW_TRGMII_TD_ODT(i)          (0x354 + 8 * (i))
-+#define  TD_DM_DRVP(x)                        ((x) & 0xf)
-+#define  TD_DM_DRVN(x)                        (((x) & 0xf) << 4)
-+
-+#define GSW_INTF_MODE                 0x390
-+#define  INTF_MODE_TRGMII             BIT(1)
-+
-+#define MT7530_TRGMII_TCK_CTRL                0x7a78
-+#define  TCK_TAP(x)                   (((x) & 0xf) << 8)
-+
-+#define MT7530_P5RGMIIRXCR            0x7b00
-+#define  CSR_RGMII_EDGE_ALIGN         BIT(8)
-+#define  CSR_RGMII_RXC_0DEG_CFG(x)    ((x) & 0xf)
-+
-+#define MT7530_P5RGMIITXCR            0x7b04
-+#define  CSR_RGMII_TXC_CFG(x)         ((x) & 0x1f)
-+
-+#define MT7530_CREV                   0x7ffc
-+#define  CHIP_NAME_SHIFT              16
-+#define  MT7530_ID                    0x7530
-+
-+/* Registers for core PLL access through mmd indirect */
-+#define CORE_PLL_GROUP2                       0x401
-+#define  RG_SYSPLL_EN_NORMAL          BIT(15)
-+#define  RG_SYSPLL_VODEN              BIT(14)
-+#define  RG_SYSPLL_LF                 BIT(13)
-+#define  RG_SYSPLL_RST_DLY(x)         (((x) & 0x3) << 12)
-+#define  RG_SYSPLL_LVROD_EN           BIT(10)
-+#define  RG_SYSPLL_PREDIV(x)          (((x) & 0x3) << 8)
-+#define  RG_SYSPLL_POSDIV(x)          (((x) & 0x3) << 5)
-+#define  RG_SYSPLL_FBKSEL             BIT(4)
-+#define  RT_SYSPLL_EN_AFE_OLT         BIT(0)
-+
-+#define CORE_PLL_GROUP4                       0x403
-+#define  RG_SYSPLL_DDSFBK_EN          BIT(12)
-+#define  RG_SYSPLL_BIAS_EN            BIT(11)
-+#define  RG_SYSPLL_BIAS_LPF_EN                BIT(10)
-+
-+#define CORE_PLL_GROUP5                       0x404
-+#define  RG_LCDDS_PCW_NCPO1(x)                ((x) & 0xffff)
-+
-+#define CORE_PLL_GROUP6                       0x405
-+#define  RG_LCDDS_PCW_NCPO0(x)                ((x) & 0xffff)
-+
-+#define CORE_PLL_GROUP7                       0x406
-+#define  RG_LCDDS_PWDB                        BIT(15)
-+#define  RG_LCDDS_ISO_EN              BIT(13)
-+#define  RG_LCCDS_C(x)                        (((x) & 0x7) << 4)
-+#define  RG_LCDDS_PCW_NCPO_CHG                BIT(3)
-+
-+#define CORE_PLL_GROUP10              0x409
-+#define  RG_LCDDS_SSC_DELTA(x)                ((x) & 0xfff)
-+
-+#define CORE_PLL_GROUP11              0x40a
-+#define  RG_LCDDS_SSC_DELTA1(x)               ((x) & 0xfff)
-+
-+#define CORE_GSWPLL_GRP1              0x40d
-+#define  RG_GSWPLL_PREDIV(x)          (((x) & 0x3) << 14)
-+#define  RG_GSWPLL_POSDIV_200M(x)     (((x) & 0x3) << 12)
-+#define  RG_GSWPLL_EN_PRE             BIT(11)
-+#define  RG_GSWPLL_FBKSEL             BIT(10)
-+#define  RG_GSWPLL_BP                 BIT(9)
-+#define  RG_GSWPLL_BR                 BIT(8)
-+#define  RG_GSWPLL_FBKDIV_200M(x)     ((x) & 0xff)
-+
-+#define CORE_GSWPLL_GRP2              0x40e
-+#define  RG_GSWPLL_POSDIV_500M(x)     (((x) & 0x3) << 8)
-+#define  RG_GSWPLL_FBKDIV_500M(x)     ((x) & 0xff)
-+
-+#define CORE_TRGMII_GSW_CLK_CG                0x410
-+#define  REG_GSWCK_EN                 BIT(0)
-+#define  REG_TRGMIICK_EN              BIT(1)
-+
-+#define MIB_DESC(_s, _o, _n)  \
-+      {                       \
-+              .size = (_s),   \
-+              .offset = (_o), \
-+              .name = (_n),   \
-+      }
-+
-+struct mt7530_mib_desc {
-+      unsigned int size;
-+      unsigned int offset;
-+      const char *name;
-+};
-+
-+struct mt7530_fdb {
-+      u16 vid;
-+      u8 port_mask;
-+      u8 aging;
-+      u8 mac[6];
-+      bool noarp;
-+};
-+
-+struct mt7530_port {
-+      bool enable;
-+      u32 pm;
-+};
-+
-+/* struct mt7530_priv -       This is the main data structure for holding the state
-+ *                    of the driver
-+ * @dev:              The device pointer
-+ * @ds:                       The pointer to the dsa core structure
-+ * @bus:              The bus used for the device and built-in PHY
-+ * @rstc:             The pointer to reset control used by MCM
-+ * @ethernet:         The regmap used for access TRGMII-based registers
-+ * @core_pwr:         The power supplied into the core
-+ * @io_pwr:           The power supplied into the I/O
-+ * @reset:            The descriptor for GPIO line tied to its reset pin
-+ * @mcm:              Flag for distinguishing if standalone IC or module
-+ *                    coupling
-+ * @ports:            Holding the state among ports
-+ * @reg_mutex:                The lock for protecting among process accessing
-+ *                    registers
-+ */
-+struct mt7530_priv {
-+      struct device           *dev;
-+      struct dsa_switch       *ds;
-+      struct mii_bus          *bus;
-+      struct reset_control    *rstc;
-+      struct regmap           *ethernet;
-+      struct regulator        *core_pwr;
-+      struct regulator        *io_pwr;
-+      struct gpio_desc        *reset;
-+      bool                    mcm;
-+
-+      struct mt7530_port      ports[MT7530_NUM_PORTS];
-+      /* protect among processes for registers access*/
-+      struct mutex reg_mutex;
-+};
-+
-+struct mt7530_hw_stats {
-+      const char      *string;
-+      u16             reg;
-+      u8              sizeof_stat;
-+};
-+
-+#endif /* __MT7530_H */
diff --git a/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch
deleted file mode 100644 (file)
index f69078c..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc
-       int i;
-       mutex_lock(&priv->reg_mutex);
-+      priv->bridge_dev[port] = bridge;
-       for (i = 0; i < MT7530_NUM_PORTS; i++) {
-               /* Add this port to the port matrix of the other ports in the
-@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc
-                * and not being setup until the port becomes enabled.
-                */
-               if (ds->enabled_port_mask & BIT(i) && i != port) {
--                      if (ds->ports[i].bridge_dev != bridge)
-+                      if (priv->bridge_dev[i] != bridge)
-                               continue;
-                       if (priv->ports[i].enable)
-                               mt7530_set(priv, MT7530_PCR_P(i),
-@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc
- }
- static void
--mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
--                       struct net_device *bridge)
-+mt7530_port_bridge_leave(struct dsa_switch *ds, int port)
- {
-       struct mt7530_priv *priv = ds->priv;
-       int i;
-@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit
-                * is kept and not being setup until the port becomes enabled.
-                */
-               if (ds->enabled_port_mask & BIT(i) && i != port) {
--                      if (ds->ports[i].bridge_dev != bridge)
-+                      if (priv->bridge_dev[i] != priv->bridge_dev[port])
-                               continue;
-                       if (priv->ports[i].enable)
-                               mt7530_clear(priv, MT7530_PCR_P(i),
-@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit
-       /* Set the cpu port to be the only one in the port matrix of
-        * this port.
-        */
-+      priv->bridge_dev[port] = NULL;
-       if (priv->ports[port].enable)
-               mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-                          PCR_MATRIX(BIT(MT7530_CPU_PORT)));
-@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev
-       if (!priv)
-               return -ENOMEM;
--      priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS);
-+      priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
-       if (!priv->ds)
-               return -ENOMEM;
-@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev
-       priv->bus = mdiodev->bus;
-       priv->dev = &mdiodev->dev;
-       priv->ds->priv = priv;
-+      priv->ds->dev = &mdiodev->dev;
-       priv->ds->ops = &mt7530_switch_ops;
-       mutex_init(&priv->reg_mutex);
-       lpriv = priv;
-       dev_set_drvdata(&mdiodev->dev, priv);
--      return dsa_register_switch(priv->ds, &mdiodev->dev);
-+      return dsa_register_switch(priv->ds, priv->ds->dev->of_node);
- }
- static void
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -379,6 +379,8 @@ struct mt7530_priv {
-       struct mt7530_port      ports[MT7530_NUM_PORTS];
-       /* protect among processes for registers access*/
-       struct mutex reg_mutex;
-+
-+      struct net_device *bridge_dev[MT7530_NUM_PORTS];
- };
- struct mt7530_hw_stats {
---- a/net/dsa/tag_mtk.c
-+++ b/net/dsa/tag_mtk.c
-@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru
-       /* Build the tag after the MAC Source Address */
-       mtk_tag = skb->data + 2 * ETH_ALEN;
-       mtk_tag[0] = 0;
--      mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK;
-+      mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK;
-       mtk_tag[2] = 0;
-       mtk_tag[3] = 0;
diff --git a/target/linux/mediatek/patches-4.9/0094-net-affinity.patch b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch
deleted file mode 100644 (file)
index 0c468fb..0000000
+++ /dev/null
@@ -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;
diff --git a/target/linux/mediatek/patches-4.9/0095-ephy.patch b/target/linux/mediatek/patches-4.9/0095-ephy.patch
deleted file mode 100644 (file)
index dc88ca2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -629,6 +629,11 @@ mt7530_setup(struct dsa_switch *ds)
-       val = mt7530_read(priv, MT7530_MHWTRAP);
-       val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
-       val |= MHWTRAP_MANUAL;
-+      if (!dsa_is_cpu_port(ds, 5)) {
-+              val |= MHWTRAP_P5_DIS;
-+              val |= MHWTRAP_P5_MAC_SEL;
-+              val |= MHWTRAP_P5_RGMII_MODE;
-+      }
-       mt7530_write(priv, MT7530_MHWTRAP, val);
-       /* Enable and reset MIB counters */
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -221,6 +221,9 @@ static void mtk_phy_link_adjust(struct n
-               netif_carrier_on(dev);
-       else
-               netif_carrier_off(dev);
-+
-+      if (!of_phy_is_fixed_link(mac->of_node))
-+              phy_print_status(dev->phydev);
- }
- static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
diff --git a/target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch b/target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch
deleted file mode 100644 (file)
index 6394e14..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -996,15 +996,7 @@ err:
- static enum dsa_tag_protocol
- mtk_get_tag_protocol(struct dsa_switch *ds)
- {
--      struct mt7530_priv *priv = ds->priv;
--
--      if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) {
--              dev_warn(priv->dev,
--                       "port not matched with tagging CPU port\n");
--              return DSA_TAG_PROTO_NONE;
--      } else {
--              return DSA_TAG_PROTO_MTK;
--      }
-+      return DSA_TAG_PROTO_MTK;
- }
- static struct dsa_switch_ops mt7530_switch_ops = {
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -145,6 +145,8 @@ struct dsa_port {
-       struct device_node      *dn;
-       unsigned int            ageing_time;
-       u8                      stp_state;
-+      struct net_device       *ethernet;
-+      int                     upstream;
- };
- struct dsa_switch {
-@@ -205,7 +207,7 @@ struct dsa_switch {
- static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
- {
--      return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
-+      return !!(ds->cpu_port_mask & (1 << p));
- }
- static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p)
-@@ -218,6 +220,11 @@ static inline bool dsa_is_port_initializ
-       return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev;
- }
-+static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p)
-+{
-+      return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p);
-+}
-+
- static inline u8 dsa_upstream_port(struct dsa_switch *ds)
- {
-       struct dsa_switch_tree *dst = ds->dst;
-@@ -234,6 +241,18 @@ static inline u8 dsa_upstream_port(struc
-               return ds->rtable[dst->cpu_switch];
- }
-+static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port)
-+{
-+      /*
-+       * If this port has a specific upstream cpu port, use it,
-+       * otherwise use the switch default.
-+       */
-+      if (ds->ports[port].upstream)
-+              return ds->ports[port].upstream;
-+      else
-+              return dsa_upstream_port(ds);
-+}
-+
- struct switchdev_trans;
- struct switchdev_obj;
- struct switchdev_obj_port_fdb;
---- a/net/dsa/dsa2.c
-+++ b/net/dsa/dsa2.c
-@@ -248,8 +248,6 @@ static int dsa_cpu_port_apply(struct dev
-               return err;
-       }
--      ds->cpu_port_mask |= BIT(index);
--
-       return 0;
- }
-@@ -259,6 +257,10 @@ static void dsa_cpu_port_unapply(struct
-       dsa_cpu_dsa_destroy(port);
-       ds->cpu_port_mask &= ~BIT(index);
-+      if (ds->ports[index].ethernet) {
-+              dev_put(ds->ports[index].ethernet);
-+              ds->ports[index].ethernet = NULL;
-+      }
- }
- static int dsa_user_port_apply(struct device_node *port, u32 index,
-@@ -479,6 +481,29 @@ static int dsa_cpu_parse(struct device_n
-       dst->rcv = dst->tag_ops->rcv;
-+      dev_hold(ethernet_dev);
-+      ds->ports[index].ethernet = ethernet_dev;
-+      ds->cpu_port_mask |= BIT(index);
-+
-+      return 0;
-+}
-+
-+static int dsa_user_parse(struct device_node *port, u32 index,
-+                        struct dsa_switch *ds)
-+{
-+      struct device_node *cpu_port;
-+      const unsigned int *cpu_port_reg;
-+      int cpu_port_index;
-+
-+      cpu_port = of_parse_phandle(port, "cpu", 0);
-+      if (cpu_port) {
-+              cpu_port_reg = of_get_property(cpu_port, "reg", NULL);
-+              if (!cpu_port_reg)
-+                      return -EINVAL;
-+              cpu_port_index = be32_to_cpup(cpu_port_reg);
-+              ds->ports[index].upstream = cpu_port_index;
-+      }
-+
-       return 0;
- }
-@@ -486,18 +511,19 @@ static int dsa_ds_parse(struct dsa_switc
- {
-       struct device_node *port;
-       u32 index;
--      int err;
-+      int err = 0;
-       for (index = 0; index < DSA_MAX_PORTS; index++) {
-               port = ds->ports[index].dn;
-               if (!port)
-                       continue;
--              if (dsa_port_is_cpu(port)) {
-+              if (dsa_port_is_cpu(port))
-                       err = dsa_cpu_parse(port, index, dst, ds);
--                      if (err)
--                              return err;
--              }
-+              else if (!dsa_port_is_dsa(port))
-+                      err = dsa_user_parse(port, index,  ds);
-+              if (err)
-+                      return err;
-       }
-       pr_info("DSA: switch %d %d parsed\n", dst->tree, ds->index);
---- a/net/dsa/dsa_priv.h
-+++ b/net/dsa/dsa_priv.h
-@@ -43,6 +43,7 @@ struct dsa_slave_priv {
-       int                     old_duplex;
-       struct net_device       *bridge_dev;
-+      struct net_device       *master;
- #ifdef CONFIG_NET_POLL_CONTROLLER
-       struct netpoll          *netpoll;
- #endif
---- a/net/dsa/slave.c
-+++ b/net/dsa/slave.c
-@@ -61,7 +61,7 @@ static int dsa_slave_get_iflink(const st
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      return p->parent->dst->master_netdev->ifindex;
-+      return p->master->ifindex;
- }
- static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)
-@@ -96,7 +96,7 @@ static void dsa_port_set_stp_state(struc
- static int dsa_slave_open(struct net_device *dev)
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      struct net_device *master = p->parent->dst->master_netdev;
-+      struct net_device *master = p->master;
-       struct dsa_switch *ds = p->parent;
-       u8 stp_state = dsa_port_is_bridged(p) ?
-                       BR_STATE_BLOCKING : BR_STATE_FORWARDING;
-@@ -151,7 +151,7 @@ out:
- static int dsa_slave_close(struct net_device *dev)
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      struct net_device *master = p->parent->dst->master_netdev;
-+      struct net_device *master = p->master;
-       struct dsa_switch *ds = p->parent;
-       if (p->phy)
-@@ -178,7 +178,7 @@ static int dsa_slave_close(struct net_de
- static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      struct net_device *master = p->parent->dst->master_netdev;
-+      struct net_device *master = p->master;
-       if (change & IFF_ALLMULTI)
-               dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
-@@ -189,7 +189,7 @@ static void dsa_slave_change_rx_flags(st
- static void dsa_slave_set_rx_mode(struct net_device *dev)
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      struct net_device *master = p->parent->dst->master_netdev;
-+      struct net_device *master = p->master;
-       dev_mc_sync(master, dev);
-       dev_uc_sync(master, dev);
-@@ -198,7 +198,7 @@ static void dsa_slave_set_rx_mode(struct
- static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
--      struct net_device *master = p->parent->dst->master_netdev;
-+      struct net_device *master = p->master;
-       struct sockaddr *addr = a;
-       int err;
-@@ -633,7 +633,7 @@ static netdev_tx_t dsa_slave_xmit(struct
-       /* Queue the SKB for transmission on the parent interface, but
-        * do not modify its EtherType
-        */
--      nskb->dev = p->parent->dst->master_netdev;
-+      nskb->dev = p->master;
-       dev_queue_xmit(nskb);
-       return NETDEV_TX_OK;
-@@ -945,7 +945,7 @@ static int dsa_slave_netpoll_setup(struc
- {
-       struct dsa_slave_priv *p = netdev_priv(dev);
-       struct dsa_switch *ds = p->parent;
--      struct net_device *master = ds->dst->master_netdev;
-+      struct net_device *master = p->master;
-       struct netpoll *netpoll;
-       int err = 0;
-@@ -1233,11 +1233,16 @@ int dsa_slave_create(struct dsa_switch *
-       struct net_device *master;
-       struct net_device *slave_dev;
-       struct dsa_slave_priv *p;
-+      int port_cpu = ds->ports[port].upstream;
-       int ret;
--      master = ds->dst->master_netdev;
--      if (ds->master_netdev)
-+      if (port_cpu && ds->ports[port_cpu].ethernet)
-+              master = ds->ports[port_cpu].ethernet;
-+      else if (ds->master_netdev)
-               master = ds->master_netdev;
-+      else
-+              master = ds->dst->master_netdev;
-+      master->dsa_ptr = (void *)ds->dst;
-       slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name,
-                                NET_NAME_UNKNOWN, ether_setup);
-@@ -1263,6 +1268,7 @@ int dsa_slave_create(struct dsa_switch *
-       p->parent = ds;
-       p->port = port;
-       p->xmit = dst->tag_ops->xmit;
-+      p->master = master;
-       p->old_pause = -1;
-       p->old_link = -1;
diff --git a/target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch b/target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch
deleted file mode 100644 (file)
index 26eff60..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -627,7 +627,7 @@ mt7530_setup(struct dsa_switch *ds)
-       /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */
-       val = mt7530_read(priv, MT7530_MHWTRAP);
--      val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
-+      val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS;
-       val |= MHWTRAP_MANUAL;
-       if (!dsa_is_cpu_port(ds, 5)) {
-               val |= MHWTRAP_P5_DIS;
-@@ -735,6 +735,9 @@ static int
- mt7530_cpu_port_enable(struct mt7530_priv *priv,
-                      int port)
- {
-+      u8 port_mask = 0;
-+      int i;
-+
-       /* Enable Mediatek header mode on the cpu port */
-       mt7530_write(priv, MT7530_PVC_P(port),
-                    PORT_SPEC_TAG);
-@@ -751,8 +754,12 @@ mt7530_cpu_port_enable(struct mt7530_pri
-       /* CPU port gets connected to all user ports of
-        * the switch
-        */
-+      for (i = 0; i < MT7530_NUM_PORTS; i++)
-+              if ((priv->ds->enabled_port_mask & BIT(i)) &&
-+                  (dsa_port_upstream_port(priv->ds, i) == port))
-+                      port_mask |= BIT(i);
-       mt7530_write(priv, MT7530_PCR_P(port),
--                   PCR_MATRIX(priv->ds->enabled_port_mask));
-+                   PCR_MATRIX(port_mask));
-       return 0;
- }
-@@ -762,6 +769,7 @@ mt7530_port_enable(struct dsa_switch *ds
-                  struct phy_device *phy)
- {
-       struct mt7530_priv *priv = ds->priv;
-+      u8 upstream = dsa_port_upstream_port(ds, port);
-       mutex_lock(&priv->reg_mutex);
-@@ -772,7 +780,7 @@ mt7530_port_enable(struct dsa_switch *ds
-        * restore the port matrix if the port is the member of a certain
-        * bridge.
-        */
--      priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
-+      priv->ports[port].pm |= PCR_MATRIX(BIT(upstream));
-       priv->ports[port].enable = true;
-       mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-                  priv->ports[port].pm);
-@@ -835,7 +843,8 @@ mt7530_port_bridge_join(struct dsa_switc
-                       struct net_device *bridge)
- {
-       struct mt7530_priv *priv = ds->priv;
--      u32 port_bitmap = BIT(MT7530_CPU_PORT);
-+      u8 upstream = dsa_port_upstream_port(ds, port);
-+      u32 port_bitmap = BIT(upstream);
-       int i;
-       mutex_lock(&priv->reg_mutex);
-@@ -873,6 +882,7 @@ static void
- mt7530_port_bridge_leave(struct dsa_switch *ds, int port)
- {
-       struct mt7530_priv *priv = ds->priv;
-+      u8 upstream = dsa_port_upstream_port(ds, port);
-       int i;
-       mutex_lock(&priv->reg_mutex);
-@@ -898,8 +908,8 @@ mt7530_port_bridge_leave(struct dsa_swit
-       priv->bridge_dev[port] = NULL;
-       if (priv->ports[port].enable)
-               mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
--                         PCR_MATRIX(BIT(MT7530_CPU_PORT)));
--      priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
-+                         PCR_MATRIX(BIT(upstream)));
-+      priv->ports[port].pm = PCR_MATRIX(BIT(upstream));
-       mutex_unlock(&priv->reg_mutex);
- }
diff --git a/target/linux/mediatek/patches-4.9/0103-nand_fixes.patch b/target/linux/mediatek/patches-4.9/0103-nand_fixes.patch
deleted file mode 100644 (file)
index 874661d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
---- 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
-       if (section >= eccsteps)
-               return -ERANGE;
--      oob_region->length = fdm->reg_size - fdm->ecc_size;
--      oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
-+      oob_region->length = fdm->reg_size - 1;
-+      oob_region->offset = section * fdm->reg_size + 1;
-       return 0;
- }
-@@ -1114,7 +1114,7 @@ static void mtk_nfc_set_fdm(struct mtk_n
-               fdm->reg_size = NFI_FDM_MAX_SIZE;
-       /* bad block mark storage */
--      fdm->ecc_size = 1;
-+      fdm->ecc_size = fdm->reg_size;
- }
- static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
diff --git a/target/linux/mediatek/patches-4.9/0200-devicetree.patch b/target/linux/mediatek/patches-4.9/0200-devicetree.patch
deleted file mode 100644 (file)
index 4eca20a..0000000
+++ /dev/null
@@ -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
diff --git a/target/linux/mediatek/patches-4.9/0201-block2mtd.patch b/target/linux/mediatek/patches-4.9/0201-block2mtd.patch
deleted file mode 100644 (file)
index 395884b..0000000
+++ /dev/null
@@ -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;
-       }