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 3617711..e071ab2 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 7e936c4..7161a4b 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 2a49d94..9d15a7d 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 7093d35..620ad95 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 1278b8b..bcd2df2 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 6606176..d9f08d0 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 be7bced..6f45ff6 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 574bf93..ea1474d 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",&