From: John Crispin Date: Fri, 18 Aug 2017 16:11:52 +0000 (+0200) Subject: mediatek: update to latest kernel patchset from v4.13-rc X-Git-Tag: v18.06.0-rc1~2390 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fopenwrt.git;a=commitdiff_plain;h=1f068588efddf0175e954ffc07ec8478bddd52c7 mediatek: update to latest kernel patchset from v4.13-rc Signed-off-by: Muciri Gatimu Signed-off-by: Shashidhar Lakkavalli Signed-off-by: John Crispin --- diff --git a/target/linux/mediatek/base-files/etc/board.d/02_network b/target/linux/mediatek/base-files/etc/board.d/02_network index 361771199f..e071ab27a0 100755 --- a/target/linux/mediatek/base-files/etc/board.d/02_network +++ b/target/linux/mediatek/base-files/etc/board.d/02_network @@ -9,6 +9,7 @@ mediatek_setup_interfaces() local board="$1" case $board in + 'bananapi,bpi-r2' | \ 'mediatek,mt7623-rfb-emmc' | \ 'mediatek,mt7623-rfb-nand-ephy') ucidef_set_interface_lan "lan0 lan1 lan2 lan3" diff --git a/target/linux/mediatek/base-files/etc/config/mtkhnat b/target/linux/mediatek/base-files/etc/config/mtkhnat new file mode 100644 index 0000000000..a23bd1c22b --- /dev/null +++ b/target/linux/mediatek/base-files/etc/config/mtkhnat @@ -0,0 +1,60 @@ +config global global + option enable 0 + option upstream 1000000 + option downstream 1000000 + +config queue + option id 0 + option minrate 10 + option maxrate 50 + option weight 7 + option resv 32 + +config queue + option id 1 + option minrate 30 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 2 + option minrate 30 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 3 + option minrate 30 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 4 + option minrate 25 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 5 + option minrate 25 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 6 + option minrate 25 + option maxrate 100 + option weight 7 + option resv 32 + +config queue + option id 7 + option minrate 25 + option maxrate 100 + option weight 7 + option resv 32 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 index 0000000000..32011e73aa --- /dev/null +++ b/target/linux/mediatek/base-files/etc/init.d/mtkhnat @@ -0,0 +1,13 @@ +#!/bin/sh /etc/rc.common + +START=90 + +USE_PROCD=1 +NAME=mtkhnat +PROG=/sbin/mtkhnat + +start_service() { + procd_open_instance + procd_set_param command "${PROG}" + procd_close_instance +} 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 index 0000000000..9a0dd9b5f0 --- /dev/null +++ b/target/linux/mediatek/base-files/etc/uci-defaults/99-firewall @@ -0,0 +1,9 @@ +echo "iptables -t mangle -A FORWARD -i br-lan -o eth1 -p tcp -m mark --mark 0/0x7 -j MARK --set-mark 4/0x7" >> /etc/firewall.user +echo "iptables -t mangle -A FORWARD -i br-lan -o eth1 -p udp -m mark --mark 0/0x7 -j MARK --set-mark 5/0x7" >> /etc/firewall.user +echo "iptables -t mangle -A FORWARD -i eth1 -o br-lan -p tcp -m mark --mark 0/0x7 -j MARK --set-mark 4/0x7" >> /etc/firewall.user +echo "iptables -t mangle -A FORWARD -i eth1 -o br-lan -p udp -m mark --mark 0/0x7 -j MARK --set-mark 5/0x7" >> /etc/firewall.user + +echo "iptables -t mangle -A FORWARD -p udp -m mark --mark 0/0xf8 -j MARK --or-mark 0x60" >> /etc/firewall.user +echo "iptables -t mangle -A FORWARD -p tcp -m mark --mark 0/0xf8 -j MARK --or-mark 0xc0" >> /etc/firewall.user + +exit 0 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 index 0000000000..9267340317 --- /dev/null +++ b/target/linux/mediatek/base-files/etc/uci-defaults/99-net-ps @@ -0,0 +1,16 @@ +uci set network.globals.default_rps_val=14 +uci set network.globals.default_rps_flow_cnt=256 +uci set network.globals.default_xps_val=14 +uci set network.globals.default_ps=1 +uci set network.eth0=device +uci set network.eth0.name=eth0 +uci set network.lan0=device +uci set network.lan0.name=lan0 +uci set network.lan1=device +uci set network.lan1.name=lan1 +uci set network.lan2=device +uci set network.lan2.name=lan2 +uci set network.lan3=device +uci set network.lan3.name=lan3 +uci commit +exit 0 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 index 0000000000..9a84ff4bf5 --- /dev/null +++ b/target/linux/mediatek/base-files/lib/preinit/06_set_rps_sock_flow @@ -0,0 +1,8 @@ +#!/bin/sh + +set_rps_sock_flow() { + echo 1024 > /proc/sys/net/core/rps_sock_flow_entries +} + +boot_hook_add preinit_main set_rps_sock_flow + diff --git a/target/linux/mediatek/base-files/lib/upgrade/platform.sh b/target/linux/mediatek/base-files/lib/upgrade/platform.sh index 7e936c4dad..7161a4b84e 100755 --- a/target/linux/mediatek/base-files/lib/upgrade/platform.sh +++ b/target/linux/mediatek/base-files/lib/upgrade/platform.sh @@ -25,6 +25,7 @@ platform_check_image() { nand_do_platform_check $board $1 return $? ;; + bananapi,bpi-r2 |\ mediatek,mt7623-rfb-emmc) local kernel_length=`(tar xf $tar_file sysupgrade-$board/kernel -O | wc -c) 2> /dev/null` local rootfs_length=`(tar xf $tar_file sysupgrade-$board/root -O | wc -c) 2> /dev/null` diff --git a/target/linux/mediatek/base-files/sbin/mtkhnat b/target/linux/mediatek/base-files/sbin/mtkhnat new file mode 100755 index 0000000000..fdfc8427c5 --- /dev/null +++ b/target/linux/mediatek/base-files/sbin/mtkhnat @@ -0,0 +1,64 @@ +#!/bin/sh + +. /lib/functions.sh + +config_load mtkhnat +config_get enable global enable 0 + +[ "${enable}" -eq 1 ] || { + echo 0 ${sch_upstream} > /sys/kernel/debug/hnat/scheduler0 + echo 0 ${sch_downstream} > /sys/kernel/debug/hnat/scheduler1 + + rmmod mtkhnat + exit 0 +} + +insmod mtkhnat + +sleep 1 + +config_get sch_upstream global upstream 100000 +config_get sch_downstream global downstream 100000 + +echo 1 ${sch_upstream} > /sys/kernel/debug/hnat/scheduler0 +echo 1 ${sch_downstream} > /sys/kernel/debug/hnat/scheduler1 + +setup_queue() { + local queue_id queue_scheduler queue_minebl queue_maxebl queue_minrate queue_maxrate queue_resv minrate maxrate queue_weight + + config_get queue_id $1 id 0 + config_get queue_minrate $1 minrate 0 + config_get queue_maxrate $1 maxrate 0 + config_get queue_resv $1 resv 22 + config_get queue_weight $1 weight 7 + + [ "${queue_id}" -gt 7 ] && return 0 + + queue_minebl=1 + queue_maxebl=1 + queue_scheduler=0 + + [ "${queue_minrate}" -eq 0 ] && queue_minebl=0 + [ "${queue_maxrate}" -eq 0 ] && queue_maxebl=0 + + minrate=$((sch_upstream * $queue_minrate)) + minrate=$((minrate / 100)) + + maxrate=$((sch_upstream * $queue_maxrate)) + maxrate=$((maxrate / 100)) + + echo 0 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} ${queue_resv} > /sys/kernel/debug/hnat/queue${queue_id} + + queue_id=$((queue_id + 8)) + + minrate=$((sch_downstream * $queue_minrate)) + minrate=$((minrate / 100)) + + maxrate=$((sch_downstream * $queue_maxrate)) + maxrate=$((maxrate / 100)) + + echo 1 ${queue_minebl} ${minrate} ${queue_maxebl} ${maxrate} ${queue_weight} ${queue_resv} > /sys/kernel/debug/hnat/queue${queue_id} +} + +config_foreach setup_scheduler scheduler +config_foreach setup_queue queue diff --git a/target/linux/mediatek/config-4.9 b/target/linux/mediatek/config-4.9 index 2a49d94723..9d15a7d631 100644 --- a/target/linux/mediatek/config-4.9 +++ b/target/linux/mediatek/config-4.9 @@ -45,7 +45,6 @@ CONFIG_ARM_UNWIND=y CONFIG_ARM_VIRT_EXT=y CONFIG_ATAGS=y CONFIG_AUTO_ZRELADDR=y -# CONFIG_BINFMT_FLAT is not set CONFIG_BLK_MQ_PCI=y # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 @@ -104,13 +103,29 @@ CONFIG_CRC32_SLICEBY8=y CONFIG_CROSS_MEMORY_ATTACH=y CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_MEDIATEK=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y CONFIG_CRYPTO_LZO=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_RNG=y CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_WORKQUEUE=y CONFIG_DCACHE_WORD_ACCESS=y CONFIG_DEBUG_BUGVERBOSE=y @@ -213,6 +228,7 @@ CONFIG_HIGHMEM=y CONFIG_HOTPLUG_CPU=y CONFIG_HWMON=y CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MTK=y CONFIG_HZ_FIXED=0 CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y @@ -254,7 +270,6 @@ CONFIG_MDIO_GPIO=y CONFIG_MEDIATEK_MT6577_AUXADC=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MFD_CORE=y -# CONFIG_MFD_MAX77620 is not set CONFIG_MFD_MT6397=y CONFIG_MFD_SYSCON=y CONFIG_MIGHT_HAVE_CACHE_L2X0=y @@ -275,7 +290,6 @@ CONFIG_MTD_MT81xx_NOR=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_MTK=y -# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_BEB_LIMIT=20 @@ -300,6 +314,8 @@ CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y +# CONFIG_NET_MEDIATEK_HNAT is not set +CONFIG_NET_MEDIATEK_HW_QOS=y CONFIG_NET_MEDIATEK_SOC=y CONFIG_NET_SWITCHDEV=y # CONFIG_NET_VENDOR_AURORA is not set @@ -329,7 +345,10 @@ CONFIG_OLD_SIGSUSPEND3=y CONFIG_PADATA=y CONFIG_PAGE_OFFSET=0xC0000000 CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y CONFIG_PCIE_MTK=y +CONFIG_PCIE_PME=y CONFIG_PCI_DOMAINS=y CONFIG_PCI_DOMAINS_GENERIC=y CONFIG_PCI_MSI=y @@ -366,6 +385,7 @@ CONFIG_PWM=y CONFIG_PWM_MEDIATEK=y # CONFIG_PWM_MTK_DISP is not set CONFIG_PWM_SYSFS=y +CONFIG_RAS=y CONFIG_RATIONAL=y CONFIG_RCU_CPU_STALL_TIMEOUT=21 # CONFIG_RCU_EXPERT is not set diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi index 7093d35131..620ad95e76 100644 --- a/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi +++ b/target/linux/mediatek/files/arch/arm/boot/dts/_mt7623.dtsi @@ -19,6 +19,7 @@ #include #include #include +#include #include "skeleton64.dtsi" @@ -151,7 +152,7 @@ }; pio: pinctrl@10005000 { - compatible = "mediatek,mt2701-pinctrl"; + compatible = "mediatek,mt7623-pinctrl"; reg = <0 0x1000b000 0 0x1000>; mediatek,pctl-regmap = <&syscfg_pctl_a>; pins-are-numbered; @@ -211,6 +212,15 @@ clock-names = "spi", "wrap"; }; + cir: cir@10013000 { + compatible = "mediatek,mt7623-cir"; + reg = <0 0x10013000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_IRRX>; + clock-names = "clk"; + status = "disabled"; + }; + sysirq: interrupt-controller@10200100 { compatible = "mediatek,mt7623-sysirq", "mediatek,mt6577-sysirq"; @@ -240,6 +250,13 @@ #clock-cells = <1>; }; + rng: rng@1020f000 { + compatible = "mediatek,mt7623-rng"; + reg = <0 0x1020f000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_TRNG>; + clock-names = "rng"; + }; + gic: interrupt-controller@10211000 { compatible = "arm,cortex-a7-gic"; interrupt-controller; @@ -370,7 +387,7 @@ status = "disabled"; }; - spi: spi@1100a000 { + spi0: spi@1100a000 { compatible = "mediatek,mt7623-spi", "mediatek,mt6589-spi"; reg = <0 0x1100a000 0 0x1000>; @@ -399,6 +416,34 @@ nvmem-cell-names = "calibration-data"; }; + spi1: spi@11016000 { + compatible = "mediatek,mt7623-spi", + "mediatek,mt2701-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11016000 0 0x100>; + interrupts = ; + 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 = ; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI2_SEL>, + <&pericfg CLK_PERI_SPI2>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + nandc: nfi@1100d000 { compatible = "mediatek,mt7623-nfc", "mediatek,mt2701-nfc"; @@ -424,6 +469,104 @@ status = "disabled"; }; + afe: audio-controller@11220000 { + compatible = "mediatek,mt7623-audio", + "mediatek,mt2701-audio"; + reg = <0 0x11220000 0 0x2000>, + <0 0x112a0000 0 0x20000>; + interrupts = ; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUDPLL_MUX_SEL>, + <&topckgen CLK_TOP_APLL_SEL>, + <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>, + <&topckgen CLK_TOP_HADDS2PLL_98M>, + <&topckgen CLK_TOP_HADDS2PLL_294M>, + <&topckgen CLK_TOP_AUDPLL>, + <&topckgen CLK_TOP_AUDPLL_D4>, + <&topckgen CLK_TOP_AUDPLL_D8>, + <&topckgen CLK_TOP_AUDPLL_D16>, + <&topckgen CLK_TOP_AUDPLL_D24>, + <&topckgen CLK_TOP_AUDINTBUS_SEL>, + <&clk26m>, + <&topckgen CLK_TOP_SYSPLL1_D4>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K5_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K6_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K5_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K6_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&topckgen CLK_TOP_AUD_I2S5_MCLK>, + <&topckgen CLK_TOP_AUD_I2S6_MCLK>, + <&topckgen CLK_TOP_ASM_M_SEL>, + <&topckgen CLK_TOP_ASM_H_SEL>, + <&topckgen CLK_TOP_UNIVPLL2_D4>, + <&topckgen CLK_TOP_UNIVPLL2_D2>, + <&topckgen CLK_TOP_SYSPLL_D5>; + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_mux1_div", + "top_audio_mux2_div", + "top_audio_48k_timing", + "top_audio_44k_timing", + "top_audpll_mux_sel", + "top_apll_sel", + "top_aud1_pll_98M", + "top_aud2_pll_90M", + "top_hadds2_pll_98M", + "top_hadds2_pll_294M", + "top_audpll", + "top_audpll_d4", + "top_audpll_d8", + "top_audpll_d16", + "top_audpll_d24", + "top_audintbus_sel", + "clk_26m", + "top_syspll1_d4", + "top_aud_k1_src_sel", + "top_aud_k2_src_sel", + "top_aud_k3_src_sel", + "top_aud_k4_src_sel", + "top_aud_k5_src_sel", + "top_aud_k6_src_sel", + "top_aud_k1_src_div", + "top_aud_k2_src_div", + "top_aud_k3_src_div", + "top_aud_k4_src_div", + "top_aud_k5_src_div", + "top_aud_k6_src_div", + "top_aud_i2s1_mclk", + "top_aud_i2s2_mclk", + "top_aud_i2s3_mclk", + "top_aud_i2s4_mclk", + "top_aud_i2s5_mclk", + "top_aud_i2s6_mclk", + "top_asm_m_sel", + "top_asm_h_sel", + "top_univpll2_d4", + "top_univpll2_d2", + "top_syspll_d5"; + }; + mmc0: mmc@11230000 { compatible = "mediatek,mt7623-mmc", "mediatek,mt8135-mmc"; @@ -636,4 +779,26 @@ #size-cells = <0>; }; }; + + hnat: hnat@1b000000 { + compatible = "mediatek,mt7623-hnat"; + reg = <0 0x1b100000 0 0x3000>; + mtketh-wan = "eth1"; + resets = <ðsys 0>; + reset-names = "mtketh"; + }; + + crypto: crypto@1b240000 { + compatible = "mediatek,mt7623-crypto", "mediatek,eip97-crypto"; + reg = <0 0x1b240000 0 0x20000>; + interrupts = , + , + , + , + ; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <ðsys 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 index 0000000000..7c783d6c75 --- /dev/null +++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt6323.dtsi @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: John Crispin + * Sean Wang + * 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>; + }; + }; + }; +}; diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts index 1278b8bf0d..bcd2df264d 100644 --- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts +++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND-ePHY.dts @@ -363,13 +363,6 @@ ; }; - pins_eth_esw { - pinmux = ; - input-enable; - drive-strength = ; - bias-pull-up; - }; - pins_eth_rst { pinmux = ; output-low; diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts index 6606176d4d..d9f08d015d 100644 --- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts +++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-NAND.dts @@ -363,13 +363,6 @@ ; }; - pins_eth_esw { - pinmux = ; - input-enable; - drive-strength = ; - bias-pull-up; - }; - pins_eth_rst { pinmux = ; output-low; diff --git a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts index be7bced254..6f45ff6863 100644 --- a/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts +++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623-eMMC.dts @@ -38,6 +38,61 @@ gpio = <&pio 135 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + switch { + compatible = "mediatek,mt7530"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + dsa,mii-bus = <&mdio0>; + + pinctrl-names = "default"; + pinctrl-0 = <ð_default>; + + core-supply = <&mt6323_vpa_reg>; + io-supply = <&mt6323_vemc3v3_reg>; + + mediatek,mcm; + resets = <ðsys 2>; + reset-names = "mcm"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + port@0 { + reg = <0>; + label = "lan0"; + }; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac1>; + phy-mode = "trgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; }; &cpu0 { @@ -428,7 +483,6 @@ , , , - , ; }; @@ -480,59 +534,6 @@ }; &mdio0 { - switch@0 { - compatible = "mediatek,mt7530"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0>; - - pinctrl-names = "default"; - pinctrl-0 = <ð_default>; - - core-supply = <&mt6323_vpa_reg>; - io-supply = <&mt6323_vemc3v3_reg>; - - mediatek,mcm; - resets = <ðsys 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 index 0000000000..a66956e26c --- /dev/null +++ b/target/linux/mediatek/files/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts @@ -0,0 +1,443 @@ +/* + * Copyright 2017 Sean Wang + * + * SPDX-License-Identifier: (GPL-2.0+ OR MIT) + */ + +/dts-v1/; +#include +#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 = ; + gpios = <&pio 256 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "wps"; + linux,code = ; + 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"; +}; + +ð { + 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 = ; + bias-disable; + }; + }; + + i2c0_pins_a: i2c@0 { + pins_i2c0 { + pinmux = , + ; + bias-disable; + }; + }; + + i2c1_pins_a: i2c@1 { + pin_i2c1 { + pinmux = , + ; + bias-disable; + }; + }; + + i2s0_pins_a: i2s@0 { + pin_i2s0 { + pinmux = , + , + , + , + ; + drive-strength = ; + bias-pull-down; + }; + }; + + i2s1_pins_a: i2s@1 { + pin_i2s1 { + pinmux = , + , + , + , + ; + drive-strength = ; + bias-pull-down; + }; + }; + + key_pins_a: keys@0 { + pins_keys { + pinmux = , + ; + input-enable; + }; + }; + + led_pins_a: leds@0 { + pins_leds { + pinmux = , + , + ; + }; + }; + + mmc0_pins_default: mmc0default { + pins_cmd_dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + bias-pull-up; + }; + + pins_clk { + pinmux = ; + bias-pull-down; + }; + + pins_rst { + pinmux = ; + bias-pull-up; + }; + }; + + mmc0_pins_uhs: mmc0 { + pins_cmd_dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + drive-strength = ; + bias-pull-down = ; + }; + + pins_rst { + pinmux = ; + bias-pull-up; + }; + }; + + mmc1_pins_default: mmc1default { + pins_cmd_dat { + pinmux = , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + bias-pull-down; + drive-strength = ; + }; + }; + + mmc1_pins_uhs: mmc1 { + pins_cmd_dat { + pinmux = , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up = ; + }; + + pins_clk { + pinmux = ; + drive-strength = ; + bias-pull-down = ; + }; + }; + + spi0_pins_a: spi@0 { + pins_spi { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + pwm_pins_a: pwm@0 { + pins_pwm { + pinmux = , + , + , + , + ; + }; + }; + + uart0_pins_a: uart@0 { + pins_dat { + pinmux = , + ; + }; + }; + + uart1_pins_a: uart@1 { + pins_dat { + pinmux = , + ; + }; + }; +}; + +&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 index 0000000000..df8eb54fd5 --- /dev/null +++ b/target/linux/mediatek/files/drivers/char/hw_random/mtk-rng.c @@ -0,0 +1,168 @@ +/* + * Driver for Mediatek Hardware Random Number Generator + * + * Copyright (C) 2017 Sean Wang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 index 0000000000..187be79c7f --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mtk-crypto.o +mtk-crypto-objs:= mtk-platform.o mtk-aes.o mtk-sha.o 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 index 0000000000..9e845e866d --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-aes.c @@ -0,0 +1,1304 @@ +/* + * Cryptographic API. + * + * Driver for EIP97 AES acceleration. + * + * Copyright (c) 2016 Ryder Lee + * + * 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 +#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 index 0000000000..b6ecc288b5 --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.c @@ -0,0 +1,607 @@ +/* + * Driver for EIP97 cryptographic accelerator. + * + * Copyright (c) 2016 Ryder Lee + * + * 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 +#include +#include +#include +#include +#include +#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 "); +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 index 0000000000..303c152dc9 --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-platform.h @@ -0,0 +1,237 @@ +/* + * Driver for EIP97 cryptographic accelerator. + * + * Copyright (c) 2016 Ryder Lee + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000000..94f4eb85be --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-regs.h @@ -0,0 +1,194 @@ +/* + * Support for MediaTek cryptographic accelerator. + * + * Copyright (c) 2016 MediaTek Inc. + * Author: Ryder Lee + * + * 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 index 0000000000..2226f12d1c --- /dev/null +++ b/target/linux/mediatek/files/drivers/crypto/mediatek/mtk-sha.c @@ -0,0 +1,1358 @@ +/* + * Cryptographic API. + * + * Driver for EIP97 SHA1/SHA2(HMAC) acceleration. + * + * Copyright (c) 2016 Ryder Lee + * + * 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 +#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); +} diff --git a/target/linux/mediatek/image/32.mk b/target/linux/mediatek/image/32.mk index 574bf9395e..ea1474dc85 100644 --- a/target/linux/mediatek/image/32.mk +++ b/target/linux/mediatek/image/32.mk @@ -1,6 +1,6 @@ define Image/BuilduImage $(CP) $(KDIR)/zImage$(2) $(KDIR)/zImage-$(1)$(2) - cat $(LINUX_DIR)/arch/arm/boot/dts/mt7623-$1.dtb >> $(KDIR)/zImage-$(1)$(2) + cat $(LINUX_DIR)/arch/arm/boot/dts/$1.dtb >> $(KDIR)/zImage-$(1)$(2) mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' -d $(KDIR)/zImage-$(1)$(2) $(KDIR)/uImage-$(1)$(2) endef @@ -20,6 +20,7 @@ endif ) endef +COMPAT_BPI-R2:=bananapi,bpi-r2 COMPAT_EMMC:=mediatek,mt7623-rfb-emmc COMPAT_NAND:=mediatek,mt7623-rfb-nand COMPAT_NAND_EPHY:=mediatek,mt7623-rfb-nand-ephy @@ -28,16 +29,17 @@ define Image/Build/squashfs $(call prepare_generic_squashfs,$(KDIR)/root.squashfs) $(CP) $(KDIR)/root.squashfs $(BIN_DIR)/$(IMG_PREFIX)-root.squashfs - $(call Image/Build/SysupgradeCombined,eMMC,squashfs,$$(COMPAT_EMMC)) + $(call Image/Build/SysupgradeCombined,mt7623n-bananapi-bpi-r2,squashfs,$$(COMPAT_EMMC)) + $(call Image/Build/SysupgradeCombined,mt7623-eMMC,squashfs,$$(COMPAT_BPI-R2)) - $(call Image/BuilduImage,NAND) - $(call Image/BuilduImage,NAND-ePHY) + $(call Image/BuilduImage,mt7623-NAND) + $(call Image/BuilduImage,mt7623-NAND-ePHY) ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) - $(call Image/BuilduImage,NAND,-initramfs) - $(call Image/BuilduImage,NAND-ePHY,-initramfs) - $(CP) $(KDIR)/uImage-NAND-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-initramfs - $(CP) $(KDIR)/uImage-NAND-ePHY-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-ePHY-initramfs + $(call Image/BuilduImage,mt7623-NAND,-initramfs) + $(call Image/BuilduImage,mt7623-NAND-ePHY,-initramfs) + $(CP) $(KDIR)/uImage-mt7623-NAND-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-initramfs + $(CP) $(KDIR)/uImage-mt7623-NAND-ePHY-initramfs $(BIN_DIR)/$(IMG_PREFIX)-uImage-NAND-ePHY-initramfs endif - $(call Image/Build/SysupgradeNAND,NAND,$(1),$(KDIR)/uImage-NAND,$$(COMPAT_NAND)) - $(call Image/Build/SysupgradeNAND,NAND-ePHY,$(1),$(KDIR)/uImage-NAND-ePHY,$$(COMPAT_NAND_EPHY)) + $(call Image/Build/SysupgradeNAND,mt7623-NAND,$(1),$(KDIR)/uImage-mt7623-NAND,$$(COMPAT_NAND)) + $(call Image/Build/SysupgradeNAND,mt7623-NAND-ePHY,$(1),$(KDIR)/uImage-mt7623-NAND-ePHY,$$(COMPAT_NAND_EPHY)) endef diff --git a/target/linux/mediatek/modules.mk b/target/linux/mediatek/modules.mk new file mode 100644 index 0000000000..447ae119e1 --- /dev/null +++ b/target/linux/mediatek/modules.mk @@ -0,0 +1,14 @@ +define KernelPackage/mediatek_hnat + SUBMENU:=Network Devices + TITLE:=MT7623 HNAT + DEPENDS:=@TARGET_mediatek +kmod-nf-conntrack +iptables-mod-ipmark + KCONFIG:= CONFIG_NET_MEDIATEK_HNAT=y + FILES:= \ + $(LINUX_DIR)/drivers/net/ethernet/mediatek/mtk_hnat/mtkhnat.ko +endef + +define KernelPackage/mediatek_hnat/description + Kernel modules for MediaTek HW NAT offloading +endef + +$(eval $(call KernelPackage,mediatek_hnat)) 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 index 282c28da0f..0000000000 --- a/target/linux/mediatek/patches-4.9/0000-pinctrl-esw.patch +++ /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 index 0e8ce0cbbf..0000000000 --- a/target/linux/mediatek/patches-4.9/0001-NET-multi-phy-support.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 1e021917e634b173d466bf0dd3d2ae84e51a77ff Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Sun, 27 Jul 2014 09:38:50 +0100 -Subject: [PATCH 001/102] NET: multi phy support - -Signed-off-by: John Crispin ---- - 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 index 0000000000..ff04a9f1e5 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0001-arch-arm-add-dts-build-code.patch @@ -0,0 +1,23 @@ +From 9fdcf63545855f3a6f82dee109510f4735e861c8 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:54:13 +0200 +Subject: [PATCH 01/57] arch: arm: add dts build code + +Signed-off-by: John Crispin +--- + 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 index ce38640ab9..0000000000 --- a/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001 -From: Shunli Wang -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 -Signed-off-by: James Liao -Acked-by: Rob Herring -Reviewed-by: Kevin Hilman -Signed-off-by: Matthias Brugger ---- - .../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 index 0000000000..9dd6fcd01d --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0002-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch @@ -0,0 +1,154 @@ +From ad2d4df46d8ef6a7aab20f0b668fa7db5257cbea Mon Sep 17 00:00:00 2001 +From: John Crispin +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 +--- + .../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 = , ++ , ++ ; ++ 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 index 0000000000..43f51ef6b3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0003-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch @@ -0,0 +1,698 @@ +From 950bd9b0691dd10209c333086a6bdda0108ed3a8 Mon Sep 17 00:00:00 2001 +From: John Crispin +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 +--- + 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 ++ * Copyright (C) 2015 John Crispin ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 index 0000000000..8d91b121d7 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch @@ -0,0 +1,75 @@ +From 2f47c01fe3015f4c649849ddffe04f12a122abe2 Mon Sep 17 00:00:00 2001 +From: Shunli Wang +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 +Signed-off-by: James Liao +Acked-by: Rob Herring +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + .../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 index 0000000000..ef40ba2345 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0005-clk-mediatek-Add-MT2701-clock-support.patch @@ -0,0 +1,1431 @@ +From f76b34c799d87ab241432b1241f6fc6d9db3ecb6 Mon Sep 17 00:00:00 2001 +From: Shunli Wang +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 +Signed-off-by: James Liao +--- + 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 ++ * ++ * 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 ++#include ++#include ++ ++#include "clk-mtk.h" ++#include "clk-gate.h" ++ ++#include ++ ++static DEFINE_SPINLOCK(lock); ++ ++static const struct mtk_fixed_clk top_fixed_clks[] __initconst = { ++ FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m", 108 * MHZ), ++ FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m", 400 * MHZ), ++ FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m", 295750000), ++ FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m", 340 * MHZ), ++ FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m", 340 * MHZ), ++ FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", 340 * MHZ), ++ FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m", 300 * MHZ), ++ FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", 27 * MHZ), ++ FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", 416 * MHZ), ++}; ++ ++static const struct mtk_fixed_factor top_fixed_divs[] __initconst = { ++ FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1), ++ FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2), ++ FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3), ++ FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5), ++ FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7), ++ FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2), ++ FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4), ++ FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8), ++ FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16), ++ FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2), ++ FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4), ++ FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8), ++ FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2), ++ FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4), ++ FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2), ++ FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4), ++ ++ FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1), ++ FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), ++ FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), ++ FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), ++ FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7), ++ FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26), ++ FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52), ++ FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108), ++ FACTOR(CLK_TOP_USB_PHY48M, "USB_PHY48M_CK", "univpll", 1, 26), ++ FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2), ++ FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4), ++ FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8), ++ FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1), ++ FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2), ++ FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4), ++ FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8), ++ FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16), ++ FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32), ++ FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2), ++ FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4), ++ FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8), ++ ++ FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1), ++ FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), ++ FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4), ++ FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8), ++ ++ FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1), ++ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), ++ ++ FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2), ++ FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4), ++ FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1), ++ ++ FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1), ++ FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2), ++ FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4), ++ ++ FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1), ++ FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1), ++ FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2), ++ ++ FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1), ++ FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2), ++ FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4), ++ ++ FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1), ++ FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2), ++ FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3), ++ ++ FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1), ++ ++ FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1), ++ FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4), ++ FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8), ++ FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16), ++ FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24), ++ ++ FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3), ++ FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3), ++ FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3), ++ FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1), ++ FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1), ++ FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8), ++ FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793), ++ FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1), ++}; ++ ++static const char * const axi_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d2", ++ "syspll_d5", ++ "syspll1_d4", ++ "univpll_d5", ++ "univpll2_d2", ++ "mmpll_d2", ++ "dmpll_d2" ++}; ++ ++static const char * const mem_parents[] __initconst = { ++ "clk26m", ++ "dmpll_ck" ++}; ++ ++static const char * const ddrphycfg_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d8" ++}; ++ ++static const char * const mm_parents[] __initconst = { ++ "clk26m", ++ "vencpll_ck", ++ "syspll1_d2", ++ "syspll1_d4", ++ "univpll_d5", ++ "univpll1_d2", ++ "univpll2_d2", ++ "dmpll_ck" ++}; ++ ++static const char * const pwm_parents[] __initconst = { ++ "clk26m", ++ "univpll2_d4", ++ "univpll3_d2", ++ "univpll1_d4", ++}; ++ ++static const char * const vdec_parents[] __initconst = { ++ "clk26m", ++ "vdecpll_ck", ++ "syspll_d5", ++ "syspll1_d4", ++ "univpll_d5", ++ "univpll2_d2", ++ "vencpll_ck", ++ "msdcpll_d2", ++ "mmpll_d2" ++}; ++ ++static const char * const mfg_parents[] __initconst = { ++ "clk26m", ++ "mmpll_ck", ++ "dmpll_x2_ck", ++ "msdcpll_ck", ++ "clk26m", ++ "syspll_d3", ++ "univpll_d3", ++ "univpll1_d2" ++}; ++ ++static const char * const camtg_parents[] __initconst = { ++ "clk26m", ++ "univpll_d26", ++ "univpll2_d2", ++ "syspll3_d2", ++ "syspll3_d4", ++ "msdcpll_d2", ++ "mmpll_d2" ++}; ++ ++static const char * const uart_parents[] __initconst = { ++ "clk26m", ++ "univpll2_d8" ++}; ++ ++static const char * const spi_parents[] __initconst = { ++ "clk26m", ++ "syspll3_d2", ++ "syspll4_d2", ++ "univpll2_d4", ++ "univpll1_d8" ++}; ++ ++static const char * const usb20_parents[] __initconst = { ++ "clk26m", ++ "univpll1_d8", ++ "univpll3_d4" ++}; ++ ++static const char * const msdc30_parents[] __initconst = { ++ "clk26m", ++ "msdcpll_d2", ++ "syspll2_d2", ++ "syspll1_d4", ++ "univpll1_d4", ++ "univpll2_d4" ++}; ++ ++static const char * const audio_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d16" ++}; ++ ++static const char * const aud_intbus_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d4", ++ "syspll3_d2", ++ "syspll4_d2", ++ "univpll3_d2", ++ "univpll2_d4" ++}; ++ ++static const char * const pmicspi_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d8", ++ "syspll2_d4", ++ "syspll4_d2", ++ "syspll3_d4", ++ "syspll2_d8", ++ "syspll1_d16", ++ "univpll3_d4", ++ "univpll_d26", ++ "dmpll_d2", ++ "dmpll_d4" ++}; ++ ++static const char * const scp_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d8", ++ "dmpll_d2", ++ "dmpll_d4" ++}; ++ ++static const char * const dpi0_parents[] __initconst = { ++ "clk26m", ++ "mipipll", ++ "mipipll_d2", ++ "mipipll_d4", ++ "clk26m", ++ "tvdpll_ck", ++ "tvdpll_d2", ++ "tvdpll_d4" ++}; ++ ++static const char * const dpi1_parents[] __initconst = { ++ "clk26m", ++ "tvdpll_ck", ++ "tvdpll_d2", ++ "tvdpll_d4" ++}; ++ ++static const char * const tve_parents[] __initconst = { ++ "clk26m", ++ "mipipll", ++ "mipipll_d2", ++ "mipipll_d4", ++ "clk26m", ++ "tvdpll_ck", ++ "tvdpll_d2", ++ "tvdpll_d4" ++}; ++ ++static const char * const hdmi_parents[] __initconst = { ++ "clk26m", ++ "hdmipll_ck", ++ "hdmipll_d2", ++ "hdmipll_d3" ++}; ++ ++static const char * const apll_parents[] __initconst = { ++ "clk26m", ++ "audpll", ++ "audpll_d4", ++ "audpll_d8", ++ "audpll_d16", ++ "audpll_d24", ++ "clk26m", ++ "clk26m" ++}; ++ ++static const char * const rtc_parents[] __initconst = { ++ "32k_internal", ++ "32k_external", ++ "clk26m", ++ "univpll3_d8" ++}; ++ ++static const char * const nfi2x_parents[] __initconst = { ++ "clk26m", ++ "syspll2_d2", ++ "syspll_d7", ++ "univpll3_d2", ++ "syspll2_d4", ++ "univpll3_d4", ++ "syspll4_d4", ++ "clk26m" ++}; ++ ++static const char * const emmc_hclk_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d2", ++ "syspll1_d4", ++ "syspll2_d2" ++}; ++ ++static const char * const flash_parents[] __initconst = { ++ "clk26m_d8", ++ "clk26m", ++ "syspll2_d8", ++ "syspll3_d4", ++ "univpll3_d4", ++ "syspll4_d2", ++ "syspll2_d4", ++ "univpll2_d4" ++}; ++ ++static const char * const di_parents[] __initconst = { ++ "clk26m", ++ "tvd2pll_ck", ++ "tvd2pll_d2", ++ "clk26m" ++}; ++ ++static const char * const nr_osd_parents[] __initconst = { ++ "clk26m", ++ "vencpll_ck", ++ "syspll1_d2", ++ "syspll1_d4", ++ "univpll_d5", ++ "univpll1_d2", ++ "univpll2_d2", ++ "dmpll_ck" ++}; ++ ++static const char * const hdmirx_bist_parents[] __initconst = { ++ "clk26m", ++ "syspll_d3", ++ "clk26m", ++ "syspll1_d16", ++ "syspll4_d2", ++ "syspll1_d4", ++ "vencpll_ck", ++ "clk26m" ++}; ++ ++static const char * const intdir_parents[] __initconst = { ++ "clk26m", ++ "mmpll_ck", ++ "syspll_d2", ++ "univpll_d2" ++}; ++ ++static const char * const asm_parents[] __initconst = { ++ "clk26m", ++ "univpll2_d4", ++ "univpll2_d2", ++ "syspll_d5" ++}; ++ ++static const char * const ms_card_parents[] __initconst = { ++ "clk26m", ++ "univpll3_d8", ++ "syspll4_d4" ++}; ++ ++static const char * const ethif_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d2", ++ "syspll_d5", ++ "syspll1_d4", ++ "univpll_d5", ++ "univpll1_d2", ++ "dmpll_ck", ++ "dmpll_d2" ++}; ++ ++static const char * const hdmirx_parents[] __initconst = { ++ "clk26m", ++ "univpll_d52" ++}; ++ ++static const char * const cmsys_parents[] __initconst = { ++ "clk26m", ++ "syspll1_d2", ++ "univpll1_d2", ++ "univpll_d5", ++ "syspll_d5", ++ "syspll2_d2", ++ "syspll1_d4", ++ "syspll3_d2", ++ "syspll2_d4", ++ "syspll1_d8", ++ "clk26m", ++ "clk26m", ++ "clk26m", ++ "clk26m", ++ "clk26m" ++}; ++ ++static const char * const clk_8bdac_parents[] __initconst = { ++ "clkrtc_int", ++ "8bdac_ck_pre", ++ "clk26m", ++ "clk26m" ++}; ++ ++static const char * const aud2dvd_parents[] __initconst = { ++ "a1sys_hp_ck", ++ "a2sys_hp_ck" ++}; ++ ++static const char * const padmclk_parents[] __initconst = { ++ "clk26m", ++ "univpll_d26", ++ "univpll_d52", ++ "univpll_d108", ++ "univpll2_d8", ++ "univpll2_d16", ++ "univpll2_d32" ++}; ++ ++static const char * const aud_mux_parents[] __initconst = { ++ "clk26m", ++ "aud1pll_98m_ck", ++ "aud2pll_90m_ck", ++ "hadds2pll_98m", ++ "audio_ext1_ck", ++ "audio_ext2_ck" ++}; ++ ++static const char * const aud_src_parents[] __initconst = { ++ "aud_mux1_sel", ++ "aud_mux2_sel" ++}; ++ ++static const char * const cpu_parents[] __initconst = { ++ "clk26m", ++ "armpll", ++ "mainpll", ++ "mmpll" ++}; ++ ++static const struct mtk_composite top_muxes[] __initconst = { ++ MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, ++ 0x0040, 0, 3, INVALID_MUX_GATE_BIT), ++ MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1, 15), ++ MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23), ++ MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7), ++ MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15), ++ MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 16, 3, 23), ++ MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0050, 24, 3, 31), ++ MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 0, 1, 7), ++ ++ MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents, 0x0060, 8, 3, 15), ++ MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 16, 2, 23), ++ MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0060, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0070, 0, 3, 7), ++ MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0070, 8, 3, 15), ++ MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents, 0x0070, 16, 1, 23), ++ MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0070, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0080, 0, 4, 7), ++ MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0080, 8, 2, 15), ++ MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x0080, 16, 3, 23), ++ MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0080, 24, 2, 31), ++ ++ MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, 0x0090, 0, 3, 7), ++ MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x0090, 8, 2, 15), ++ MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0090, 16, 3, 23), ++ ++ MUX_GATE(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00A0, 0, 2, 7), ++ MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, 0x00A0, 8, 3, 15), ++ MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents, 0x00A0, 24, 2, 31), ++ ++ MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, 0x00B0, 0, 3, 7), ++ MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, 0x00B0, 8, 2, 15), ++ MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents, 0x00B0, 16, 3, 23), ++ MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents, 0x00B0, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel", hdmirx_bist_parents, 0x00C0, 0, 3, 7), ++ MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, 0x00C0, 8, 2, 15), ++ MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents, 0x00C0, 16, 2, 23), ++ MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents, 0x00C0, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents, 0x00D0, 0, 2, 7), ++ MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents, 0x00D0, 16, 2, 23), ++ MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents, 0x00D0, 24, 3, 31), ++ ++ MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents, 0x00E0, 0, 1, 7), ++ MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x00E0, 8, 3, 15), ++ MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, 0x00E0, 16, 4, 23), ++ ++ MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents, 0x00E0, 24, 3, 31), ++ MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents, 0x00F0, 0, 3, 7), ++ MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents, 0x00F0, 8, 2, 15), ++ MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents, 0x00F0, 16, 1, 23), ++ ++ MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents, 0x0100, 0, 3), ++ ++ MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents, 0x012c, 0, 3), ++ MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents, 0x012c, 3, 3), ++ MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents, 0x012c, 6, 3), ++ MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents, 0x012c, 15, 1, 23), ++ MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents, 0x012c, 16, 1, 24), ++ MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents, 0x012c, 17, 1, 25), ++ MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents, 0x012c, 18, 1, 26), ++ MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents, 0x012c, 19, 1, 27), ++ MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents, 0x012c, 20, 1, 28), ++}; ++ ++static const struct mtk_clk_divider top_adj_divs[] __initconst = { ++ DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext_ck1", 0x0120, 0, 8), ++ DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext_ck2", 0x0120, 8, 8), ++ DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel", 0x0120, 16, 8), ++ DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel", 0x0120, 24, 8), ++ DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel", 0x0124, 0, 8), ++ DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel", 0x0124, 8, 8), ++ DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel", 0x0124, 16, 8), ++ DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel", 0x0124, 24, 8), ++ DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel", 0x0128, 0, 8), ++ DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel", 0x0128, 8, 8), ++}; ++ ++static const struct mtk_gate_regs top_aud_cg_regs __initconst = { ++ .sta_ofs = 0x012C, ++}; ++ ++#define GATE_TOP_AUD(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &top_aud_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_no_setclr, \ ++ } ++ ++static const struct mtk_gate top_clks[] __initconst = { ++ GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", 21), ++ GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div", 22), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div", 23), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div", 24), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div", 25), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div", 26), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div", 27), ++ GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28), ++}; ++ ++static void __init mtk_topckgen_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ void __iomem *base; ++ int r; ++ ++ base = of_iomap(node, 0); ++ if (!base) { ++ pr_err("%s(): ioremap failed\n", __func__); ++ return; ++ } ++ ++ clk_data = mtk_alloc_clk_data(CLK_TOP_NR); ++ ++ mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), ++ clk_data); ++ ++ mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs), ++ clk_data); ++ ++ mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), ++ base, &lock, clk_data); ++ ++ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), ++ base, &lock, clk_data); ++ ++ mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init); ++ ++static const struct mtk_gate_regs infra_cg_regs __initconst = { ++ .set_ofs = 0x0040, ++ .clr_ofs = 0x0044, ++ .sta_ofs = 0x0048, ++}; ++ ++#define GATE_ICG(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &infra_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++static const struct mtk_gate infra_clks[] __initconst = { ++ GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0), ++ GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1), ++ GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2), ++ GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2_294m_ck", 4), ++ GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk_null", 5), ++ GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6), ++ GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7), ++ GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8), ++ GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12), ++ GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13), ++ GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14), ++ GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15), ++ GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16), ++ GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18), ++ GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19), ++ GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22), ++ GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23), ++ GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24), ++}; ++ ++static const struct mtk_fixed_factor infra_fixed_divs[] __initconst = { ++ FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2), ++}; ++ ++static void __init mtk_infrasys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); ++ ++ mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), ++ clk_data); ++ mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init); ++ ++static const struct mtk_gate_regs peri0_cg_regs __initconst = { ++ .set_ofs = 0x0008, ++ .clr_ofs = 0x0010, ++ .sta_ofs = 0x0018, ++}; ++ ++static const struct mtk_gate_regs peri1_cg_regs __initconst = { ++ .set_ofs = 0x000c, ++ .clr_ofs = 0x0014, ++ .sta_ofs = 0x001c, ++}; ++ ++#define GATE_PERI0(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &peri0_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++#define GATE_PERI1(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &peri1_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++static const struct mtk_gate peri_clks[] __initconst = { ++ GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31), ++ GATE_PERI1(CLK_PERI_ETH, "eth_ck", "clk26m", 30), ++ GATE_PERI1(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29), ++ GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28), ++ GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27), ++ GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26), ++ GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25), ++ GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24), ++ GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23), ++ GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22), ++ GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21), ++ GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20), ++ GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19), ++ GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18), ++ GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17), ++ GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16), ++ GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15), ++ GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14), ++ GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13), ++ GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12), ++ GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11), ++ GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10), ++ GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9), ++ GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8), ++ GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7), ++ GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6), ++ GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5), ++ GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4), ++ GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3), ++ GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2), ++ GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1), ++ GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0), ++ ++ GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card", 11), ++ GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10), ++ GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9), ++ GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8), ++ GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7), ++ GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6), ++ GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5), ++ GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi_sel", 4), ++ GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi_sel", 3), ++ GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2), ++ GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1), ++ GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0), ++}; ++ ++static const char * const uart_ck_sel_parents[] __initconst = { ++ "clk26m", ++ "uart_sel", ++}; ++ ++static const struct mtk_composite peri_muxs[] __initconst = { ++ MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1), ++ MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1), ++ MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1), ++ MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1), ++}; ++ ++static void __init mtk_pericfg_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ void __iomem *base; ++ int r; ++ ++ base = of_iomap(node, 0); ++ if (!base) { ++ pr_err("%s(): ioremap failed\n", __func__); ++ return; ++ } ++ ++ clk_data = mtk_alloc_clk_data(CLK_PERI_NR); ++ ++ mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), ++ clk_data); ++ ++ mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base, ++ &lock, clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init); ++ ++static const struct mtk_gate_regs disp0_cg_regs __initconst = { ++ .set_ofs = 0x0104, ++ .clr_ofs = 0x0108, ++ .sta_ofs = 0x0100, ++}; ++ ++static const struct mtk_gate_regs disp1_cg_regs __initconst = { ++ .set_ofs = 0x0114, ++ .clr_ofs = 0x0118, ++ .sta_ofs = 0x0110, ++}; ++ ++#define GATE_DISP0(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &disp0_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++#define GATE_DISP1(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &disp1_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++static const struct mtk_gate mm_clks[] __initconst = { ++ GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0), ++ GATE_DISP0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), ++ GATE_DISP0(CLK_MM_CMDQ, "mm_cmdq", "mm_sel", 2), ++ GATE_DISP0(CLK_MM_MUTEX, "mm_mutex", "mm_sel", 3), ++ GATE_DISP0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 4), ++ GATE_DISP0(CLK_MM_DISP_BLS, "mm_disp_bls", "mm_sel", 5), ++ GATE_DISP0(CLK_MM_DISP_WDMA, "mm_disp_wdma", "mm_sel", 6), ++ GATE_DISP0(CLK_MM_DISP_RDMA, "mm_disp_rdma", "mm_sel", 7), ++ GATE_DISP0(CLK_MM_DISP_OVL, "mm_disp_ovl", "mm_sel", 8), ++ GATE_DISP0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9), ++ GATE_DISP0(CLK_MM_MDP_WROT, "mm_mdp_wrot", "mm_sel", 10), ++ GATE_DISP0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11), ++ GATE_DISP0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 12), ++ GATE_DISP0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 13), ++ GATE_DISP0(CLK_MM_MDP_RDMA, "mm_mdp_rdma", "mm_sel", 14), ++ GATE_DISP0(CLK_MM_MDP_BLS_26M, "mm_mdp_bls_26m", "clk26m", 15), ++ GATE_DISP0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 16), ++ GATE_DISP0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 17), ++ GATE_DISP0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "rtc_sel", 18), ++ GATE_DISP0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19), ++ GATE_DISP0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 20), ++ GATE_DISP1(CLK_MM_DSI_ENGINE, "mm_dsi_eng", "mm_sel", 0), ++ GATE_DISP1(CLK_MM_DSI_DIG, "mm_dsi_dig", "dsio_lntc_dsiclk", 1), ++ GATE_DISP1(CLK_MM_DPI_DIGL, "mm_dpi_digl", "dpi0_sel", 2), ++ GATE_DISP1(CLK_MM_DPI_ENGINE, "mm_dpi_eng", "mm_sel", 3), ++ GATE_DISP1(CLK_MM_DPI1_DIGL, "mm_dpi1_digl", "dpi1_sel", 4), ++ GATE_DISP1(CLK_MM_DPI1_ENGINE, "mm_dpi1_eng", "mm_sel", 5), ++ GATE_DISP1(CLK_MM_TVE_OUTPUT, "mm_tve_output", "tve_sel", 6), ++ GATE_DISP1(CLK_MM_TVE_INPUT, "mm_tve_input", "dpi0_sel", 7), ++ GATE_DISP1(CLK_MM_HDMI_PIXEL, "mm_hdmi_pixel", "dpi1_sel", 8), ++ GATE_DISP1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmi_sel", 9), ++ GATE_DISP1(CLK_MM_HDMI_AUDIO, "mm_hdmi_audio", "apll_sel", 10), ++ GATE_DISP1(CLK_MM_HDMI_SPDIF, "mm_hdmi_spdif", "apll_sel", 11), ++ GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14), ++}; ++ ++static void __init mtk_mmsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_MM_NR); ++ ++ mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_mmsys, "mediatek,mt2701-mmsys", mtk_mmsys_init); ++ ++static const struct mtk_gate_regs img_cg_regs __initconst = { ++ .set_ofs = 0x0004, ++ .clr_ofs = 0x0008, ++ .sta_ofs = 0x0000, ++}; ++ ++#define GATE_IMG(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &img_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr, \ ++ } ++ ++static const struct mtk_gate img_clks[] __initconst = { ++ GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0), ++ GATE_IMG(CLK_IMG_RESZ, "img_resz", "mm_sel", 1), ++ GATE_IMG(CLK_IMG_JPGDEC, "img_jpgdec", "mm_sel", 5), ++ GATE_IMG(CLK_IMG_VENC_LT, "img_venc_lt", "mm_sel", 8), ++ GATE_IMG(CLK_IMG_VENC, "img_venc", "mm_sel", 9), ++}; ++ ++static void __init mtk_imgsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_IMG_NR); ++ ++ mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt2701-imgsys", mtk_imgsys_init); ++ ++static const struct mtk_gate_regs vdec0_cg_regs __initconst = { ++ .set_ofs = 0x0000, ++ .clr_ofs = 0x0004, ++ .sta_ofs = 0x0000, ++}; ++ ++static const struct mtk_gate_regs vdec1_cg_regs __initconst = { ++ .set_ofs = 0x0008, ++ .clr_ofs = 0x000c, ++ .sta_ofs = 0x0008, ++}; ++ ++#define GATE_VDEC0(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &vdec0_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr_inv, \ ++ } ++ ++#define GATE_VDEC1(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &vdec1_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr_inv, \ ++ } ++ ++static const struct mtk_gate vdec_clks[] __initconst = { ++ GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0), ++ GATE_VDEC1(CLK_VDEC_LARB, "vdec_larb_cken", "mm_sel", 0), ++}; ++ ++static void __init mtk_vdecsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_VDEC_NR); ++ ++ mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt2701-vdecsys", mtk_vdecsys_init); ++ ++static const struct mtk_gate_regs hif_cg_regs __initconst = { ++ .sta_ofs = 0x0008, ++}; ++ ++#define GATE_HIF(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &hif_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \ ++ } ++ ++static const struct mtk_gate hif_clks[] __initconst = { ++ GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21), ++ GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22), ++ GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24), ++ GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25), ++ GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26), ++}; ++ ++static void __init mtk_hifsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR); ++ ++ mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init); ++ ++static const struct mtk_gate_regs eth_cg_regs __initconst = { ++ .sta_ofs = 0x0030, ++}; ++ ++#define GATE_eth(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = ð_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_no_setclr_inv, \ ++ } ++ ++static const struct mtk_gate eth_clks[] __initconst = { ++ GATE_HIF(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5), ++ GATE_HIF(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6), ++ GATE_HIF(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7), ++ GATE_HIF(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8), ++ GATE_HIF(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11), ++ GATE_HIF(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14), ++ GATE_HIF(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17), ++ GATE_HIF(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29), ++}; ++ ++static void __init mtk_ethsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR); ++ ++ mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init); ++ ++static const struct mtk_gate_regs bdp0_cg_regs __initconst = { ++ .set_ofs = 0x0104, ++ .clr_ofs = 0x0108, ++ .sta_ofs = 0x0100, ++}; ++ ++static const struct mtk_gate_regs bdp1_cg_regs __initconst = { ++ .set_ofs = 0x0114, ++ .clr_ofs = 0x0118, ++ .sta_ofs = 0x0110, ++}; ++ ++#define GATE_BDP0(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &bdp0_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr_inv, \ ++ } ++ ++#define GATE_BDP1(_id, _name, _parent, _shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .regs = &bdp1_cg_regs, \ ++ .shift = _shift, \ ++ .ops = &mtk_clk_gate_ops_setclr_inv, \ ++ } ++ ++static const struct mtk_gate bdp_clks[] __initconst = { ++ GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0), ++ GATE_BDP0(CLK_BDP_BRG_DRAM, "brg_dram", "mm_sel", 1), ++ GATE_BDP0(CLK_BDP_LARB_DRAM, "larb_dram", "mm_sel", 2), ++ GATE_BDP0(CLK_BDP_WR_VDI_PXL, "wr_vdi_pxl", "hdmi_0_deep340m", 3), ++ GATE_BDP0(CLK_BDP_WR_VDI_DRAM, "wr_vdi_dram", "mm_sel", 4), ++ GATE_BDP0(CLK_BDP_WR_B, "wr_bclk", "mm_sel", 5), ++ GATE_BDP0(CLK_BDP_DGI_IN, "dgi_in", "dpi1_sel", 6), ++ GATE_BDP0(CLK_BDP_DGI_OUT, "dgi_out", "dpi_sel", 7), ++ GATE_BDP0(CLK_BDP_FMT_MAST_27, "fmt_mast_27", "dpi1_sel", 8), ++ GATE_BDP0(CLK_BDP_FMT_B, "fmt_bclk", "mm_sel", 9), ++ GATE_BDP0(CLK_BDP_OSD_B, "osd_bclk", "mm_sel", 10), ++ GATE_BDP0(CLK_BDP_OSD_DRAM, "osd_dram", "mm_sel", 11), ++ GATE_BDP0(CLK_BDP_OSD_AGENT, "osd_agent", "osd_sel", 12), ++ GATE_BDP0(CLK_BDP_OSD_PXL, "osd_pxl", "dpi1_sel", 13), ++ GATE_BDP0(CLK_BDP_RLE_B, "rle_bclk", "mm_sel", 14), ++ GATE_BDP0(CLK_BDP_RLE_AGENT, "rle_agent", "mm_sel", 15), ++ GATE_BDP0(CLK_BDP_RLE_DRAM, "rle_dram", "mm_sel", 16), ++ GATE_BDP0(CLK_BDP_F27M, "f27m", "di_sel", 17), ++ GATE_BDP0(CLK_BDP_F27M_VDOUT, "f27m_vdout", "di_sel", 18), ++ GATE_BDP0(CLK_BDP_F27_74_74, "f27_74_74", "di_sel", 19), ++ GATE_BDP0(CLK_BDP_F2FS, "f2fs", "di_sel", 20), ++ GATE_BDP0(CLK_BDP_F2FS74_148, "f2fs74_148", "di_sel", 21), ++ GATE_BDP0(CLK_BDP_FB, "fbclk", "mm_sel", 22), ++ GATE_BDP0(CLK_BDP_VDO_DRAM, "vdo_dram", "mm_sel", 23), ++ GATE_BDP0(CLK_BDP_VDO_2FS, "vdo_2fs", "di_sel", 24), ++ GATE_BDP0(CLK_BDP_VDO_B, "vdo_bclk", "mm_sel", 25), ++ GATE_BDP0(CLK_BDP_WR_DI_PXL, "wr_di_pxl", "di_sel", 26), ++ GATE_BDP0(CLK_BDP_WR_DI_DRAM, "wr_di_dram", "mm_sel", 27), ++ GATE_BDP0(CLK_BDP_WR_DI_B, "wr_di_bclk", "mm_sel", 28), ++ GATE_BDP0(CLK_BDP_NR_PXL, "nr_pxl", "nr_sel", 29), ++ GATE_BDP0(CLK_BDP_NR_DRAM, "nr_dram", "mm_sel", 30), ++ GATE_BDP0(CLK_BDP_NR_B, "nr_bclk", "mm_sel", 31), ++ GATE_BDP1(CLK_BDP_RX_F, "rx_fclk", "hadds2_fbclk", 0), ++ GATE_BDP1(CLK_BDP_RX_X, "rx_xclk", "clk26m", 1), ++ GATE_BDP1(CLK_BDP_RXPDT, "rxpdtclk", "hdmi_0_pix340m", 2), ++ GATE_BDP1(CLK_BDP_RX_CSCL_N, "rx_cscl_n", "clk26m", 3), ++ GATE_BDP1(CLK_BDP_RX_CSCL, "rx_cscl", "clk26m", 4), ++ GATE_BDP1(CLK_BDP_RX_DDCSCL_N, "rx_ddcscl_n", "hdmi_scl_rx", 5), ++ GATE_BDP1(CLK_BDP_RX_DDCSCL, "rx_ddcscl", "hdmi_scl_rx", 6), ++ GATE_BDP1(CLK_BDP_RX_VCO, "rx_vcoclk", "hadds2pll_294m", 7), ++ GATE_BDP1(CLK_BDP_RX_DP, "rx_dpclk", "hdmi_0_pll340m", 8), ++ GATE_BDP1(CLK_BDP_RX_P, "rx_pclk", "hdmi_0_pll340m", 9), ++ GATE_BDP1(CLK_BDP_RX_M, "rx_mclk", "hadds2pll_294m", 10), ++ GATE_BDP1(CLK_BDP_RX_PLL, "rx_pllclk", "hdmi_0_pix340m", 11), ++ GATE_BDP1(CLK_BDP_BRG_RT_B, "brg_rt_bclk", "mm_sel", 12), ++ GATE_BDP1(CLK_BDP_BRG_RT_DRAM, "brg_rt_dram", "mm_sel", 13), ++ GATE_BDP1(CLK_BDP_LARBRT_DRAM, "larbrt_dram", "mm_sel", 14), ++ GATE_BDP1(CLK_BDP_TMDS_SYN, "tmds_syn", "hdmi_0_pll340m", 15), ++ GATE_BDP1(CLK_BDP_HDMI_MON, "hdmi_mon", "hdmi_0_mon", 16), ++}; ++ ++static void __init mtk_bdpsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(CLK_BDP_NR); ++ ++ mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_bdpsys, "mediatek,mt2701-bdpsys", mtk_bdpsys_init); ++ ++#define MT8590_PLL_FMAX (2000 * MHZ) ++#define CON0_MT8590_RST_BAR BIT(27) ++ ++#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ ++ _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .reg = _reg, \ ++ .pwr_reg = _pwr_reg, \ ++ .en_mask = _en_mask, \ ++ .flags = _flags, \ ++ .rst_bar_mask = CON0_MT8590_RST_BAR, \ ++ .fmax = MT8590_PLL_FMAX, \ ++ .pcwbits = _pcwbits, \ ++ .pd_reg = _pd_reg, \ ++ .pd_shift = _pd_shift, \ ++ .tuner_reg = _tuner_reg, \ ++ .pcw_reg = _pcw_reg, \ ++ .pcw_shift = _pcw_shift, \ ++ } ++ ++static const struct mtk_pll_data apmixed_plls[] = { ++ PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001, 0, ++ 21, 0x204, 24, 0x0, 0x204, 0), ++ PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001, ++ HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0), ++ PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001, ++ HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14), ++ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0, ++ 21, 0x230, 4, 0x0, 0x234, 0), ++ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0, ++ 21, 0x240, 4, 0x0, 0x244, 0), ++ PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0, ++ 21, 0x250, 4, 0x0, 0x254, 0), ++ PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0, ++ 31, 0x270, 4, 0x0, 0x274, 0), ++ PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0, ++ 31, 0x280, 4, 0x0, 0x284, 0), ++ PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0, ++ 31, 0x290, 4, 0x0, 0x294, 0), ++ PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0, ++ 31, 0x2a0, 4, 0x0, 0x2a4, 0), ++ PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0, ++ 31, 0x2b0, 4, 0x0, 0x2b4, 0), ++ PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0, ++ 31, 0x2c0, 4, 0x0, 0x2c4, 0), ++ PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0, ++ 21, 0x2d0, 4, 0x0, 0x2d4, 0), ++}; ++ ++static void __init mtk_apmixedsys_init(struct device_node *node) ++{ ++ struct clk_onecell_data *clk_data; ++ int r; ++ ++ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); ++ if (!clk_data) ++ return; ++ ++ mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls), ++ clk_data); ++ ++ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); ++ if (r) ++ pr_err("%s(): could not register clock provider: %d\n", ++ __func__, r); ++} ++CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys", ++ mtk_apmixedsys_init); +--- a/drivers/clk/mediatek/clk-mtk.c ++++ b/drivers/clk/mediatek/clk-mtk.c +@@ -244,3 +244,28 @@ void mtk_clk_register_composites(const s + clk_data->clks[mc->id] = clk; + } + } ++ ++void __init mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, ++ int num, void __iomem *base, spinlock_t *lock, ++ struct clk_onecell_data *clk_data) ++{ ++ struct clk *clk; ++ int i; ++ ++ for (i = 0; i < num; i++) { ++ const struct mtk_clk_divider *mcd = &mcds[i]; ++ ++ clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, ++ mcd->flags, base + mcd->div_reg, mcd->div_shift, ++ mcd->div_width, mcd->clk_divider_flags, lock); ++ ++ if (IS_ERR(clk)) { ++ pr_err("Failed to register clk %s: %ld\n", ++ mcd->name, PTR_ERR(clk)); ++ continue; ++ } ++ ++ if (clk_data) ++ clk_data->clks[mcd->id] = clk; ++ } ++} +--- a/drivers/clk/mediatek/clk-mtk.h ++++ b/drivers/clk/mediatek/clk-mtk.h +@@ -121,7 +121,8 @@ struct mtk_composite { + .flags = CLK_SET_RATE_PARENT, \ + } + +-#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \ ++#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ ++ _div_width, _div_shift) { \ + .id = _id, \ + .parent = _parent, \ + .name = _name, \ +@@ -156,8 +157,36 @@ struct mtk_gate { + const struct clk_ops *ops; + }; + +-int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, +- int num, struct clk_onecell_data *clk_data); ++int mtk_clk_register_gates(struct device_node *node, ++ const struct mtk_gate *clks, int num, ++ struct clk_onecell_data *clk_data); ++ ++struct mtk_clk_divider { ++ int id; ++ const char *name; ++ const char *parent_name; ++ unsigned long flags; ++ ++ uint32_t div_reg; ++ unsigned char div_shift; ++ unsigned char div_width; ++ unsigned char clk_divider_flags; ++ const struct clk_div_table *clk_div_table; ++}; ++ ++#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ ++ .id = _id, \ ++ .name = _name, \ ++ .parent_name = _parent, \ ++ .flags = CLK_SET_RATE_PARENT, \ ++ .div_reg = _reg, \ ++ .div_shift = _shift, \ ++ .div_width = _width, \ ++} ++ ++void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, ++ int num, void __iomem *base, spinlock_t *lock, ++ struct clk_onecell_data *clk_data); + + struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); + diff --git a/target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch new file mode 100644 index 0000000000..12bda9c6b1 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0006-reset-mediatek-mt2701-reset-driver.patch @@ -0,0 +1,36 @@ +From 596c3a7300c0419dba71d58cbd4136e0d1e12a4e Mon Sep 17 00:00:00 2001 +From: Shunli Wang +Date: Tue, 5 Jan 2016 14:30:22 +0800 +Subject: [PATCH 06/57] reset: mediatek: mt2701 reset driver + +In infrasys and perifsys, there are many reset +control bits for kinds of modules. These bits are +used as actual reset controllers to be registered +into kernel's generic reset controller framework. + +Signed-off-by: Shunli Wang +Acked-by: Philipp Zabel +--- + drivers/clk/mediatek/clk-mt2701.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_register_reset_controller(node, 2, 0x30); + } + CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init); + +@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_register_reset_controller(node, 2, 0x0); + } + CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init); + diff --git a/target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch new file mode 100644 index 0000000000..f38b435c85 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0007-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch @@ -0,0 +1,29 @@ +From 60c14df3cc898b6b03d66ec725f9705bf431b677 Mon Sep 17 00:00:00 2001 +From: Erin Lo +Date: Mon, 28 Dec 2015 15:09:02 +0800 +Subject: [PATCH 07/57] ARM: mediatek: Add MT2701 config options for mediatek + SoCs. + +The upcoming MTK pinctrl driver have a big pin table for each SoC +and we don't want to bloat the kernel binary if we don't need it. +Add config options so we can build for one SoC only. Add MT2701. + +Signed-off-by: Erin Lo +Acked-by: Linus Walleij +--- + arch/arm/mach-mediatek/Kconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -14,6 +14,10 @@ config MACH_MT2701 + bool "MediaTek MT2701 SoCs support" + default ARCH_MEDIATEK + ++config MACH_MT2701 ++ bool "MediaTek MT2701 SoCs support" ++ default ARCH_MEDIATEK ++ + config MACH_MT6589 + bool "MediaTek MT6589 SoCs support" + default ARCH_MEDIATEK diff --git a/target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch new file mode 100644 index 0000000000..1d83e9ae5d --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0008-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch @@ -0,0 +1,487 @@ +From b5a1e520d8039c242b2157b511f684ce464d6e21 Mon Sep 17 00:00:00 2001 +From: James Liao +Date: Thu, 20 Oct 2016 16:56:35 +0800 +Subject: [PATCH 08/57] soc: mediatek: Refine scpsys to support multiple + platform + +Refine scpsys driver common code to support multiple SoC / platform. + +Signed-off-by: James Liao +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++--------------- + 1 file changed, 210 insertions(+), 138 deletions(-) + +--- a/drivers/soc/mediatek/mtk-scpsys.c ++++ b/drivers/soc/mediatek/mtk-scpsys.c +@@ -11,17 +11,15 @@ + * GNU General Public License for more details. + */ + #include +-#include ++#include + #include +-#include + #include +-#include + #include + #include + #include +-#include +-#include + #include ++#include ++ + #include + + #define SPM_VDE_PWR_CON 0x0210 +@@ -34,6 +32,7 @@ + #define SPM_MFG_2D_PWR_CON 0x02c0 + #define SPM_MFG_ASYNC_PWR_CON 0x02c4 + #define SPM_USB_PWR_CON 0x02cc ++ + #define SPM_PWR_STATUS 0x060c + #define SPM_PWR_STATUS_2ND 0x0610 + +@@ -55,12 +54,21 @@ + #define PWR_STATUS_USB BIT(25) + + enum clk_id { +- MT8173_CLK_NONE, +- MT8173_CLK_MM, +- MT8173_CLK_MFG, +- MT8173_CLK_VENC, +- MT8173_CLK_VENC_LT, +- MT8173_CLK_MAX, ++ CLK_NONE, ++ CLK_MM, ++ CLK_MFG, ++ CLK_VENC, ++ CLK_VENC_LT, ++ CLK_MAX, ++}; ++ ++static const char * const clk_names[] = { ++ NULL, ++ "mm", ++ "mfg", ++ "venc", ++ "venc_lt", ++ NULL, + }; + + #define MAX_CLKS 2 +@@ -76,98 +84,6 @@ struct scp_domain_data { + bool active_wakeup; + }; + +-static const struct scp_domain_data scp_domain_data[] = { +- [MT8173_POWER_DOMAIN_VDEC] = { +- .name = "vdec", +- .sta_mask = PWR_STATUS_VDEC, +- .ctl_offs = SPM_VDE_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(12, 12), +- .clk_id = {MT8173_CLK_MM}, +- }, +- [MT8173_POWER_DOMAIN_VENC] = { +- .name = "venc", +- .sta_mask = PWR_STATUS_VENC, +- .ctl_offs = SPM_VEN_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, +- }, +- [MT8173_POWER_DOMAIN_ISP] = { +- .name = "isp", +- .sta_mask = PWR_STATUS_ISP, +- .ctl_offs = SPM_ISP_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(13, 12), +- .clk_id = {MT8173_CLK_MM}, +- }, +- [MT8173_POWER_DOMAIN_MM] = { +- .name = "mm", +- .sta_mask = PWR_STATUS_DISP, +- .ctl_offs = SPM_DIS_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(12, 12), +- .clk_id = {MT8173_CLK_MM}, +- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | +- MT8173_TOP_AXI_PROT_EN_MM_M1, +- }, +- [MT8173_POWER_DOMAIN_VENC_LT] = { +- .name = "venc_lt", +- .sta_mask = PWR_STATUS_VENC_LT, +- .ctl_offs = SPM_VEN2_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, +- }, +- [MT8173_POWER_DOMAIN_AUDIO] = { +- .name = "audio", +- .sta_mask = PWR_STATUS_AUDIO, +- .ctl_offs = SPM_AUDIO_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_NONE}, +- }, +- [MT8173_POWER_DOMAIN_USB] = { +- .name = "usb", +- .sta_mask = PWR_STATUS_USB, +- .ctl_offs = SPM_USB_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_NONE}, +- .active_wakeup = true, +- }, +- [MT8173_POWER_DOMAIN_MFG_ASYNC] = { +- .name = "mfg_async", +- .sta_mask = PWR_STATUS_MFG_ASYNC, +- .ctl_offs = SPM_MFG_ASYNC_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = 0, +- .clk_id = {MT8173_CLK_MFG}, +- }, +- [MT8173_POWER_DOMAIN_MFG_2D] = { +- .name = "mfg_2d", +- .sta_mask = PWR_STATUS_MFG_2D, +- .ctl_offs = SPM_MFG_2D_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(13, 12), +- .clk_id = {MT8173_CLK_NONE}, +- }, +- [MT8173_POWER_DOMAIN_MFG] = { +- .name = "mfg", +- .sta_mask = PWR_STATUS_MFG, +- .ctl_offs = SPM_MFG_PWR_CON, +- .sram_pdn_bits = GENMASK(13, 8), +- .sram_pdn_ack_bits = GENMASK(21, 16), +- .clk_id = {MT8173_CLK_NONE}, +- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | +- MT8173_TOP_AXI_PROT_EN_MFG_M0 | +- MT8173_TOP_AXI_PROT_EN_MFG_M1 | +- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, +- }, +-}; +- +-#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) +- + struct scp; + + struct scp_domain { +@@ -179,7 +95,7 @@ struct scp_domain { + }; + + struct scp { +- struct scp_domain domains[NUM_DOMAINS]; ++ struct scp_domain *domains; + struct genpd_onecell_data pd_data; + struct device *dev; + void __iomem *base; +@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct + return scpd->data->active_wakeup; + } + +-static int scpsys_probe(struct platform_device *pdev) ++static void init_clks(struct platform_device *pdev, struct clk **clk) ++{ ++ int i; ++ ++ for (i = CLK_NONE + 1; i < CLK_MAX; i++) ++ clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); ++} ++ ++static struct scp *init_scp(struct platform_device *pdev, ++ const struct scp_domain_data *scp_domain_data, int num) + { + struct genpd_onecell_data *pd_data; + struct resource *res; +- int i, j, ret; ++ int i, j; + struct scp *scp; +- struct clk *clk[MT8173_CLK_MAX]; ++ struct clk *clk[CLK_MAX]; + + scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); + if (!scp) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + scp->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + scp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(scp->base)) +- return PTR_ERR(scp->base); ++ return ERR_CAST(scp->base); ++ ++ scp->domains = devm_kzalloc(&pdev->dev, ++ sizeof(*scp->domains) * num, GFP_KERNEL); ++ if (!scp->domains) ++ return ERR_PTR(-ENOMEM); + + pd_data = &scp->pd_data; + + pd_data->domains = devm_kzalloc(&pdev->dev, +- sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); ++ sizeof(*pd_data->domains) * num, GFP_KERNEL); + if (!pd_data->domains) +- return -ENOMEM; +- +- clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); +- if (IS_ERR(clk[MT8173_CLK_MM])) +- return PTR_ERR(clk[MT8173_CLK_MM]); +- +- clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); +- if (IS_ERR(clk[MT8173_CLK_MFG])) +- return PTR_ERR(clk[MT8173_CLK_MFG]); +- +- clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); +- if (IS_ERR(clk[MT8173_CLK_VENC])) +- return PTR_ERR(clk[MT8173_CLK_VENC]); +- +- clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); +- if (IS_ERR(clk[MT8173_CLK_VENC_LT])) +- return PTR_ERR(clk[MT8173_CLK_VENC_LT]); ++ return ERR_PTR(-ENOMEM); + + scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "infracfg"); + if (IS_ERR(scp->infracfg)) { + dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", + PTR_ERR(scp->infracfg)); +- return PTR_ERR(scp->infracfg); ++ return ERR_CAST(scp->infracfg); + } + +- for (i = 0; i < NUM_DOMAINS; i++) { ++ for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + const struct scp_domain_data *data = &scp_domain_data[i]; + +@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_ + if (PTR_ERR(scpd->supply) == -ENODEV) + scpd->supply = NULL; + else +- return PTR_ERR(scpd->supply); ++ return ERR_CAST(scpd->supply); + } + } + +- pd_data->num_domains = NUM_DOMAINS; ++ pd_data->num_domains = num; ++ ++ init_clks(pdev, clk); + +- for (i = 0; i < NUM_DOMAINS; i++) { ++ for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; + const struct scp_domain_data *data = &scp_domain_data[i]; +@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_ + scpd->scp = scp; + + scpd->data = data; +- for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) +- scpd->clk[j] = clk[data->clk_id[j]]; ++ ++ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { ++ struct clk *c = clk[data->clk_id[j]]; ++ ++ if (IS_ERR(c)) { ++ dev_err(&pdev->dev, "%s: clk unavailable\n", ++ data->name); ++ return ERR_CAST(c); ++ } ++ ++ scpd->clk[j] = c; ++ } + + genpd->name = data->name; + genpd->power_off = scpsys_power_off; + genpd->power_on = scpsys_power_on; + genpd->dev_ops.active_wakeup = scpsys_active_wakeup; ++ } ++ ++ return scp; ++} ++ ++static void mtk_register_power_domains(struct platform_device *pdev, ++ struct scp *scp, int num) ++{ ++ struct genpd_onecell_data *pd_data; ++ int i, ret; ++ ++ for (i = 0; i < num; i++) { ++ struct scp_domain *scpd = &scp->domains[i]; ++ struct generic_pm_domain *genpd = &scpd->genpd; + + /* + * Initially turn on all domains to make the domains usable +@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_ + * valid. + */ + ++ pd_data = &scp->pd_data; ++ ++ ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); ++ if (ret) ++ dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); ++} ++ ++/* ++ * MT8173 power domain support ++ */ ++ ++static const struct scp_domain_data scp_domain_data_mt8173[] = { ++ [MT8173_POWER_DOMAIN_VDEC] = { ++ .name = "vdec", ++ .sta_mask = PWR_STATUS_VDEC, ++ .ctl_offs = SPM_VDE_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ }, ++ [MT8173_POWER_DOMAIN_VENC] = { ++ .name = "venc", ++ .sta_mask = PWR_STATUS_VENC, ++ .ctl_offs = SPM_VEN_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_MM, CLK_VENC}, ++ }, ++ [MT8173_POWER_DOMAIN_ISP] = { ++ .name = "isp", ++ .sta_mask = PWR_STATUS_ISP, ++ .ctl_offs = SPM_ISP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_MM}, ++ }, ++ [MT8173_POWER_DOMAIN_MM] = { ++ .name = "mm", ++ .sta_mask = PWR_STATUS_DISP, ++ .ctl_offs = SPM_DIS_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | ++ MT8173_TOP_AXI_PROT_EN_MM_M1, ++ }, ++ [MT8173_POWER_DOMAIN_VENC_LT] = { ++ .name = "venc_lt", ++ .sta_mask = PWR_STATUS_VENC_LT, ++ .ctl_offs = SPM_VEN2_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_MM, CLK_VENC_LT}, ++ }, ++ [MT8173_POWER_DOMAIN_AUDIO] = { ++ .name = "audio", ++ .sta_mask = PWR_STATUS_AUDIO, ++ .ctl_offs = SPM_AUDIO_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_NONE}, ++ }, ++ [MT8173_POWER_DOMAIN_USB] = { ++ .name = "usb", ++ .sta_mask = PWR_STATUS_USB, ++ .ctl_offs = SPM_USB_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT8173_POWER_DOMAIN_MFG_ASYNC] = { ++ .name = "mfg_async", ++ .sta_mask = PWR_STATUS_MFG_ASYNC, ++ .ctl_offs = SPM_MFG_ASYNC_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = 0, ++ .clk_id = {CLK_MFG}, ++ }, ++ [MT8173_POWER_DOMAIN_MFG_2D] = { ++ .name = "mfg_2d", ++ .sta_mask = PWR_STATUS_MFG_2D, ++ .ctl_offs = SPM_MFG_2D_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_NONE}, ++ }, ++ [MT8173_POWER_DOMAIN_MFG] = { ++ .name = "mfg", ++ .sta_mask = PWR_STATUS_MFG, ++ .ctl_offs = SPM_MFG_PWR_CON, ++ .sram_pdn_bits = GENMASK(13, 8), ++ .sram_pdn_ack_bits = GENMASK(21, 16), ++ .clk_id = {CLK_NONE}, ++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | ++ MT8173_TOP_AXI_PROT_EN_MFG_M0 | ++ MT8173_TOP_AXI_PROT_EN_MFG_M1 | ++ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, ++ }, ++}; ++ ++#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173) ++ ++static int __init scpsys_probe_mt8173(struct platform_device *pdev) ++{ ++ struct scp *scp; ++ struct genpd_onecell_data *pd_data; ++ int ret; ++ ++ scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173); ++ if (IS_ERR(scp)) ++ return PTR_ERR(scp); ++ ++ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173); ++ ++ pd_data = &scp->pd_data; ++ + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], + pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); + if (ret && IS_ENABLED(CONFIG_PM)) +@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_ + if (ret && IS_ENABLED(CONFIG_PM)) + dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); + +- ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); +- if (ret) +- dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); +- + return 0; + } + ++/* ++ * scpsys driver init ++ */ ++ + static const struct of_device_id of_scpsys_match_tbl[] = { + { + .compatible = "mediatek,mt8173-scpsys", ++ .data = scpsys_probe_mt8173, + }, { + /* sentinel */ + } + }; + ++static int scpsys_probe(struct platform_device *pdev) ++{ ++ int (*probe)(struct platform_device *); ++ const struct of_device_id *of_id; ++ ++ of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node); ++ if (!of_id || !of_id->data) ++ return -EINVAL; ++ ++ probe = of_id->data; ++ ++ return probe(pdev); ++} ++ + static struct platform_driver scpsys_drv = { + .probe = scpsys_probe, + .driver = { diff --git a/target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch deleted file mode 100644 index 2cd1e75c3a..0000000000 --- a/target/linux/mediatek/patches-4.9/0009-clk-mediatek-Add-MT2701-clock-support.patch +++ /dev/null @@ -1,1431 +0,0 @@ -From a4c507d052390b42d7e8c59241e3c336796f730f Mon Sep 17 00:00:00 2001 -From: Shunli Wang -Date: Tue, 5 Jan 2016 14:30:20 +0800 -Subject: [PATCH 009/102] clk: mediatek: Add MT2701 clock support - -Add MT2701 clock support, include topckgen, apmixedsys, -infracfg, pericfg and subsystem clocks. - -Signed-off-by: Shunli Wang -Signed-off-by: James Liao ---- - 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 -+ * -+ * 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 -+#include -+#include -+ -+#include "clk-mtk.h" -+#include "clk-gate.h" -+ -+#include -+ -+static DEFINE_SPINLOCK(lock); -+ -+static const struct mtk_fixed_clk top_fixed_clks[] __initconst = { -+ FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m", 108 * MHZ), -+ FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m", 400 * MHZ), -+ FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m", 295750000), -+ FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m", 340 * MHZ), -+ FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m", 340 * MHZ), -+ FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", 340 * MHZ), -+ FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m", 300 * MHZ), -+ FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", 27 * MHZ), -+ FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", 416 * MHZ), -+}; -+ -+static const struct mtk_fixed_factor top_fixed_divs[] __initconst = { -+ FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1), -+ FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2), -+ FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3), -+ FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5), -+ FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7), -+ FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2), -+ FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4), -+ FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8), -+ FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16), -+ FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2), -+ FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4), -+ FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8), -+ FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2), -+ FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4), -+ FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2), -+ FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4), -+ -+ FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1), -+ FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), -+ FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), -+ FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), -+ FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7), -+ FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26), -+ FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52), -+ FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108), -+ FACTOR(CLK_TOP_USB_PHY48M, "USB_PHY48M_CK", "univpll", 1, 26), -+ FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2), -+ FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4), -+ FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8), -+ FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1), -+ FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2), -+ FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4), -+ FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8), -+ FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16), -+ FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32), -+ FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2), -+ FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4), -+ FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8), -+ -+ FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1), -+ FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), -+ FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4), -+ FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8), -+ -+ FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1), -+ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), -+ -+ FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2), -+ FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4), -+ FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1), -+ -+ FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1), -+ FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2), -+ FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4), -+ -+ FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1), -+ FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1), -+ FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2), -+ -+ FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1), -+ FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2), -+ FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4), -+ -+ FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1), -+ FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2), -+ FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3), -+ -+ FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1), -+ -+ FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1), -+ FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4), -+ FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8), -+ FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16), -+ FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24), -+ -+ FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3), -+ FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3), -+ FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3), -+ FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1), -+ FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1), -+ FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8), -+ FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793), -+ FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1), -+}; -+ -+static const char * const axi_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d2", -+ "syspll_d5", -+ "syspll1_d4", -+ "univpll_d5", -+ "univpll2_d2", -+ "mmpll_d2", -+ "dmpll_d2" -+}; -+ -+static const char * const mem_parents[] __initconst = { -+ "clk26m", -+ "dmpll_ck" -+}; -+ -+static const char * const ddrphycfg_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d8" -+}; -+ -+static const char * const mm_parents[] __initconst = { -+ "clk26m", -+ "vencpll_ck", -+ "syspll1_d2", -+ "syspll1_d4", -+ "univpll_d5", -+ "univpll1_d2", -+ "univpll2_d2", -+ "dmpll_ck" -+}; -+ -+static const char * const pwm_parents[] __initconst = { -+ "clk26m", -+ "univpll2_d4", -+ "univpll3_d2", -+ "univpll1_d4", -+}; -+ -+static const char * const vdec_parents[] __initconst = { -+ "clk26m", -+ "vdecpll_ck", -+ "syspll_d5", -+ "syspll1_d4", -+ "univpll_d5", -+ "univpll2_d2", -+ "vencpll_ck", -+ "msdcpll_d2", -+ "mmpll_d2" -+}; -+ -+static const char * const mfg_parents[] __initconst = { -+ "clk26m", -+ "mmpll_ck", -+ "dmpll_x2_ck", -+ "msdcpll_ck", -+ "clk26m", -+ "syspll_d3", -+ "univpll_d3", -+ "univpll1_d2" -+}; -+ -+static const char * const camtg_parents[] __initconst = { -+ "clk26m", -+ "univpll_d26", -+ "univpll2_d2", -+ "syspll3_d2", -+ "syspll3_d4", -+ "msdcpll_d2", -+ "mmpll_d2" -+}; -+ -+static const char * const uart_parents[] __initconst = { -+ "clk26m", -+ "univpll2_d8" -+}; -+ -+static const char * const spi_parents[] __initconst = { -+ "clk26m", -+ "syspll3_d2", -+ "syspll4_d2", -+ "univpll2_d4", -+ "univpll1_d8" -+}; -+ -+static const char * const usb20_parents[] __initconst = { -+ "clk26m", -+ "univpll1_d8", -+ "univpll3_d4" -+}; -+ -+static const char * const msdc30_parents[] __initconst = { -+ "clk26m", -+ "msdcpll_d2", -+ "syspll2_d2", -+ "syspll1_d4", -+ "univpll1_d4", -+ "univpll2_d4" -+}; -+ -+static const char * const audio_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d16" -+}; -+ -+static const char * const aud_intbus_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d4", -+ "syspll3_d2", -+ "syspll4_d2", -+ "univpll3_d2", -+ "univpll2_d4" -+}; -+ -+static const char * const pmicspi_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d8", -+ "syspll2_d4", -+ "syspll4_d2", -+ "syspll3_d4", -+ "syspll2_d8", -+ "syspll1_d16", -+ "univpll3_d4", -+ "univpll_d26", -+ "dmpll_d2", -+ "dmpll_d4" -+}; -+ -+static const char * const scp_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d8", -+ "dmpll_d2", -+ "dmpll_d4" -+}; -+ -+static const char * const dpi0_parents[] __initconst = { -+ "clk26m", -+ "mipipll", -+ "mipipll_d2", -+ "mipipll_d4", -+ "clk26m", -+ "tvdpll_ck", -+ "tvdpll_d2", -+ "tvdpll_d4" -+}; -+ -+static const char * const dpi1_parents[] __initconst = { -+ "clk26m", -+ "tvdpll_ck", -+ "tvdpll_d2", -+ "tvdpll_d4" -+}; -+ -+static const char * const tve_parents[] __initconst = { -+ "clk26m", -+ "mipipll", -+ "mipipll_d2", -+ "mipipll_d4", -+ "clk26m", -+ "tvdpll_ck", -+ "tvdpll_d2", -+ "tvdpll_d4" -+}; -+ -+static const char * const hdmi_parents[] __initconst = { -+ "clk26m", -+ "hdmipll_ck", -+ "hdmipll_d2", -+ "hdmipll_d3" -+}; -+ -+static const char * const apll_parents[] __initconst = { -+ "clk26m", -+ "audpll", -+ "audpll_d4", -+ "audpll_d8", -+ "audpll_d16", -+ "audpll_d24", -+ "clk26m", -+ "clk26m" -+}; -+ -+static const char * const rtc_parents[] __initconst = { -+ "32k_internal", -+ "32k_external", -+ "clk26m", -+ "univpll3_d8" -+}; -+ -+static const char * const nfi2x_parents[] __initconst = { -+ "clk26m", -+ "syspll2_d2", -+ "syspll_d7", -+ "univpll3_d2", -+ "syspll2_d4", -+ "univpll3_d4", -+ "syspll4_d4", -+ "clk26m" -+}; -+ -+static const char * const emmc_hclk_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d2", -+ "syspll1_d4", -+ "syspll2_d2" -+}; -+ -+static const char * const flash_parents[] __initconst = { -+ "clk26m_d8", -+ "clk26m", -+ "syspll2_d8", -+ "syspll3_d4", -+ "univpll3_d4", -+ "syspll4_d2", -+ "syspll2_d4", -+ "univpll2_d4" -+}; -+ -+static const char * const di_parents[] __initconst = { -+ "clk26m", -+ "tvd2pll_ck", -+ "tvd2pll_d2", -+ "clk26m" -+}; -+ -+static const char * const nr_osd_parents[] __initconst = { -+ "clk26m", -+ "vencpll_ck", -+ "syspll1_d2", -+ "syspll1_d4", -+ "univpll_d5", -+ "univpll1_d2", -+ "univpll2_d2", -+ "dmpll_ck" -+}; -+ -+static const char * const hdmirx_bist_parents[] __initconst = { -+ "clk26m", -+ "syspll_d3", -+ "clk26m", -+ "syspll1_d16", -+ "syspll4_d2", -+ "syspll1_d4", -+ "vencpll_ck", -+ "clk26m" -+}; -+ -+static const char * const intdir_parents[] __initconst = { -+ "clk26m", -+ "mmpll_ck", -+ "syspll_d2", -+ "univpll_d2" -+}; -+ -+static const char * const asm_parents[] __initconst = { -+ "clk26m", -+ "univpll2_d4", -+ "univpll2_d2", -+ "syspll_d5" -+}; -+ -+static const char * const ms_card_parents[] __initconst = { -+ "clk26m", -+ "univpll3_d8", -+ "syspll4_d4" -+}; -+ -+static const char * const ethif_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d2", -+ "syspll_d5", -+ "syspll1_d4", -+ "univpll_d5", -+ "univpll1_d2", -+ "dmpll_ck", -+ "dmpll_d2" -+}; -+ -+static const char * const hdmirx_parents[] __initconst = { -+ "clk26m", -+ "univpll_d52" -+}; -+ -+static const char * const cmsys_parents[] __initconst = { -+ "clk26m", -+ "syspll1_d2", -+ "univpll1_d2", -+ "univpll_d5", -+ "syspll_d5", -+ "syspll2_d2", -+ "syspll1_d4", -+ "syspll3_d2", -+ "syspll2_d4", -+ "syspll1_d8", -+ "clk26m", -+ "clk26m", -+ "clk26m", -+ "clk26m", -+ "clk26m" -+}; -+ -+static const char * const clk_8bdac_parents[] __initconst = { -+ "clkrtc_int", -+ "8bdac_ck_pre", -+ "clk26m", -+ "clk26m" -+}; -+ -+static const char * const aud2dvd_parents[] __initconst = { -+ "a1sys_hp_ck", -+ "a2sys_hp_ck" -+}; -+ -+static const char * const padmclk_parents[] __initconst = { -+ "clk26m", -+ "univpll_d26", -+ "univpll_d52", -+ "univpll_d108", -+ "univpll2_d8", -+ "univpll2_d16", -+ "univpll2_d32" -+}; -+ -+static const char * const aud_mux_parents[] __initconst = { -+ "clk26m", -+ "aud1pll_98m_ck", -+ "aud2pll_90m_ck", -+ "hadds2pll_98m", -+ "audio_ext1_ck", -+ "audio_ext2_ck" -+}; -+ -+static const char * const aud_src_parents[] __initconst = { -+ "aud_mux1_sel", -+ "aud_mux2_sel" -+}; -+ -+static const char * const cpu_parents[] __initconst = { -+ "clk26m", -+ "armpll", -+ "mainpll", -+ "mmpll" -+}; -+ -+static const struct mtk_composite top_muxes[] __initconst = { -+ MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, -+ 0x0040, 0, 3, INVALID_MUX_GATE_BIT), -+ MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x0040, 8, 1, 15), -+ MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, 0x0040, 16, 1, 23), -+ MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, 0x0040, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x0050, 0, 2, 7), -+ MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, 0x0050, 8, 4, 15), -+ MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, 0x0050, 16, 3, 23), -+ MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, 0x0050, 24, 3, 31), -+ MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x0060, 0, 1, 7), -+ -+ MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents, 0x0060, 8, 3, 15), -+ MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, 0x0060, 16, 2, 23), -+ MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, 0x0060, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, 0x0070, 0, 3, 7), -+ MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, 0x0070, 8, 3, 15), -+ MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents, 0x0070, 16, 1, 23), -+ MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, 0x0070, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, 0x0080, 0, 4, 7), -+ MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, 0x0080, 8, 2, 15), -+ MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, 0x0080, 16, 3, 23), -+ MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, 0x0080, 24, 2, 31), -+ -+ MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, 0x0090, 0, 3, 7), -+ MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, 0x0090, 8, 2, 15), -+ MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, 0x0090, 16, 3, 23), -+ -+ MUX_GATE(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x00A0, 0, 2, 7), -+ MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, 0x00A0, 8, 3, 15), -+ MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents, 0x00A0, 24, 2, 31), -+ -+ MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, 0x00B0, 0, 3, 7), -+ MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, 0x00B0, 8, 2, 15), -+ MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents, 0x00B0, 16, 3, 23), -+ MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents, 0x00B0, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel", hdmirx_bist_parents, 0x00C0, 0, 3, 7), -+ MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, 0x00C0, 8, 2, 15), -+ MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents, 0x00C0, 16, 2, 23), -+ MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents, 0x00C0, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents, 0x00D0, 0, 2, 7), -+ MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents, 0x00D0, 16, 2, 23), -+ MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents, 0x00D0, 24, 3, 31), -+ -+ MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents, 0x00E0, 0, 1, 7), -+ MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, 0x00E0, 8, 3, 15), -+ MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, 0x00E0, 16, 4, 23), -+ -+ MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents, 0x00E0, 24, 3, 31), -+ MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents, 0x00F0, 0, 3, 7), -+ MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents, 0x00F0, 8, 2, 15), -+ MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents, 0x00F0, 16, 1, 23), -+ -+ MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents, 0x0100, 0, 3), -+ -+ MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents, 0x012c, 0, 3), -+ MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents, 0x012c, 3, 3), -+ MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents, 0x012c, 6, 3), -+ MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents, 0x012c, 15, 1, 23), -+ MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents, 0x012c, 16, 1, 24), -+ MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents, 0x012c, 17, 1, 25), -+ MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents, 0x012c, 18, 1, 26), -+ MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents, 0x012c, 19, 1, 27), -+ MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents, 0x012c, 20, 1, 28), -+}; -+ -+static const struct mtk_clk_divider top_adj_divs[] __initconst = { -+ DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext_ck1", 0x0120, 0, 8), -+ DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext_ck2", 0x0120, 8, 8), -+ DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel", 0x0120, 16, 8), -+ DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel", 0x0120, 24, 8), -+ DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel", 0x0124, 0, 8), -+ DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel", 0x0124, 8, 8), -+ DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel", 0x0124, 16, 8), -+ DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel", 0x0124, 24, 8), -+ DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel", 0x0128, 0, 8), -+ DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel", 0x0128, 8, 8), -+}; -+ -+static const struct mtk_gate_regs top_aud_cg_regs __initconst = { -+ .sta_ofs = 0x012C, -+}; -+ -+#define GATE_TOP_AUD(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &top_aud_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_no_setclr, \ -+ } -+ -+static const struct mtk_gate top_clks[] __initconst = { -+ GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", 21), -+ GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div", 22), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div", 23), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div", 24), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div", 25), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div", 26), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div", 27), -+ GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28), -+}; -+ -+static void __init mtk_topckgen_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ void __iomem *base; -+ int r; -+ -+ base = of_iomap(node, 0); -+ if (!base) { -+ pr_err("%s(): ioremap failed\n", __func__); -+ return; -+ } -+ -+ clk_data = mtk_alloc_clk_data(CLK_TOP_NR); -+ -+ mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), -+ clk_data); -+ -+ mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs), -+ clk_data); -+ -+ mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), -+ base, &lock, clk_data); -+ -+ mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), -+ base, &lock, clk_data); -+ -+ mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init); -+ -+static const struct mtk_gate_regs infra_cg_regs __initconst = { -+ .set_ofs = 0x0040, -+ .clr_ofs = 0x0044, -+ .sta_ofs = 0x0048, -+}; -+ -+#define GATE_ICG(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &infra_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+static const struct mtk_gate infra_clks[] __initconst = { -+ GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0), -+ GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1), -+ GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2), -+ GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2_294m_ck", 4), -+ GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk_null", 5), -+ GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6), -+ GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7), -+ GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8), -+ GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12), -+ GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13), -+ GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14), -+ GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15), -+ GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16), -+ GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18), -+ GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19), -+ GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22), -+ GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23), -+ GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24), -+}; -+ -+static const struct mtk_fixed_factor infra_fixed_divs[] __initconst = { -+ FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2), -+}; -+ -+static void __init mtk_infrasys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); -+ -+ mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), -+ clk_data); -+ mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init); -+ -+static const struct mtk_gate_regs peri0_cg_regs __initconst = { -+ .set_ofs = 0x0008, -+ .clr_ofs = 0x0010, -+ .sta_ofs = 0x0018, -+}; -+ -+static const struct mtk_gate_regs peri1_cg_regs __initconst = { -+ .set_ofs = 0x000c, -+ .clr_ofs = 0x0014, -+ .sta_ofs = 0x001c, -+}; -+ -+#define GATE_PERI0(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &peri0_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+#define GATE_PERI1(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &peri1_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+static const struct mtk_gate peri_clks[] __initconst = { -+ GATE_PERI1(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31), -+ GATE_PERI1(CLK_PERI_ETH, "eth_ck", "clk26m", 30), -+ GATE_PERI1(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29), -+ GATE_PERI1(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28), -+ GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27), -+ GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26), -+ GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25), -+ GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24), -+ GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23), -+ GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22), -+ GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21), -+ GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20), -+ GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19), -+ GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18), -+ GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17), -+ GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16), -+ GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15), -+ GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14), -+ GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13), -+ GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12), -+ GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11), -+ GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10), -+ GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9), -+ GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8), -+ GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7), -+ GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6), -+ GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5), -+ GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4), -+ GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3), -+ GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2), -+ GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1), -+ GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0), -+ -+ GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card", 11), -+ GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10), -+ GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9), -+ GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8), -+ GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7), -+ GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6), -+ GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5), -+ GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi_sel", 4), -+ GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi_sel", 3), -+ GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2), -+ GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1), -+ GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0), -+}; -+ -+static const char * const uart_ck_sel_parents[] __initconst = { -+ "clk26m", -+ "uart_sel", -+}; -+ -+static const struct mtk_composite peri_muxs[] __initconst = { -+ MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, 0x40c, 0, 1), -+ MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, 0x40c, 1, 1), -+ MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, 0x40c, 2, 1), -+ MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, 0x40c, 3, 1), -+}; -+ -+static void __init mtk_pericfg_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ void __iomem *base; -+ int r; -+ -+ base = of_iomap(node, 0); -+ if (!base) { -+ pr_err("%s(): ioremap failed\n", __func__); -+ return; -+ } -+ -+ clk_data = mtk_alloc_clk_data(CLK_PERI_NR); -+ -+ mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), -+ clk_data); -+ -+ mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base, -+ &lock, clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init); -+ -+static const struct mtk_gate_regs disp0_cg_regs __initconst = { -+ .set_ofs = 0x0104, -+ .clr_ofs = 0x0108, -+ .sta_ofs = 0x0100, -+}; -+ -+static const struct mtk_gate_regs disp1_cg_regs __initconst = { -+ .set_ofs = 0x0114, -+ .clr_ofs = 0x0118, -+ .sta_ofs = 0x0110, -+}; -+ -+#define GATE_DISP0(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &disp0_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+#define GATE_DISP1(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &disp1_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+static const struct mtk_gate mm_clks[] __initconst = { -+ GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0), -+ GATE_DISP0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), -+ GATE_DISP0(CLK_MM_CMDQ, "mm_cmdq", "mm_sel", 2), -+ GATE_DISP0(CLK_MM_MUTEX, "mm_mutex", "mm_sel", 3), -+ GATE_DISP0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 4), -+ GATE_DISP0(CLK_MM_DISP_BLS, "mm_disp_bls", "mm_sel", 5), -+ GATE_DISP0(CLK_MM_DISP_WDMA, "mm_disp_wdma", "mm_sel", 6), -+ GATE_DISP0(CLK_MM_DISP_RDMA, "mm_disp_rdma", "mm_sel", 7), -+ GATE_DISP0(CLK_MM_DISP_OVL, "mm_disp_ovl", "mm_sel", 8), -+ GATE_DISP0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9), -+ GATE_DISP0(CLK_MM_MDP_WROT, "mm_mdp_wrot", "mm_sel", 10), -+ GATE_DISP0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11), -+ GATE_DISP0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 12), -+ GATE_DISP0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 13), -+ GATE_DISP0(CLK_MM_MDP_RDMA, "mm_mdp_rdma", "mm_sel", 14), -+ GATE_DISP0(CLK_MM_MDP_BLS_26M, "mm_mdp_bls_26m", "clk26m", 15), -+ GATE_DISP0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 16), -+ GATE_DISP0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 17), -+ GATE_DISP0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "rtc_sel", 18), -+ GATE_DISP0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19), -+ GATE_DISP0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 20), -+ GATE_DISP1(CLK_MM_DSI_ENGINE, "mm_dsi_eng", "mm_sel", 0), -+ GATE_DISP1(CLK_MM_DSI_DIG, "mm_dsi_dig", "dsio_lntc_dsiclk", 1), -+ GATE_DISP1(CLK_MM_DPI_DIGL, "mm_dpi_digl", "dpi0_sel", 2), -+ GATE_DISP1(CLK_MM_DPI_ENGINE, "mm_dpi_eng", "mm_sel", 3), -+ GATE_DISP1(CLK_MM_DPI1_DIGL, "mm_dpi1_digl", "dpi1_sel", 4), -+ GATE_DISP1(CLK_MM_DPI1_ENGINE, "mm_dpi1_eng", "mm_sel", 5), -+ GATE_DISP1(CLK_MM_TVE_OUTPUT, "mm_tve_output", "tve_sel", 6), -+ GATE_DISP1(CLK_MM_TVE_INPUT, "mm_tve_input", "dpi0_sel", 7), -+ GATE_DISP1(CLK_MM_HDMI_PIXEL, "mm_hdmi_pixel", "dpi1_sel", 8), -+ GATE_DISP1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmi_sel", 9), -+ GATE_DISP1(CLK_MM_HDMI_AUDIO, "mm_hdmi_audio", "apll_sel", 10), -+ GATE_DISP1(CLK_MM_HDMI_SPDIF, "mm_hdmi_spdif", "apll_sel", 11), -+ GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14), -+}; -+ -+static void __init mtk_mmsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_MM_NR); -+ -+ mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_mmsys, "mediatek,mt2701-mmsys", mtk_mmsys_init); -+ -+static const struct mtk_gate_regs img_cg_regs __initconst = { -+ .set_ofs = 0x0004, -+ .clr_ofs = 0x0008, -+ .sta_ofs = 0x0000, -+}; -+ -+#define GATE_IMG(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &img_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr, \ -+ } -+ -+static const struct mtk_gate img_clks[] __initconst = { -+ GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0), -+ GATE_IMG(CLK_IMG_RESZ, "img_resz", "mm_sel", 1), -+ GATE_IMG(CLK_IMG_JPGDEC, "img_jpgdec", "mm_sel", 5), -+ GATE_IMG(CLK_IMG_VENC_LT, "img_venc_lt", "mm_sel", 8), -+ GATE_IMG(CLK_IMG_VENC, "img_venc", "mm_sel", 9), -+}; -+ -+static void __init mtk_imgsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_IMG_NR); -+ -+ mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_imgsys, "mediatek,mt2701-imgsys", mtk_imgsys_init); -+ -+static const struct mtk_gate_regs vdec0_cg_regs __initconst = { -+ .set_ofs = 0x0000, -+ .clr_ofs = 0x0004, -+ .sta_ofs = 0x0000, -+}; -+ -+static const struct mtk_gate_regs vdec1_cg_regs __initconst = { -+ .set_ofs = 0x0008, -+ .clr_ofs = 0x000c, -+ .sta_ofs = 0x0008, -+}; -+ -+#define GATE_VDEC0(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &vdec0_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr_inv, \ -+ } -+ -+#define GATE_VDEC1(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &vdec1_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr_inv, \ -+ } -+ -+static const struct mtk_gate vdec_clks[] __initconst = { -+ GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0), -+ GATE_VDEC1(CLK_VDEC_LARB, "vdec_larb_cken", "mm_sel", 0), -+}; -+ -+static void __init mtk_vdecsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_VDEC_NR); -+ -+ mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_vdecsys, "mediatek,mt2701-vdecsys", mtk_vdecsys_init); -+ -+static const struct mtk_gate_regs hif_cg_regs __initconst = { -+ .sta_ofs = 0x0008, -+}; -+ -+#define GATE_HIF(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &hif_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \ -+ } -+ -+static const struct mtk_gate hif_clks[] __initconst = { -+ GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21), -+ GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22), -+ GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24), -+ GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25), -+ GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26), -+}; -+ -+static void __init mtk_hifsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR); -+ -+ mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init); -+ -+static const struct mtk_gate_regs eth_cg_regs __initconst = { -+ .sta_ofs = 0x0030, -+}; -+ -+#define GATE_eth(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = ð_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \ -+ } -+ -+static const struct mtk_gate eth_clks[] __initconst = { -+ GATE_HIF(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5), -+ GATE_HIF(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6), -+ GATE_HIF(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7), -+ GATE_HIF(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8), -+ GATE_HIF(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11), -+ GATE_HIF(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14), -+ GATE_HIF(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17), -+ GATE_HIF(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29), -+}; -+ -+static void __init mtk_ethsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR); -+ -+ mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init); -+ -+static const struct mtk_gate_regs bdp0_cg_regs __initconst = { -+ .set_ofs = 0x0104, -+ .clr_ofs = 0x0108, -+ .sta_ofs = 0x0100, -+}; -+ -+static const struct mtk_gate_regs bdp1_cg_regs __initconst = { -+ .set_ofs = 0x0114, -+ .clr_ofs = 0x0118, -+ .sta_ofs = 0x0110, -+}; -+ -+#define GATE_BDP0(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &bdp0_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr_inv, \ -+ } -+ -+#define GATE_BDP1(_id, _name, _parent, _shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .regs = &bdp1_cg_regs, \ -+ .shift = _shift, \ -+ .ops = &mtk_clk_gate_ops_setclr_inv, \ -+ } -+ -+static const struct mtk_gate bdp_clks[] __initconst = { -+ GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0), -+ GATE_BDP0(CLK_BDP_BRG_DRAM, "brg_dram", "mm_sel", 1), -+ GATE_BDP0(CLK_BDP_LARB_DRAM, "larb_dram", "mm_sel", 2), -+ GATE_BDP0(CLK_BDP_WR_VDI_PXL, "wr_vdi_pxl", "hdmi_0_deep340m", 3), -+ GATE_BDP0(CLK_BDP_WR_VDI_DRAM, "wr_vdi_dram", "mm_sel", 4), -+ GATE_BDP0(CLK_BDP_WR_B, "wr_bclk", "mm_sel", 5), -+ GATE_BDP0(CLK_BDP_DGI_IN, "dgi_in", "dpi1_sel", 6), -+ GATE_BDP0(CLK_BDP_DGI_OUT, "dgi_out", "dpi_sel", 7), -+ GATE_BDP0(CLK_BDP_FMT_MAST_27, "fmt_mast_27", "dpi1_sel", 8), -+ GATE_BDP0(CLK_BDP_FMT_B, "fmt_bclk", "mm_sel", 9), -+ GATE_BDP0(CLK_BDP_OSD_B, "osd_bclk", "mm_sel", 10), -+ GATE_BDP0(CLK_BDP_OSD_DRAM, "osd_dram", "mm_sel", 11), -+ GATE_BDP0(CLK_BDP_OSD_AGENT, "osd_agent", "osd_sel", 12), -+ GATE_BDP0(CLK_BDP_OSD_PXL, "osd_pxl", "dpi1_sel", 13), -+ GATE_BDP0(CLK_BDP_RLE_B, "rle_bclk", "mm_sel", 14), -+ GATE_BDP0(CLK_BDP_RLE_AGENT, "rle_agent", "mm_sel", 15), -+ GATE_BDP0(CLK_BDP_RLE_DRAM, "rle_dram", "mm_sel", 16), -+ GATE_BDP0(CLK_BDP_F27M, "f27m", "di_sel", 17), -+ GATE_BDP0(CLK_BDP_F27M_VDOUT, "f27m_vdout", "di_sel", 18), -+ GATE_BDP0(CLK_BDP_F27_74_74, "f27_74_74", "di_sel", 19), -+ GATE_BDP0(CLK_BDP_F2FS, "f2fs", "di_sel", 20), -+ GATE_BDP0(CLK_BDP_F2FS74_148, "f2fs74_148", "di_sel", 21), -+ GATE_BDP0(CLK_BDP_FB, "fbclk", "mm_sel", 22), -+ GATE_BDP0(CLK_BDP_VDO_DRAM, "vdo_dram", "mm_sel", 23), -+ GATE_BDP0(CLK_BDP_VDO_2FS, "vdo_2fs", "di_sel", 24), -+ GATE_BDP0(CLK_BDP_VDO_B, "vdo_bclk", "mm_sel", 25), -+ GATE_BDP0(CLK_BDP_WR_DI_PXL, "wr_di_pxl", "di_sel", 26), -+ GATE_BDP0(CLK_BDP_WR_DI_DRAM, "wr_di_dram", "mm_sel", 27), -+ GATE_BDP0(CLK_BDP_WR_DI_B, "wr_di_bclk", "mm_sel", 28), -+ GATE_BDP0(CLK_BDP_NR_PXL, "nr_pxl", "nr_sel", 29), -+ GATE_BDP0(CLK_BDP_NR_DRAM, "nr_dram", "mm_sel", 30), -+ GATE_BDP0(CLK_BDP_NR_B, "nr_bclk", "mm_sel", 31), -+ GATE_BDP1(CLK_BDP_RX_F, "rx_fclk", "hadds2_fbclk", 0), -+ GATE_BDP1(CLK_BDP_RX_X, "rx_xclk", "clk26m", 1), -+ GATE_BDP1(CLK_BDP_RXPDT, "rxpdtclk", "hdmi_0_pix340m", 2), -+ GATE_BDP1(CLK_BDP_RX_CSCL_N, "rx_cscl_n", "clk26m", 3), -+ GATE_BDP1(CLK_BDP_RX_CSCL, "rx_cscl", "clk26m", 4), -+ GATE_BDP1(CLK_BDP_RX_DDCSCL_N, "rx_ddcscl_n", "hdmi_scl_rx", 5), -+ GATE_BDP1(CLK_BDP_RX_DDCSCL, "rx_ddcscl", "hdmi_scl_rx", 6), -+ GATE_BDP1(CLK_BDP_RX_VCO, "rx_vcoclk", "hadds2pll_294m", 7), -+ GATE_BDP1(CLK_BDP_RX_DP, "rx_dpclk", "hdmi_0_pll340m", 8), -+ GATE_BDP1(CLK_BDP_RX_P, "rx_pclk", "hdmi_0_pll340m", 9), -+ GATE_BDP1(CLK_BDP_RX_M, "rx_mclk", "hadds2pll_294m", 10), -+ GATE_BDP1(CLK_BDP_RX_PLL, "rx_pllclk", "hdmi_0_pix340m", 11), -+ GATE_BDP1(CLK_BDP_BRG_RT_B, "brg_rt_bclk", "mm_sel", 12), -+ GATE_BDP1(CLK_BDP_BRG_RT_DRAM, "brg_rt_dram", "mm_sel", 13), -+ GATE_BDP1(CLK_BDP_LARBRT_DRAM, "larbrt_dram", "mm_sel", 14), -+ GATE_BDP1(CLK_BDP_TMDS_SYN, "tmds_syn", "hdmi_0_pll340m", 15), -+ GATE_BDP1(CLK_BDP_HDMI_MON, "hdmi_mon", "hdmi_0_mon", 16), -+}; -+ -+static void __init mtk_bdpsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(CLK_BDP_NR); -+ -+ mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_bdpsys, "mediatek,mt2701-bdpsys", mtk_bdpsys_init); -+ -+#define MT8590_PLL_FMAX (2000 * MHZ) -+#define CON0_MT8590_RST_BAR BIT(27) -+ -+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ -+ _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .reg = _reg, \ -+ .pwr_reg = _pwr_reg, \ -+ .en_mask = _en_mask, \ -+ .flags = _flags, \ -+ .rst_bar_mask = CON0_MT8590_RST_BAR, \ -+ .fmax = MT8590_PLL_FMAX, \ -+ .pcwbits = _pcwbits, \ -+ .pd_reg = _pd_reg, \ -+ .pd_shift = _pd_shift, \ -+ .tuner_reg = _tuner_reg, \ -+ .pcw_reg = _pcw_reg, \ -+ .pcw_shift = _pcw_shift, \ -+ } -+ -+static const struct mtk_pll_data apmixed_plls[] = { -+ PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001, 0, -+ 21, 0x204, 24, 0x0, 0x204, 0), -+ PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001, -+ HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0), -+ PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001, -+ HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14), -+ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0, -+ 21, 0x230, 4, 0x0, 0x234, 0), -+ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0, -+ 21, 0x240, 4, 0x0, 0x244, 0), -+ PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0, -+ 21, 0x250, 4, 0x0, 0x254, 0), -+ PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0, -+ 31, 0x270, 4, 0x0, 0x274, 0), -+ PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0, -+ 31, 0x280, 4, 0x0, 0x284, 0), -+ PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0, -+ 31, 0x290, 4, 0x0, 0x294, 0), -+ PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0, -+ 31, 0x2a0, 4, 0x0, 0x2a4, 0), -+ PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0, -+ 31, 0x2b0, 4, 0x0, 0x2b4, 0), -+ PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0, -+ 31, 0x2c0, 4, 0x0, 0x2c4, 0), -+ PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0, -+ 21, 0x2d0, 4, 0x0, 0x2d4, 0), -+}; -+ -+static void __init mtk_apmixedsys_init(struct device_node *node) -+{ -+ struct clk_onecell_data *clk_data; -+ int r; -+ -+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); -+ if (!clk_data) -+ return; -+ -+ mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls), -+ clk_data); -+ -+ r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); -+ if (r) -+ pr_err("%s(): could not register clock provider: %d\n", -+ __func__, r); -+} -+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys", -+ mtk_apmixedsys_init); ---- a/drivers/clk/mediatek/clk-mtk.c -+++ b/drivers/clk/mediatek/clk-mtk.c -@@ -244,3 +244,28 @@ void mtk_clk_register_composites(const s - clk_data->clks[mc->id] = clk; - } - } -+ -+void __init mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, -+ int num, void __iomem *base, spinlock_t *lock, -+ struct clk_onecell_data *clk_data) -+{ -+ struct clk *clk; -+ int i; -+ -+ for (i = 0; i < num; i++) { -+ const struct mtk_clk_divider *mcd = &mcds[i]; -+ -+ clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, -+ mcd->flags, base + mcd->div_reg, mcd->div_shift, -+ mcd->div_width, mcd->clk_divider_flags, lock); -+ -+ if (IS_ERR(clk)) { -+ pr_err("Failed to register clk %s: %ld\n", -+ mcd->name, PTR_ERR(clk)); -+ continue; -+ } -+ -+ if (clk_data) -+ clk_data->clks[mcd->id] = clk; -+ } -+} ---- a/drivers/clk/mediatek/clk-mtk.h -+++ b/drivers/clk/mediatek/clk-mtk.h -@@ -121,7 +121,8 @@ struct mtk_composite { - .flags = CLK_SET_RATE_PARENT, \ - } - --#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \ -+#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ -+ _div_width, _div_shift) { \ - .id = _id, \ - .parent = _parent, \ - .name = _name, \ -@@ -156,8 +157,36 @@ struct mtk_gate { - const struct clk_ops *ops; - }; - --int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, -- int num, struct clk_onecell_data *clk_data); -+int mtk_clk_register_gates(struct device_node *node, -+ const struct mtk_gate *clks, int num, -+ struct clk_onecell_data *clk_data); -+ -+struct mtk_clk_divider { -+ int id; -+ const char *name; -+ const char *parent_name; -+ unsigned long flags; -+ -+ uint32_t div_reg; -+ unsigned char div_shift; -+ unsigned char div_width; -+ unsigned char clk_divider_flags; -+ const struct clk_div_table *clk_div_table; -+}; -+ -+#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ -+ .id = _id, \ -+ .name = _name, \ -+ .parent_name = _parent, \ -+ .flags = CLK_SET_RATE_PARENT, \ -+ .div_reg = _reg, \ -+ .div_shift = _shift, \ -+ .div_width = _width, \ -+} -+ -+void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, -+ int num, void __iomem *base, spinlock_t *lock, -+ struct clk_onecell_data *clk_data); - - struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); - diff --git a/target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch new file mode 100644 index 0000000000..0b47635170 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0009-soc-mediatek-Add-MT2701-scpsys-driver.patch @@ -0,0 +1,194 @@ +From fb9f97e047f5a831a54cd61529b8cfdc4d413bb6 Mon Sep 17 00:00:00 2001 +From: Shunli Wang +Date: Thu, 20 Oct 2016 16:56:38 +0800 +Subject: [PATCH 09/57] soc: mediatek: Add MT2701 scpsys driver + +Add scpsys driver for MT2701. + +mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should +be enabled on both arm64 and arm platforms. + +Signed-off-by: Shunli Wang +Signed-off-by: James Liao +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + drivers/soc/mediatek/Kconfig | 2 +- + drivers/soc/mediatek/mtk-scpsys.c | 108 +++++++++++++++++++++++++++++++++++++- + 2 files changed, 108 insertions(+), 2 deletions(-) + +--- a/drivers/soc/mediatek/Kconfig ++++ b/drivers/soc/mediatek/Kconfig +@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP + config MTK_SCPSYS + bool "MediaTek SCPSYS Support" + depends on ARCH_MEDIATEK || COMPILE_TEST +- default ARM64 && ARCH_MEDIATEK ++ default ARCH_MEDIATEK + select REGMAP + select MTK_INFRACFG + select PM_GENERIC_DOMAINS if PM +--- a/drivers/soc/mediatek/mtk-scpsys.c ++++ b/drivers/soc/mediatek/mtk-scpsys.c +@@ -20,6 +20,7 @@ + #include + #include + ++#include + #include + + #define SPM_VDE_PWR_CON 0x0210 +@@ -27,8 +28,13 @@ + #define SPM_VEN_PWR_CON 0x0230 + #define SPM_ISP_PWR_CON 0x0238 + #define SPM_DIS_PWR_CON 0x023c ++#define SPM_CONN_PWR_CON 0x0280 + #define SPM_VEN2_PWR_CON 0x0298 +-#define SPM_AUDIO_PWR_CON 0x029c ++#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ ++#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ ++#define SPM_ETH_PWR_CON 0x02a0 ++#define SPM_HIF_PWR_CON 0x02a4 ++#define SPM_IFR_MSC_PWR_CON 0x02a8 + #define SPM_MFG_2D_PWR_CON 0x02c0 + #define SPM_MFG_ASYNC_PWR_CON 0x02c4 + #define SPM_USB_PWR_CON 0x02cc +@@ -42,10 +48,15 @@ + #define PWR_ON_2ND_BIT BIT(3) + #define PWR_CLK_DIS_BIT BIT(4) + ++#define PWR_STATUS_CONN BIT(1) + #define PWR_STATUS_DISP BIT(3) + #define PWR_STATUS_MFG BIT(4) + #define PWR_STATUS_ISP BIT(5) + #define PWR_STATUS_VDEC BIT(7) ++#define PWR_STATUS_BDP BIT(14) ++#define PWR_STATUS_ETH BIT(15) ++#define PWR_STATUS_HIF BIT(16) ++#define PWR_STATUS_IFR_MSC BIT(17) + #define PWR_STATUS_VENC_LT BIT(20) + #define PWR_STATUS_VENC BIT(21) + #define PWR_STATUS_MFG_2D BIT(22) +@@ -59,6 +70,7 @@ enum clk_id { + CLK_MFG, + CLK_VENC, + CLK_VENC_LT, ++ CLK_ETHIF, + CLK_MAX, + }; + +@@ -68,6 +80,7 @@ static const char * const clk_names[] = + "mfg", + "venc", + "venc_lt", ++ "ethif", + NULL, + }; + +@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s + } + + /* ++ * MT2701 power domain support ++ */ ++ ++static const struct scp_domain_data scp_domain_data_mt2701[] = { ++ [MT2701_POWER_DOMAIN_CONN] = { ++ .name = "conn", ++ .sta_mask = PWR_STATUS_CONN, ++ .ctl_offs = SPM_CONN_PWR_CON, ++ .bus_prot_mask = 0x0104, ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_DISP] = { ++ .name = "disp", ++ .sta_mask = PWR_STATUS_DISP, ++ .ctl_offs = SPM_DIS_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .clk_id = {CLK_MM}, ++ .bus_prot_mask = 0x0002, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_VDEC] = { ++ .name = "vdec", ++ .sta_mask = PWR_STATUS_VDEC, ++ .ctl_offs = SPM_VDE_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_ISP] = { ++ .name = "isp", ++ .sta_mask = PWR_STATUS_ISP, ++ .ctl_offs = SPM_ISP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_MM}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_BDP] = { ++ .name = "bdp", ++ .sta_mask = PWR_STATUS_BDP, ++ .ctl_offs = SPM_BDP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_ETH] = { ++ .name = "eth", ++ .sta_mask = PWR_STATUS_ETH, ++ .ctl_offs = SPM_ETH_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_ETHIF}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_HIF] = { ++ .name = "hif", ++ .sta_mask = PWR_STATUS_HIF, ++ .ctl_offs = SPM_HIF_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_ETHIF}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_IFR_MSC] = { ++ .name = "ifr_msc", ++ .sta_mask = PWR_STATUS_IFR_MSC, ++ .ctl_offs = SPM_IFR_MSC_PWR_CON, ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++}; ++ ++#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701) ++ ++static int __init scpsys_probe_mt2701(struct platform_device *pdev) ++{ ++ struct scp *scp; ++ ++ scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701); ++ if (IS_ERR(scp)) ++ return PTR_ERR(scp); ++ ++ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701); ++ ++ return 0; ++} ++ ++/* + * MT8173 power domain support + */ + +@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st + + static const struct of_device_id of_scpsys_match_tbl[] = { + { ++ .compatible = "mediatek,mt2701-scpsys", ++ .data = scpsys_probe_mt2701, ++ }, { + .compatible = "mediatek,mt8173-scpsys", + .data = scpsys_probe_mt8173, + }, { diff --git a/target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch new file mode 100644 index 0000000000..a7ebb060ce --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0010-clk-add-hifsys-reset.patch @@ -0,0 +1,30 @@ +From 600e2bd5c3019f31e90ec876f4efb6c209cf0d73 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 6 Jan 2016 20:06:49 +0100 +Subject: [PATCH 10/57] clk: add hifsys reset + +Hi, + +small patch to add hifsys reset bits. Maybe you could add it to the next +version of your patch series. i have teste scpsys and clk on mt7623 today +and it works well. + +thanks, + John + +Signed-off-by: John Crispin +--- + drivers/clk/mediatek/clk-mt2701.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_register_reset_controller(node, 1, 0x34); + } + CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init); + diff --git a/target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch deleted file mode 100644 index 18d4fbf252..0000000000 --- a/target/linux/mediatek/patches-4.9/0011-reset-mediatek-mt2701-reset-driver.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 3ba0020ea70ffb5503eff1823be7fa5ceda38286 Mon Sep 17 00:00:00 2001 -From: Shunli Wang -Date: Tue, 5 Jan 2016 14:30:22 +0800 -Subject: [PATCH 011/102] reset: mediatek: mt2701 reset driver - -In infrasys and perifsys, there are many reset -control bits for kinds of modules. These bits are -used as actual reset controllers to be registered -into kernel's generic reset controller framework. - -Signed-off-by: Shunli Wang -Acked-by: Philipp Zabel ---- - drivers/clk/mediatek/clk-mt2701.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/clk/mediatek/clk-mt2701.c -+++ b/drivers/clk/mediatek/clk-mt2701.c -@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_register_reset_controller(node, 2, 0x30); - } - CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init); - -@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_register_reset_controller(node, 2, 0x0); - } - CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init); - diff --git a/target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch new file mode 100644 index 0000000000..8a9da5e673 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0011-scpsys-various-fixes.patch @@ -0,0 +1,20 @@ +From 1e889b3d38ab5fb425762da57313b4cc8fc2f165 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Sun, 21 Feb 2016 13:52:12 +0100 +Subject: [PATCH 11/57] scpsys: various fixes + +--- + drivers/clk/mediatek/clk-mt2701.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_register_reset_controller(node, 1, 0x34); + } + CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init); + diff --git a/target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch deleted file mode 100644 index 73e92dcec6..0000000000 --- a/target/linux/mediatek/patches-4.9/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 32fa899c6ab79953e4f470fb23c38bcc40edc5c8 Mon Sep 17 00:00:00 2001 -From: Erin Lo -Date: Mon, 28 Dec 2015 15:09:02 +0800 -Subject: [PATCH 012/102] ARM: mediatek: Add MT2701 config options for - mediatek SoCs. - -The upcoming MTK pinctrl driver have a big pin table for each SoC -and we don't want to bloat the kernel binary if we don't need it. -Add config options so we can build for one SoC only. Add MT2701. - -Signed-off-by: Erin Lo -Acked-by: Linus Walleij ---- - arch/arm/mach-mediatek/Kconfig | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/arch/arm/mach-mediatek/Kconfig -+++ b/arch/arm/mach-mediatek/Kconfig -@@ -14,6 +14,10 @@ config MACH_MT2701 - bool "MediaTek MT2701 SoCs support" - default ARCH_MEDIATEK - -+config MACH_MT2701 -+ bool "MediaTek MT2701 SoCs support" -+ default ARCH_MEDIATEK -+ - config MACH_MT6589 - bool "MediaTek MT6589 SoCs support" - default ARCH_MEDIATEK diff --git a/target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch new file mode 100644 index 0000000000..ed4111dce3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0012-clk-dont-disable-unused-clocks.patch @@ -0,0 +1,21 @@ +From 0e60d2112968ccb2570535bf19fb5020c9b28c08 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 7 Apr 2016 07:18:35 +0200 +Subject: [PATCH 12/57] clk: dont disable unused clocks + +Signed-off-by: John Crispin +--- + drivers/clk/clk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/clk.c ++++ b/drivers/clk/clk.c +@@ -796,7 +796,7 @@ unlock_out: + clk_core_disable_unprepare(core->parent); + } + +-static bool clk_ignore_unused; ++static bool clk_ignore_unused = true; + static int __init clk_ignore_unused_setup(char *__unused) + { + clk_ignore_unused = true; diff --git a/target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch new file mode 100644 index 0000000000..26257bd42f --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0013-clk-mediatek-enable-critical-clocks.patch @@ -0,0 +1,69 @@ +From 03bead9276653dc842f6970250bc7eba41faf777 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 06:46:51 +0200 +Subject: [PATCH 13/57] clk: mediatek: enable critical clocks + +Signed-off-by: John Crispin +--- + drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[] + GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28), + }; + ++static struct clk_onecell_data *mt7623_top_clk_data __initdata; ++static struct clk_onecell_data *mt7623_pll_clk_data __initdata; ++ ++static void __init mtk_clk_enable_critical(void) ++{ ++ if (!mt7623_top_clk_data || !mt7623_pll_clk_data) ++ return; ++ ++ clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]); ++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]); ++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]); ++ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]); ++} ++ + static void __init mtk_topckgen_init(struct device_node *node) + { + struct clk_onecell_data *clk_data; +@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str + return; + } + +- clk_data = mtk_alloc_clk_data(CLK_TOP_NR); ++ mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR); + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); +@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_clk_enable_critical(); + } + CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init); + +@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s + struct clk_onecell_data *clk_data; + int r; + +- clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); ++ mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); + if (!clk_data) + return; + +@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); ++ ++ mtk_clk_enable_critical(); + } + CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys", + mtk_apmixedsys_init); diff --git a/target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch new file mode 100644 index 0000000000..7e19c6f23b --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0014-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch @@ -0,0 +1,287 @@ +From 3a947321d72af191ee87a390295c661c876cc6f4 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 02:26:37 +0200 +Subject: [PATCH 14/57] clk: mediatek: Export CPU mux clocks for CPU frequency + control + +This patch adds CPU mux clocks which are used by Mediatek cpufreq driver +for intermediate clock source switching. + +Signed-off-by: Pi-Cheng Chen +--- + drivers/clk/mediatek/Makefile | 2 +- + drivers/clk/mediatek/clk-cpumux.c | 127 +++++++++++++++++++++++++++++++++ + drivers/clk/mediatek/clk-cpumux.h | 22 ++++++ + drivers/clk/mediatek/clk-mt2701.c | 8 +++ + drivers/clk/mediatek/clk-mt8173.c | 23 ++++++ + include/dt-bindings/clock/mt2701-clk.h | 3 +- + include/dt-bindings/clock/mt8173-clk.h | 4 +- + 7 files changed, 186 insertions(+), 3 deletions(-) + create mode 100644 drivers/clk/mediatek/clk-cpumux.c + create mode 100644 drivers/clk/mediatek/clk-cpumux.h + +--- a/drivers/clk/mediatek/Makefile ++++ b/drivers/clk/mediatek/Makefile +@@ -1,4 +1,4 @@ +-obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o ++obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o + obj-$(CONFIG_RESET_CONTROLLER) += reset.o + obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o + obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o +--- /dev/null ++++ b/drivers/clk/mediatek/clk-cpumux.c +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (c) 2015 Linaro Ltd. ++ * Author: Pi-Cheng Chen ++ * ++ * 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 ++#include ++#include ++ ++#include "clk-mtk.h" ++#include "clk-cpumux.h" ++ ++struct mtk_clk_cpumux { ++ struct clk_hw hw; ++ struct regmap *regmap; ++ u32 reg; ++ u32 mask; ++ u8 shift; ++}; ++ ++static inline struct mtk_clk_cpumux *to_mtk_clk_mux(struct clk_hw *_hw) ++{ ++ return container_of(_hw, struct mtk_clk_cpumux, hw); ++} ++ ++static u8 clk_cpumux_get_parent(struct clk_hw *hw) ++{ ++ struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw); ++ int num_parents = clk_hw_get_num_parents(hw); ++ unsigned int val; ++ ++ regmap_read(mux->regmap, mux->reg, &val); ++ ++ val >>= mux->shift; ++ val &= mux->mask; ++ ++ if (val >= num_parents) ++ return -EINVAL; ++ ++ return val; ++} ++ ++static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw); ++ u32 mask, val; ++ ++ val = index << mux->shift; ++ mask = mux->mask << mux->shift; ++ ++ return regmap_update_bits(mux->regmap, mux->reg, mask, val); ++} ++ ++static const struct clk_ops clk_cpumux_ops = { ++ .get_parent = clk_cpumux_get_parent, ++ .set_parent = clk_cpumux_set_parent, ++}; ++ ++static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux, ++ struct regmap *regmap) ++{ ++ struct mtk_clk_cpumux *cpumux; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL); ++ if (!cpumux) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = mux->name; ++ init.ops = &clk_cpumux_ops; ++ init.parent_names = mux->parent_names; ++ init.num_parents = mux->num_parents; ++ init.flags = mux->flags; ++ ++ cpumux->reg = mux->mux_reg; ++ cpumux->shift = mux->mux_shift; ++ cpumux->mask = BIT(mux->mux_width) - 1; ++ cpumux->regmap = regmap; ++ cpumux->hw.init = &init; ++ ++ clk = clk_register(NULL, &cpumux->hw); ++ if (IS_ERR(clk)) ++ kfree(cpumux); ++ ++ return clk; ++} ++ ++int __init mtk_clk_register_cpumuxes(struct device_node *node, ++ const struct mtk_composite *clks, int num, ++ struct clk_onecell_data *clk_data) ++{ ++ int i; ++ struct clk *clk; ++ struct regmap *regmap; ++ ++ regmap = syscon_node_to_regmap(node); ++ if (IS_ERR(regmap)) { ++ pr_err("Cannot find regmap for %s: %ld\n", node->full_name, ++ PTR_ERR(regmap)); ++ return PTR_ERR(regmap); ++ } ++ ++ for (i = 0; i < num; i++) { ++ const struct mtk_composite *mux = &clks[i]; ++ ++ clk = mtk_clk_register_cpumux(mux, regmap); ++ if (IS_ERR(clk)) { ++ pr_err("Failed to register clk %s: %ld\n", ++ mux->name, PTR_ERR(clk)); ++ continue; ++ } ++ ++ clk_data->clks[mux->id] = clk; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drivers/clk/mediatek/clk-cpumux.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (c) 2015 Linaro Ltd. ++ * Author: Pi-Cheng Chen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __DRV_CLK_CPUMUX_H ++#define __DRV_CLK_CPUMUX_H ++ ++int mtk_clk_register_cpumuxes(struct device_node *node, ++ const struct mtk_composite *clks, int num, ++ struct clk_onecell_data *clk_data); ++ ++#endif /* __DRV_CLK_CPUMUX_H */ +--- a/drivers/clk/mediatek/clk-mt2701.c ++++ b/drivers/clk/mediatek/clk-mt2701.c +@@ -18,6 +18,7 @@ + + #include "clk-mtk.h" + #include "clk-gate.h" ++#include "clk-cpumux.h" + + #include + +@@ -465,6 +466,10 @@ static const char * const cpu_parents[] + "mmpll" + }; + ++static const struct mtk_composite cpu_muxes[] __initconst = { ++ MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2), ++}; ++ + static const struct mtk_composite top_muxes[] __initconst = { + MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, + 0x0040, 0, 3, INVALID_MUX_GATE_BIT), +@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str + mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), + clk_data); + ++ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), ++ clk_data); ++ + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", +--- a/drivers/clk/mediatek/clk-mt8173.c ++++ b/drivers/clk/mediatek/clk-mt8173.c +@@ -18,6 +18,7 @@ + + #include "clk-mtk.h" + #include "clk-gate.h" ++#include "clk-cpumux.h" + + #include + +@@ -525,6 +526,25 @@ static const char * const i2s3_b_ck_pare + "apll2_div5" + }; + ++static const char * const ca53_parents[] __initconst = { ++ "clk26m", ++ "armca7pll", ++ "mainpll", ++ "univpll" ++}; ++ ++static const char * const ca57_parents[] __initconst = { ++ "clk26m", ++ "armca15pll", ++ "mainpll", ++ "univpll" ++}; ++ ++static const struct mtk_composite cpu_muxes[] __initconst = { ++ MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2), ++ MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2), ++}; ++ + static const struct mtk_composite top_muxes[] __initconst = { + /* CLK_CFG_0 */ + MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3), +@@ -948,6 +968,9 @@ static void __init mtk_infrasys_init(str + clk_data); + mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data); + ++ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), ++ clk_data); ++ + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", +--- a/include/dt-bindings/clock/mt2701-clk.h ++++ b/include/dt-bindings/clock/mt2701-clk.h +@@ -221,7 +221,8 @@ + #define CLK_INFRA_PMICWRAP 17 + #define CLK_INFRA_DDCCI 18 + #define CLK_INFRA_CLK_13M 19 +-#define CLK_INFRA_NR 20 ++#define CLK_INFRA_CPUSEL 20 ++#define CLK_INFRA_NR 21 + + /* PERICFG */ + +--- a/include/dt-bindings/clock/mt8173-clk.h ++++ b/include/dt-bindings/clock/mt8173-clk.h +@@ -193,7 +193,9 @@ + #define CLK_INFRA_PMICSPI 10 + #define CLK_INFRA_PMICWRAP 11 + #define CLK_INFRA_CLK_13M 12 +-#define CLK_INFRA_NR_CLK 13 ++#define CLK_INFRA_CA53SEL 13 ++#define CLK_INFRA_CA57SEL 14 ++#define CLK_INFRA_NR_CLK 15 + + /* PERI_SYS */ + diff --git a/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch deleted file mode 100644 index 0786e52ba6..0000000000 --- a/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch +++ /dev/null @@ -1,486 +0,0 @@ -From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001 -From: James Liao -Date: Thu, 20 Oct 2016 16:56:35 +0800 -Subject: [PATCH 1/2] soc: mediatek: Refine scpsys to support multiple platform - -Refine scpsys driver common code to support multiple SoC / platform. - -Signed-off-by: James Liao -Reviewed-by: Kevin Hilman -Signed-off-by: Matthias Brugger ---- - drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++--------------- - 1 file changed, 210 insertions(+), 138 deletions(-) - ---- a/drivers/soc/mediatek/mtk-scpsys.c -+++ b/drivers/soc/mediatek/mtk-scpsys.c -@@ -11,17 +11,15 @@ - * GNU General Public License for more details. - */ - #include --#include -+#include - #include --#include - #include --#include - #include - #include - #include --#include --#include - #include -+#include -+ - #include - - #define SPM_VDE_PWR_CON 0x0210 -@@ -34,6 +32,7 @@ - #define SPM_MFG_2D_PWR_CON 0x02c0 - #define SPM_MFG_ASYNC_PWR_CON 0x02c4 - #define SPM_USB_PWR_CON 0x02cc -+ - #define SPM_PWR_STATUS 0x060c - #define SPM_PWR_STATUS_2ND 0x0610 - -@@ -55,12 +54,21 @@ - #define PWR_STATUS_USB BIT(25) - - enum clk_id { -- MT8173_CLK_NONE, -- MT8173_CLK_MM, -- MT8173_CLK_MFG, -- MT8173_CLK_VENC, -- MT8173_CLK_VENC_LT, -- MT8173_CLK_MAX, -+ CLK_NONE, -+ CLK_MM, -+ CLK_MFG, -+ CLK_VENC, -+ CLK_VENC_LT, -+ CLK_MAX, -+}; -+ -+static const char * const clk_names[] = { -+ NULL, -+ "mm", -+ "mfg", -+ "venc", -+ "venc_lt", -+ NULL, - }; - - #define MAX_CLKS 2 -@@ -76,98 +84,6 @@ struct scp_domain_data { - bool active_wakeup; - }; - --static const struct scp_domain_data scp_domain_data[] = { -- [MT8173_POWER_DOMAIN_VDEC] = { -- .name = "vdec", -- .sta_mask = PWR_STATUS_VDEC, -- .ctl_offs = SPM_VDE_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(12, 12), -- .clk_id = {MT8173_CLK_MM}, -- }, -- [MT8173_POWER_DOMAIN_VENC] = { -- .name = "venc", -- .sta_mask = PWR_STATUS_VENC, -- .ctl_offs = SPM_VEN_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(15, 12), -- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, -- }, -- [MT8173_POWER_DOMAIN_ISP] = { -- .name = "isp", -- .sta_mask = PWR_STATUS_ISP, -- .ctl_offs = SPM_ISP_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(13, 12), -- .clk_id = {MT8173_CLK_MM}, -- }, -- [MT8173_POWER_DOMAIN_MM] = { -- .name = "mm", -- .sta_mask = PWR_STATUS_DISP, -- .ctl_offs = SPM_DIS_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(12, 12), -- .clk_id = {MT8173_CLK_MM}, -- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | -- MT8173_TOP_AXI_PROT_EN_MM_M1, -- }, -- [MT8173_POWER_DOMAIN_VENC_LT] = { -- .name = "venc_lt", -- .sta_mask = PWR_STATUS_VENC_LT, -- .ctl_offs = SPM_VEN2_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(15, 12), -- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, -- }, -- [MT8173_POWER_DOMAIN_AUDIO] = { -- .name = "audio", -- .sta_mask = PWR_STATUS_AUDIO, -- .ctl_offs = SPM_AUDIO_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(15, 12), -- .clk_id = {MT8173_CLK_NONE}, -- }, -- [MT8173_POWER_DOMAIN_USB] = { -- .name = "usb", -- .sta_mask = PWR_STATUS_USB, -- .ctl_offs = SPM_USB_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(15, 12), -- .clk_id = {MT8173_CLK_NONE}, -- .active_wakeup = true, -- }, -- [MT8173_POWER_DOMAIN_MFG_ASYNC] = { -- .name = "mfg_async", -- .sta_mask = PWR_STATUS_MFG_ASYNC, -- .ctl_offs = SPM_MFG_ASYNC_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = 0, -- .clk_id = {MT8173_CLK_MFG}, -- }, -- [MT8173_POWER_DOMAIN_MFG_2D] = { -- .name = "mfg_2d", -- .sta_mask = PWR_STATUS_MFG_2D, -- .ctl_offs = SPM_MFG_2D_PWR_CON, -- .sram_pdn_bits = GENMASK(11, 8), -- .sram_pdn_ack_bits = GENMASK(13, 12), -- .clk_id = {MT8173_CLK_NONE}, -- }, -- [MT8173_POWER_DOMAIN_MFG] = { -- .name = "mfg", -- .sta_mask = PWR_STATUS_MFG, -- .ctl_offs = SPM_MFG_PWR_CON, -- .sram_pdn_bits = GENMASK(13, 8), -- .sram_pdn_ack_bits = GENMASK(21, 16), -- .clk_id = {MT8173_CLK_NONE}, -- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | -- MT8173_TOP_AXI_PROT_EN_MFG_M0 | -- MT8173_TOP_AXI_PROT_EN_MFG_M1 | -- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, -- }, --}; -- --#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) -- - struct scp; - - struct scp_domain { -@@ -179,7 +95,7 @@ struct scp_domain { - }; - - struct scp { -- struct scp_domain domains[NUM_DOMAINS]; -+ struct scp_domain *domains; - struct genpd_onecell_data pd_data; - struct device *dev; - void __iomem *base; -@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct - return scpd->data->active_wakeup; - } - --static int scpsys_probe(struct platform_device *pdev) -+static void init_clks(struct platform_device *pdev, struct clk **clk) -+{ -+ int i; -+ -+ for (i = CLK_NONE + 1; i < CLK_MAX; i++) -+ clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); -+} -+ -+static struct scp *init_scp(struct platform_device *pdev, -+ const struct scp_domain_data *scp_domain_data, int num) - { - struct genpd_onecell_data *pd_data; - struct resource *res; -- int i, j, ret; -+ int i, j; - struct scp *scp; -- struct clk *clk[MT8173_CLK_MAX]; -+ struct clk *clk[CLK_MAX]; - - scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); - if (!scp) -- return -ENOMEM; -+ return ERR_PTR(-ENOMEM); - - scp->dev = &pdev->dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - scp->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(scp->base)) -- return PTR_ERR(scp->base); -+ return ERR_CAST(scp->base); -+ -+ scp->domains = devm_kzalloc(&pdev->dev, -+ sizeof(*scp->domains) * num, GFP_KERNEL); -+ if (!scp->domains) -+ return ERR_PTR(-ENOMEM); - - pd_data = &scp->pd_data; - - pd_data->domains = devm_kzalloc(&pdev->dev, -- sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); -+ sizeof(*pd_data->domains) * num, GFP_KERNEL); - if (!pd_data->domains) -- return -ENOMEM; -- -- clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); -- if (IS_ERR(clk[MT8173_CLK_MM])) -- return PTR_ERR(clk[MT8173_CLK_MM]); -- -- clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); -- if (IS_ERR(clk[MT8173_CLK_MFG])) -- return PTR_ERR(clk[MT8173_CLK_MFG]); -- -- clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); -- if (IS_ERR(clk[MT8173_CLK_VENC])) -- return PTR_ERR(clk[MT8173_CLK_VENC]); -- -- clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); -- if (IS_ERR(clk[MT8173_CLK_VENC_LT])) -- return PTR_ERR(clk[MT8173_CLK_VENC_LT]); -+ return ERR_PTR(-ENOMEM); - - scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, - "infracfg"); - if (IS_ERR(scp->infracfg)) { - dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", - PTR_ERR(scp->infracfg)); -- return PTR_ERR(scp->infracfg); -+ return ERR_CAST(scp->infracfg); - } - -- for (i = 0; i < NUM_DOMAINS; i++) { -+ for (i = 0; i < num; i++) { - struct scp_domain *scpd = &scp->domains[i]; - const struct scp_domain_data *data = &scp_domain_data[i]; - -@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_ - if (PTR_ERR(scpd->supply) == -ENODEV) - scpd->supply = NULL; - else -- return PTR_ERR(scpd->supply); -+ return ERR_CAST(scpd->supply); - } - } - -- pd_data->num_domains = NUM_DOMAINS; -+ pd_data->num_domains = num; -+ -+ init_clks(pdev, clk); - -- for (i = 0; i < NUM_DOMAINS; i++) { -+ for (i = 0; i < num; i++) { - struct scp_domain *scpd = &scp->domains[i]; - struct generic_pm_domain *genpd = &scpd->genpd; - const struct scp_domain_data *data = &scp_domain_data[i]; -@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_ - scpd->scp = scp; - - scpd->data = data; -- for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) -- scpd->clk[j] = clk[data->clk_id[j]]; -+ -+ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { -+ struct clk *c = clk[data->clk_id[j]]; -+ -+ if (IS_ERR(c)) { -+ dev_err(&pdev->dev, "%s: clk unavailable\n", -+ data->name); -+ return ERR_CAST(c); -+ } -+ -+ scpd->clk[j] = c; -+ } - - genpd->name = data->name; - genpd->power_off = scpsys_power_off; - genpd->power_on = scpsys_power_on; - genpd->dev_ops.active_wakeup = scpsys_active_wakeup; -+ } -+ -+ return scp; -+} -+ -+static void mtk_register_power_domains(struct platform_device *pdev, -+ struct scp *scp, int num) -+{ -+ struct genpd_onecell_data *pd_data; -+ int i, ret; -+ -+ for (i = 0; i < num; i++) { -+ struct scp_domain *scpd = &scp->domains[i]; -+ struct generic_pm_domain *genpd = &scpd->genpd; - - /* - * Initially turn on all domains to make the domains usable -@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_ - * valid. - */ - -+ pd_data = &scp->pd_data; -+ -+ ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); -+ if (ret) -+ dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); -+} -+ -+/* -+ * MT8173 power domain support -+ */ -+ -+static const struct scp_domain_data scp_domain_data_mt8173[] = { -+ [MT8173_POWER_DOMAIN_VDEC] = { -+ .name = "vdec", -+ .sta_mask = PWR_STATUS_VDEC, -+ .ctl_offs = SPM_VDE_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(12, 12), -+ .clk_id = {CLK_MM}, -+ }, -+ [MT8173_POWER_DOMAIN_VENC] = { -+ .name = "venc", -+ .sta_mask = PWR_STATUS_VENC, -+ .ctl_offs = SPM_VEN_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_MM, CLK_VENC}, -+ }, -+ [MT8173_POWER_DOMAIN_ISP] = { -+ .name = "isp", -+ .sta_mask = PWR_STATUS_ISP, -+ .ctl_offs = SPM_ISP_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(13, 12), -+ .clk_id = {CLK_MM}, -+ }, -+ [MT8173_POWER_DOMAIN_MM] = { -+ .name = "mm", -+ .sta_mask = PWR_STATUS_DISP, -+ .ctl_offs = SPM_DIS_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(12, 12), -+ .clk_id = {CLK_MM}, -+ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | -+ MT8173_TOP_AXI_PROT_EN_MM_M1, -+ }, -+ [MT8173_POWER_DOMAIN_VENC_LT] = { -+ .name = "venc_lt", -+ .sta_mask = PWR_STATUS_VENC_LT, -+ .ctl_offs = SPM_VEN2_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_MM, CLK_VENC_LT}, -+ }, -+ [MT8173_POWER_DOMAIN_AUDIO] = { -+ .name = "audio", -+ .sta_mask = PWR_STATUS_AUDIO, -+ .ctl_offs = SPM_AUDIO_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_NONE}, -+ }, -+ [MT8173_POWER_DOMAIN_USB] = { -+ .name = "usb", -+ .sta_mask = PWR_STATUS_USB, -+ .ctl_offs = SPM_USB_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_NONE}, -+ .active_wakeup = true, -+ }, -+ [MT8173_POWER_DOMAIN_MFG_ASYNC] = { -+ .name = "mfg_async", -+ .sta_mask = PWR_STATUS_MFG_ASYNC, -+ .ctl_offs = SPM_MFG_ASYNC_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = 0, -+ .clk_id = {CLK_MFG}, -+ }, -+ [MT8173_POWER_DOMAIN_MFG_2D] = { -+ .name = "mfg_2d", -+ .sta_mask = PWR_STATUS_MFG_2D, -+ .ctl_offs = SPM_MFG_2D_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(13, 12), -+ .clk_id = {CLK_NONE}, -+ }, -+ [MT8173_POWER_DOMAIN_MFG] = { -+ .name = "mfg", -+ .sta_mask = PWR_STATUS_MFG, -+ .ctl_offs = SPM_MFG_PWR_CON, -+ .sram_pdn_bits = GENMASK(13, 8), -+ .sram_pdn_ack_bits = GENMASK(21, 16), -+ .clk_id = {CLK_NONE}, -+ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | -+ MT8173_TOP_AXI_PROT_EN_MFG_M0 | -+ MT8173_TOP_AXI_PROT_EN_MFG_M1 | -+ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, -+ }, -+}; -+ -+#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173) -+ -+static int __init scpsys_probe_mt8173(struct platform_device *pdev) -+{ -+ struct scp *scp; -+ struct genpd_onecell_data *pd_data; -+ int ret; -+ -+ scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173); -+ if (IS_ERR(scp)) -+ return PTR_ERR(scp); -+ -+ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173); -+ -+ pd_data = &scp->pd_data; -+ - ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], - pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); - if (ret && IS_ENABLED(CONFIG_PM)) -@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_ - if (ret && IS_ENABLED(CONFIG_PM)) - dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); - -- ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); -- if (ret) -- dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); -- - return 0; - } - -+/* -+ * scpsys driver init -+ */ -+ - static const struct of_device_id of_scpsys_match_tbl[] = { - { - .compatible = "mediatek,mt8173-scpsys", -+ .data = scpsys_probe_mt8173, - }, { - /* sentinel */ - } - }; - -+static int scpsys_probe(struct platform_device *pdev) -+{ -+ int (*probe)(struct platform_device *); -+ const struct of_device_id *of_id; -+ -+ of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node); -+ if (!of_id || !of_id->data) -+ return -EINVAL; -+ -+ probe = of_id->data; -+ -+ return probe(pdev); -+} -+ - static struct platform_driver scpsys_drv = { - .probe = scpsys_probe, - .driver = { diff --git a/target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch new file mode 100644 index 0000000000..af60025c0a --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0015-cpufreq-mediatek-add-driver.patch @@ -0,0 +1,433 @@ +From 8aa2c6c4d8b20c0e9c69b15db4a0039d33f8b365 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 30 Mar 2016 23:48:53 +0200 +Subject: [PATCH 15/57] cpufreq: mediatek: add driver + +Signed-off-by: John Crispin +--- + drivers/cpufreq/Kconfig.arm | 9 + + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/mt7623-cpufreq.c | 389 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 399 insertions(+) + create mode 100644 drivers/cpufreq/mt7623-cpufreq.c + +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -74,6 +74,15 @@ config ARM_KIRKWOOD_CPUFREQ + This adds the CPUFreq driver for Marvell Kirkwood + SoCs. + ++config ARM_MT7623_CPUFREQ ++ bool "Mediatek MT7623 CPUFreq support" ++ depends on ARCH_MEDIATEK && REGULATOR ++ depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST) ++ depends on !CPU_THERMAL || THERMAL=y ++ select PM_OPP ++ help ++ This adds the CPUFreq driver support for Mediatek MT7623 SoC. ++ + config ARM_MT8173_CPUFREQ + tristate "Mediatek MT8173 CPUFreq support" + depends on ARCH_MEDIATEK && REGULATOR +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -58,6 +58,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += hi + obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o + obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o + obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o ++obj-$(CONFIG_ARM_MT7623_CPUFREQ) += mt7623-cpufreq.o + obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o + obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o + obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o +--- /dev/null ++++ b/drivers/cpufreq/mt7623-cpufreq.c +@@ -0,0 +1,389 @@ ++/* ++ * Copyright (c) 2015 Linaro Ltd. ++ * Author: Pi-Cheng Chen ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define VOLT_TOL (10000) ++ ++/* ++ * When scaling the clock frequency of a CPU clock domain, the clock source ++ * needs to be switched to another stable PLL clock temporarily until ++ * the original PLL becomes stable at target frequency. ++ */ ++struct mtk_cpu_dvfs_info { ++ struct device *cpu_dev; ++ struct regulator *proc_reg; ++ struct clk *cpu_clk; ++ struct clk *inter_clk; ++ struct thermal_cooling_device *cdev; ++ int intermediate_voltage; ++}; ++ ++static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc) ++{ ++ return regulator_set_voltage(info->proc_reg, vproc, ++ vproc + VOLT_TOL); ++} ++ ++static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, ++ unsigned int index) ++{ ++ struct cpufreq_frequency_table *freq_table = policy->freq_table; ++ struct clk *cpu_clk = policy->clk; ++ struct clk *armpll = clk_get_parent(cpu_clk); ++ struct mtk_cpu_dvfs_info *info = policy->driver_data; ++ struct device *cpu_dev = info->cpu_dev; ++ struct dev_pm_opp *opp; ++ long freq_hz, old_freq_hz; ++ int vproc, old_vproc, inter_vproc, target_vproc, ret; ++ ++ inter_vproc = info->intermediate_voltage; ++ ++ old_freq_hz = clk_get_rate(cpu_clk); ++ old_vproc = regulator_get_voltage(info->proc_reg); ++ ++ freq_hz = freq_table[index].frequency * 1000; ++ ++ rcu_read_lock(); ++ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); ++ if (IS_ERR(opp)) { ++ rcu_read_unlock(); ++ pr_err("cpu%d: failed to find OPP for %ld\n", ++ policy->cpu, freq_hz); ++ return PTR_ERR(opp); ++ } ++ vproc = dev_pm_opp_get_voltage(opp); ++ rcu_read_unlock(); ++ ++ /* ++ * If the new voltage or the intermediate voltage is higher than the ++ * current voltage, scale up voltage first. ++ */ ++ target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; ++ if (old_vproc < target_vproc) { ++ ret = mtk_cpufreq_set_voltage(info, target_vproc); ++ if (ret) { ++ pr_err("cpu%d: failed to scale up voltage!\n", ++ policy->cpu); ++ mtk_cpufreq_set_voltage(info, old_vproc); ++ return ret; ++ } ++ } ++ ++ /* Reparent the CPU clock to intermediate clock. */ ++ ret = clk_set_parent(cpu_clk, info->inter_clk); ++ if (ret) { ++ pr_err("cpu%d: failed to re-parent cpu clock!\n", ++ policy->cpu); ++ mtk_cpufreq_set_voltage(info, old_vproc); ++ WARN_ON(1); ++ return ret; ++ } ++ ++ /* Set the original PLL to target rate. */ ++ ret = clk_set_rate(armpll, freq_hz); ++ if (ret) { ++ pr_err("cpu%d: failed to scale cpu clock rate!\n", ++ policy->cpu); ++ clk_set_parent(cpu_clk, armpll); ++ mtk_cpufreq_set_voltage(info, old_vproc); ++ return ret; ++ } ++ ++ /* Set parent of CPU clock back to the original PLL. */ ++ ret = clk_set_parent(cpu_clk, armpll); ++ if (ret) { ++ pr_err("cpu%d: failed to re-parent cpu clock!\n", ++ policy->cpu); ++ mtk_cpufreq_set_voltage(info, inter_vproc); ++ WARN_ON(1); ++ return ret; ++ } ++ ++ /* ++ * If the new voltage is lower than the intermediate voltage or the ++ * original voltage, scale down to the new voltage. ++ */ ++ if (vproc < inter_vproc || vproc < old_vproc) { ++ ret = mtk_cpufreq_set_voltage(info, vproc); ++ if (ret) { ++ pr_err("cpu%d: failed to scale down voltage!\n", ++ policy->cpu); ++ clk_set_parent(cpu_clk, info->inter_clk); ++ clk_set_rate(armpll, old_freq_hz); ++ clk_set_parent(cpu_clk, armpll); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static void mtk_cpufreq_ready(struct cpufreq_policy *policy) ++{ ++ struct mtk_cpu_dvfs_info *info = policy->driver_data; ++ struct device_node *np = of_node_get(info->cpu_dev->of_node); ++ ++ if (WARN_ON(!np)) ++ return; ++ ++ if (of_find_property(np, "#cooling-cells", NULL)) { ++ info->cdev = of_cpufreq_cooling_register(np, ++ policy->related_cpus); ++ ++ if (IS_ERR(info->cdev)) { ++ dev_err(info->cpu_dev, ++ "running cpufreq without cooling device: %ld\n", ++ PTR_ERR(info->cdev)); ++ ++ info->cdev = NULL; ++ } ++ } ++ ++ of_node_put(np); ++} ++ ++static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) ++{ ++ struct device *cpu_dev; ++ struct regulator *proc_reg = ERR_PTR(-ENODEV); ++ struct clk *cpu_clk = ERR_PTR(-ENODEV); ++ struct clk *inter_clk = ERR_PTR(-ENODEV); ++ struct dev_pm_opp *opp; ++ unsigned long rate; ++ int ret; ++ ++ cpu_dev = get_cpu_device(cpu); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu%d device\n", cpu); ++ return -ENODEV; ++ } ++ ++ cpu_clk = clk_get(cpu_dev, "cpu"); ++ if (IS_ERR(cpu_clk)) { ++ if (PTR_ERR(cpu_clk) == -EPROBE_DEFER) ++ pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu); ++ else ++ pr_err("failed to get cpu clk for cpu%d\n", cpu); ++ ++ ret = PTR_ERR(cpu_clk); ++ return ret; ++ } ++ ++ inter_clk = clk_get(cpu_dev, "intermediate"); ++ if (IS_ERR(inter_clk)) { ++ if (PTR_ERR(inter_clk) == -EPROBE_DEFER) ++ pr_warn("intermediate clk for cpu%d not ready, retry.\n", ++ cpu); ++ else ++ pr_err("failed to get intermediate clk for cpu%d\n", ++ cpu); ++ ++ ret = PTR_ERR(inter_clk); ++ goto out_free_resources; ++ } ++ ++ proc_reg = regulator_get_exclusive(cpu_dev, "proc"); ++ if (IS_ERR(proc_reg)) { ++ if (PTR_ERR(proc_reg) == -EPROBE_DEFER) ++ pr_warn("proc regulator for cpu%d not ready, retry.\n", ++ cpu); ++ else ++ pr_err("failed to get proc regulator for cpu%d\n", ++ cpu); ++ ++ ret = PTR_ERR(proc_reg); ++ goto out_free_resources; ++ } ++ ++ ret = dev_pm_opp_of_add_table(cpu_dev); ++ if (ret) { ++ pr_warn("no OPP table for cpu%d\n", cpu); ++ goto out_free_resources; ++ } ++ ++ /* Search a safe voltage for intermediate frequency. */ ++ rate = clk_get_rate(inter_clk); ++ rcu_read_lock(); ++ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); ++ if (IS_ERR(opp)) { ++ rcu_read_unlock(); ++ pr_err("failed to get intermediate opp for cpu%d\n", cpu); ++ ret = PTR_ERR(opp); ++ goto out_free_opp_table; ++ } ++ info->intermediate_voltage = dev_pm_opp_get_voltage(opp); ++ rcu_read_unlock(); ++ ++ info->cpu_dev = cpu_dev; ++ info->proc_reg = proc_reg; ++ info->cpu_clk = cpu_clk; ++ info->inter_clk = inter_clk; ++ ++ return 0; ++ ++out_free_opp_table: ++ dev_pm_opp_of_remove_table(cpu_dev); ++ ++out_free_resources: ++ if (!IS_ERR(proc_reg)) ++ regulator_put(proc_reg); ++ if (!IS_ERR(cpu_clk)) ++ clk_put(cpu_clk); ++ if (!IS_ERR(inter_clk)) ++ clk_put(inter_clk); ++ ++ return ret; ++} ++ ++static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) ++{ ++ if (!IS_ERR(info->proc_reg)) ++ regulator_put(info->proc_reg); ++ if (!IS_ERR(info->cpu_clk)) ++ clk_put(info->cpu_clk); ++ if (!IS_ERR(info->inter_clk)) ++ clk_put(info->inter_clk); ++ ++ dev_pm_opp_of_remove_table(info->cpu_dev); ++} ++ ++static int mtk_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ struct mtk_cpu_dvfs_info *info; ++ struct cpufreq_frequency_table *freq_table; ++ int ret; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ ret = mtk_cpu_dvfs_info_init(info, policy->cpu); ++ if (ret) { ++ pr_err("%s failed to initialize dvfs info for cpu%d\n", ++ __func__, policy->cpu); ++ goto out_free_dvfs_info; ++ } ++ ++ ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); ++ if (ret) { ++ pr_err("failed to init cpufreq table for cpu%d: %d\n", ++ policy->cpu, ret); ++ goto out_release_dvfs_info; ++ } ++ ++ ret = cpufreq_table_validate_and_show(policy, freq_table); ++ if (ret) { ++ pr_err("%s: invalid frequency table: %d\n", __func__, ret); ++ goto out_free_cpufreq_table; ++ } ++ ++ /* CPUs in the same cluster share a clock and power domain. */ ++ cpumask_setall(policy->cpus); ++ policy->driver_data = info; ++ policy->clk = info->cpu_clk; ++ ++ return 0; ++ ++out_free_cpufreq_table: ++ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); ++ ++out_release_dvfs_info: ++ mtk_cpu_dvfs_info_release(info); ++ ++out_free_dvfs_info: ++ kfree(info); ++ ++ return ret; ++} ++ ++static int mtk_cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ struct mtk_cpu_dvfs_info *info = policy->driver_data; ++ ++ cpufreq_cooling_unregister(info->cdev); ++ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); ++ mtk_cpu_dvfs_info_release(info); ++ kfree(info); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver mt7623_cpufreq_driver = { ++ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = mtk_cpufreq_set_target, ++ .get = cpufreq_generic_get, ++ .init = mtk_cpufreq_init, ++ .exit = mtk_cpufreq_exit, ++ .ready = mtk_cpufreq_ready, ++ .name = "mtk-cpufreq", ++ .attr = cpufreq_generic_attr, ++}; ++ ++static int mt7623_cpufreq_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ ret = cpufreq_register_driver(&mt7623_cpufreq_driver); ++ if (ret) ++ pr_err("failed to register mtk cpufreq driver\n"); ++ ++ return ret; ++} ++ ++static struct platform_driver mt7623_cpufreq_platdrv = { ++ .driver = { ++ .name = "mt7623-cpufreq", ++ }, ++ .probe = mt7623_cpufreq_probe, ++}; ++ ++static int mt7623_cpufreq_driver_init(void) ++{ ++ struct platform_device *pdev; ++ int err; ++ ++ if (!of_machine_is_compatible("mediatek,mt7623")) ++ return -ENODEV; ++ ++ err = platform_driver_register(&mt7623_cpufreq_platdrv); ++ if (err) ++ return err; ++ ++ /* ++ * Since there's no place to hold device registration code and no ++ * device tree based way to match cpufreq driver yet, both the driver ++ * and the device registration codes are put here to handle defer ++ * probing. ++ */ ++ pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0); ++ if (IS_ERR(pdev)) { ++ pr_err("failed to register mtk-cpufreq platform device\n"); ++ return PTR_ERR(pdev); ++ } ++ ++ return 0; ++} ++device_initcall(mt7623_cpufreq_driver_init); diff --git a/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch deleted file mode 100644 index 51471496a8..0000000000 --- a/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch +++ /dev/null @@ -1,194 +0,0 @@ -From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001 -From: Shunli Wang -Date: Thu, 20 Oct 2016 16:56:38 +0800 -Subject: [PATCH 2/2] soc: mediatek: Add MT2701 scpsys driver - -Add scpsys driver for MT2701. - -mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should -be enabled on both arm64 and arm platforms. - -Signed-off-by: Shunli Wang -Signed-off-by: James Liao -Reviewed-by: Kevin Hilman -Signed-off-by: Matthias Brugger ---- - drivers/soc/mediatek/Kconfig | 2 +- - drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++- - 2 files changed, 117 insertions(+), 2 deletions(-) - ---- a/drivers/soc/mediatek/Kconfig -+++ b/drivers/soc/mediatek/Kconfig -@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP - config MTK_SCPSYS - bool "MediaTek SCPSYS Support" - depends on ARCH_MEDIATEK || COMPILE_TEST -- default ARM64 && ARCH_MEDIATEK -+ default ARCH_MEDIATEK - select REGMAP - select MTK_INFRACFG - select PM_GENERIC_DOMAINS if PM ---- a/drivers/soc/mediatek/mtk-scpsys.c -+++ b/drivers/soc/mediatek/mtk-scpsys.c -@@ -20,6 +20,7 @@ - #include - #include - -+#include - #include - - #define SPM_VDE_PWR_CON 0x0210 -@@ -27,8 +28,13 @@ - #define SPM_VEN_PWR_CON 0x0230 - #define SPM_ISP_PWR_CON 0x0238 - #define SPM_DIS_PWR_CON 0x023c -+#define SPM_CONN_PWR_CON 0x0280 - #define SPM_VEN2_PWR_CON 0x0298 --#define SPM_AUDIO_PWR_CON 0x029c -+#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ -+#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ -+#define SPM_ETH_PWR_CON 0x02a0 -+#define SPM_HIF_PWR_CON 0x02a4 -+#define SPM_IFR_MSC_PWR_CON 0x02a8 - #define SPM_MFG_2D_PWR_CON 0x02c0 - #define SPM_MFG_ASYNC_PWR_CON 0x02c4 - #define SPM_USB_PWR_CON 0x02cc -@@ -42,10 +48,15 @@ - #define PWR_ON_2ND_BIT BIT(3) - #define PWR_CLK_DIS_BIT BIT(4) - -+#define PWR_STATUS_CONN BIT(1) - #define PWR_STATUS_DISP BIT(3) - #define PWR_STATUS_MFG BIT(4) - #define PWR_STATUS_ISP BIT(5) - #define PWR_STATUS_VDEC BIT(7) -+#define PWR_STATUS_BDP BIT(14) -+#define PWR_STATUS_ETH BIT(15) -+#define PWR_STATUS_HIF BIT(16) -+#define PWR_STATUS_IFR_MSC BIT(17) - #define PWR_STATUS_VENC_LT BIT(20) - #define PWR_STATUS_VENC BIT(21) - #define PWR_STATUS_MFG_2D BIT(22) -@@ -59,6 +70,7 @@ enum clk_id { - CLK_MFG, - CLK_VENC, - CLK_VENC_LT, -+ CLK_ETHIF, - CLK_MAX, - }; - -@@ -68,6 +80,7 @@ static const char * const clk_names[] = - "mfg", - "venc", - "venc_lt", -+ "ethif", - NULL, - }; - -@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s - } - - /* -+ * MT2701 power domain support -+ */ -+ -+static const struct scp_domain_data scp_domain_data_mt2701[] = { -+ [MT2701_POWER_DOMAIN_CONN] = { -+ .name = "conn", -+ .sta_mask = PWR_STATUS_CONN, -+ .ctl_offs = SPM_CONN_PWR_CON, -+ .bus_prot_mask = 0x0104, -+ .clk_id = {CLK_NONE}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_DISP] = { -+ .name = "disp", -+ .sta_mask = PWR_STATUS_DISP, -+ .ctl_offs = SPM_DIS_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .clk_id = {CLK_MM}, -+ .bus_prot_mask = 0x0002, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_VDEC] = { -+ .name = "vdec", -+ .sta_mask = PWR_STATUS_VDEC, -+ .ctl_offs = SPM_VDE_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(12, 12), -+ .clk_id = {CLK_MM}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_ISP] = { -+ .name = "isp", -+ .sta_mask = PWR_STATUS_ISP, -+ .ctl_offs = SPM_ISP_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(13, 12), -+ .clk_id = {CLK_MM}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_BDP] = { -+ .name = "bdp", -+ .sta_mask = PWR_STATUS_BDP, -+ .ctl_offs = SPM_BDP_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .clk_id = {CLK_NONE}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_ETH] = { -+ .name = "eth", -+ .sta_mask = PWR_STATUS_ETH, -+ .ctl_offs = SPM_ETH_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_ETHIF}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_HIF] = { -+ .name = "hif", -+ .sta_mask = PWR_STATUS_HIF, -+ .ctl_offs = SPM_HIF_PWR_CON, -+ .sram_pdn_bits = GENMASK(11, 8), -+ .sram_pdn_ack_bits = GENMASK(15, 12), -+ .clk_id = {CLK_ETHIF}, -+ .active_wakeup = true, -+ }, -+ [MT2701_POWER_DOMAIN_IFR_MSC] = { -+ .name = "ifr_msc", -+ .sta_mask = PWR_STATUS_IFR_MSC, -+ .ctl_offs = SPM_IFR_MSC_PWR_CON, -+ .clk_id = {CLK_NONE}, -+ .active_wakeup = true, -+ }, -+}; -+ -+#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701) -+ -+static int __init scpsys_probe_mt2701(struct platform_device *pdev) -+{ -+ struct scp *scp; -+ -+ scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701); -+ if (IS_ERR(scp)) -+ return PTR_ERR(scp); -+ -+ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701); -+ -+ return 0; -+} -+ -+/* - * MT8173 power domain support - */ - -@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st - - static const struct of_device_id of_scpsys_match_tbl[] = { - { -+ .compatible = "mediatek,mt2701-scpsys", -+ .data = scpsys_probe_mt2701, -+ }, { - .compatible = "mediatek,mt8173-scpsys", - .data = scpsys_probe_mt8173, - }, { diff --git a/target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch new file mode 100644 index 0000000000..2e8414ea20 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0016-pwm-add-pwm-mediatek.patch @@ -0,0 +1,274 @@ +From 201be68268eddb1568c41780a62868cc1666a2de Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 6 May 2016 02:55:48 +0200 +Subject: [PATCH 16/57] pwm: add pwm-mediatek + +Signed-off-by: John Crispin +--- + drivers/pwm/Kconfig | 9 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/pwm-mediatek.c | 230 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 240 insertions(+) + create mode 100644 drivers/pwm/pwm-mediatek.c + +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -282,6 +282,15 @@ config PWM_MTK_DISP + To compile this driver as a module, choose M here: the module + will be called pwm-mtk-disp. + ++config PWM_MEDIATEK ++ tristate "MediaTek PWM support" ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ help ++ Generic PWM framework driver for Mediatek ARM SoC. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called pwm-mxs. ++ + config PWM_MXS + tristate "Freescale MXS PWM support" + depends on ARCH_MXS && OF +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o + obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o + obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o + obj-$(CONFIG_PWM_MESON) += pwm-meson.o ++obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o + obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o + obj-$(CONFIG_PWM_MXS) += pwm-mxs.o + obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o +--- /dev/null ++++ b/drivers/pwm/pwm-mediatek.c +@@ -0,0 +1,230 @@ ++/* ++ * Mediatek Pulse Width Modulator driver ++ * ++ * Copyright (C) 2015 John Crispin ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NUM_PWM 5 ++ ++/* PWM registers and bits definitions */ ++#define PWMCON 0x00 ++#define PWMHDUR 0x04 ++#define PWMLDUR 0x08 ++#define PWMGDUR 0x0c ++#define PWMWAVENUM 0x28 ++#define PWMDWIDTH 0x2c ++#define PWMTHRES 0x30 ++ ++/** ++ * struct mtk_pwm_chip - struct representing pwm chip ++ * ++ * @mmio_base: base address of pwm chip ++ * @chip: linux pwm chip representation ++ */ ++struct mtk_pwm_chip { ++ void __iomem *mmio_base; ++ struct pwm_chip chip; ++ struct clk *clk_top; ++ struct clk *clk_main; ++ struct clk *clk_pwm[NUM_PWM]; ++}; ++ ++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) ++{ ++ return container_of(chip, struct mtk_pwm_chip, chip); ++} ++ ++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, ++ unsigned long offset) ++{ ++ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset); ++} ++ ++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, ++ unsigned int num, unsigned long offset, ++ unsigned long val) ++{ ++ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset); ++} ++ ++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ++ int duty_ns, int period_ns) ++{ ++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); ++ u32 resolution = 100 / 4; ++ u32 clkdiv = 0; ++ ++ resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm])); ++ ++ while (period_ns / resolution > 8191) { ++ clkdiv++; ++ resolution *= 2; ++ } ++ ++ if (clkdiv > 7) ++ return -1; ++ ++ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv); ++ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); ++ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); ++ return 0; ++} ++ ++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); ++ u32 val; ++ int ret; ++ ++ ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]); ++ if (ret < 0) ++ return ret; ++ ++ val = ioread32(pc->mmio_base); ++ val |= BIT(pwm->hwpwm); ++ iowrite32(val, pc->mmio_base); ++ ++ return 0; ++} ++ ++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ++{ ++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); ++ u32 val; ++ ++ val = ioread32(pc->mmio_base); ++ val &= ~BIT(pwm->hwpwm); ++ iowrite32(val, pc->mmio_base); ++ clk_unprepare(pc->clk_pwm[pwm->hwpwm]); ++} ++ ++static const struct pwm_ops mtk_pwm_ops = { ++ .config = mtk_pwm_config, ++ .enable = mtk_pwm_enable, ++ .disable = mtk_pwm_disable, ++ .owner = THIS_MODULE, ++}; ++ ++static int mtk_pwm_probe(struct platform_device *pdev) ++{ ++ struct mtk_pwm_chip *pc; ++ struct resource *r; ++ int ret; ++ ++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); ++ if (!pc) ++ return -ENOMEM; ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); ++ if (IS_ERR(pc->mmio_base)) ++ return PTR_ERR(pc->mmio_base); ++ ++ pc->clk_main = devm_clk_get(&pdev->dev, "main"); ++ if (IS_ERR(pc->clk_main)) ++ return PTR_ERR(pc->clk_main); ++ ++ pc->clk_top = devm_clk_get(&pdev->dev, "top"); ++ if (IS_ERR(pc->clk_top)) ++ return PTR_ERR(pc->clk_top); ++ ++ pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1"); ++ if (IS_ERR(pc->clk_pwm[0])) ++ return PTR_ERR(pc->clk_pwm[0]); ++ ++ pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2"); ++ if (IS_ERR(pc->clk_pwm[1])) ++ return PTR_ERR(pc->clk_pwm[1]); ++ ++ pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3"); ++ if (IS_ERR(pc->clk_pwm[2])) ++ return PTR_ERR(pc->clk_pwm[2]); ++ ++ pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4"); ++ if (IS_ERR(pc->clk_pwm[3])) ++ return PTR_ERR(pc->clk_pwm[3]); ++ ++ pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5"); ++ if (IS_ERR(pc->clk_pwm[4])) ++ return PTR_ERR(pc->clk_pwm[4]); ++ ++ ret = clk_prepare(pc->clk_top); ++ if (ret < 0) ++ return ret; ++ ++ ret = clk_prepare(pc->clk_main); ++ if (ret < 0) ++ goto disable_clk_top; ++ ++ platform_set_drvdata(pdev, pc); ++ ++ pc->chip.dev = &pdev->dev; ++ pc->chip.ops = &mtk_pwm_ops; ++ pc->chip.base = -1; ++ pc->chip.npwm = NUM_PWM; ++ ++ ret = pwmchip_add(&pc->chip); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); ++ goto disable_clk_main; ++ } ++ ++ return 0; ++ ++disable_clk_main: ++ clk_unprepare(pc->clk_main); ++disable_clk_top: ++ clk_unprepare(pc->clk_top); ++ ++ return ret; ++} ++ ++static int mtk_pwm_remove(struct platform_device *pdev) ++{ ++ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); ++ int i; ++ ++ for (i = 0; i < NUM_PWM; i++) ++ pwm_disable(&pc->chip.pwms[i]); ++ ++ return pwmchip_remove(&pc->chip); ++} ++ ++static const struct of_device_id mtk_pwm_of_match[] = { ++ { .compatible = "mediatek,mt7623-pwm" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); ++ ++static struct platform_driver mtk_pwm_driver = { ++ .driver = { ++ .name = "mtk-pwm", ++ .owner = THIS_MODULE, ++ .of_match_table = mtk_pwm_of_match, ++ }, ++ .probe = mtk_pwm_probe, ++ .remove = mtk_pwm_remove, ++}; ++ ++module_platform_driver(mtk_pwm_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin "); ++MODULE_ALIAS("platform:mtk-pwm"); diff --git a/target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch deleted file mode 100644 index 86d9f451dd..0000000000 --- a/target/linux/mediatek/patches-4.9/0017-clk-add-hifsys-reset.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f7121d2b19ddad33a09408a2c5923bfd95da8533 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Wed, 6 Jan 2016 20:06:49 +0100 -Subject: [PATCH 017/102] clk: add hifsys reset - -Hi, - -small patch to add hifsys reset bits. Maybe you could add it to the next -version of your patch series. i have teste scpsys and clk on mt7623 today -and it works well. - -thanks, - John - -Signed-off-by: John Crispin ---- - drivers/clk/mediatek/clk-mt2701.c | 2 ++ - include/dt-bindings/reset-controller/mt2701-resets.h | 9 +++++++++ - 2 files changed, 11 insertions(+) - ---- a/drivers/clk/mediatek/clk-mt2701.c -+++ b/drivers/clk/mediatek/clk-mt2701.c -@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_register_reset_controller(node, 1, 0x34); - } - CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init); - diff --git a/target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch b/target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch new file mode 100644 index 0000000000..73ac0eead2 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0017-mfd-mt6397-Add-MT6323-LED-support-into-MT6397-driver.patch @@ -0,0 +1,27 @@ +From 2b866d69f6198701457d29c5886c0ad7865c785f Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Sat, 25 Feb 2017 02:47:21 +0800 +Subject: [PATCH 17/57] mfd: mt6397: Add MT6323 LED support into MT6397 driver + +Add compatible string as "mt6323-led" that will make +the OF core spawn child devices for the LED subnode +of that MT6323 MFD device. + +Signed-off-by: Sean Wang +--- + drivers/mfd/mt6397-core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs + .name = "mt6323-regulator", + .of_compatible = "mediatek,mt6323-regulator" + }, ++ { ++ .name = "mt6323-led", ++ .of_compatible = "mediatek,mt6323-led" ++ }, + }; + + static const struct mfd_cell mt6397_devs[] = { diff --git a/target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch b/target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch new file mode 100644 index 0000000000..ca0ee0443a --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0018-dt-bindings-leds-Add-document-bindings-for-leds-mt63.patch @@ -0,0 +1,78 @@ +From 424ca23e68b043ce26d6981839ca825ef8637aba Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Mon, 20 Mar 2017 14:47:24 +0800 +Subject: [PATCH 18/57] dt-bindings: leds: Add document bindings for + leds-mt6323 + +This patch adds documentation for devicetree bindings for LED support on +MT6323 PMIC. + +Signed-off-by: Sean Wang +--- + .../devicetree/bindings/leds/leds-mt6323.txt | 60 ++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt +@@ -0,0 +1,60 @@ ++Device Tree Bindings for LED support on MT6323 PMIC ++ ++MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED ++controllers are defined as the subnode of the function node provided by MT6323 ++PMIC controller that is being defined as one kind of Muti-Function Device (MFD) ++using shared bus called PMIC wrapper for each subfunction to access remote ++MT6323 PMIC hardware. ++ ++For MT6323 MFD bindings see: ++Documentation/devicetree/bindings/mfd/mt6397.txt ++For MediaTek PMIC wrapper bindings see: ++Documentation/devicetree/bindings/soc/mediatek/pwrap.txt ++ ++Required properties: ++- compatible : Must be "mediatek,mt6323-led" ++- address-cells : Must be 1 ++- size-cells : Must be 0 ++ ++Each led is represented as a child node of the mediatek,mt6323-led that ++describes the initial behavior for each LED physically and currently only four ++LED child nodes can be supported. ++ ++Required properties for the LED child node: ++- reg : LED channel number (0..3) ++ ++Optional properties for the LED child node: ++- label : See Documentation/devicetree/bindings/leds/common.txt ++- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt ++- default-state: See Documentation/devicetree/bindings/leds/common.txt ++ ++Example: ++ ++ mt6323: pmic { ++ compatible = "mediatek,mt6323"; ++ ++ ... ++ ++ mt6323led: leds { ++ compatible = "mediatek,mt6323-led"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ label = "LED0"; ++ linux,default-trigger = "timer"; ++ default-state = "on"; ++ }; ++ led@1 { ++ reg = <1>; ++ label = "LED1"; ++ default-state = "off"; ++ }; ++ led@2 { ++ reg = <2>; ++ label = "LED2"; ++ default-state = "on"; ++ }; ++ }; ++ }; diff --git a/target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch b/target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch new file mode 100644 index 0000000000..c8afdc0888 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0019-dt-bindings-mfd-Add-the-description-for-LED-as-the-s.patch @@ -0,0 +1,24 @@ +From 7c137e4b83f32a67ccf6b39fa455aca71980a21f Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Mon, 20 Mar 2017 14:47:25 +0800 +Subject: [PATCH 19/57] dt-bindings: mfd: Add the description for LED as the + sub module + +This patch adds description for LED as the sub-module on MT6397/MT6323 +multifunction device. + +Signed-off-by: Sean Wang +--- + Documentation/devicetree/bindings/mfd/mt6397.txt | 1 + + 1 file changed, 1 insertion(+) + +--- a/Documentation/devicetree/bindings/mfd/mt6397.txt ++++ b/Documentation/devicetree/bindings/mfd/mt6397.txt +@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device + - Audio codec + - GPIO + - Clock ++- LED + + It is interfaced to host controller using SPI interface by a proprietary hardware + called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap. diff --git a/target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch b/target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch new file mode 100644 index 0000000000..37b926de18 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0020-leds-Add-LED-support-for-MT6323-PMIC.patch @@ -0,0 +1,539 @@ +From e482f9590f2e831c68bcf85e3f9f4c88bbd3329f Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Mon, 20 Mar 2017 14:47:26 +0800 +Subject: [PATCH 20/57] leds: Add LED support for MT6323 PMIC + +MT6323 PMIC is a multi-function device that includes LED function. +It allows attaching up to 4 LEDs which can either be on, off or dimmed +and/or blinked with the controller. + +Signed-off-by: Sean Wang +Reviewed-by: Jacek Anaszewski +--- + drivers/leds/Kconfig | 8 + + drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 510 insertions(+) + create mode 100644 drivers/leds/leds-mt6323.c + +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532 + This option enables support for the so called "User LED" of + Mikrotik's Routerboard 532. + ++config LEDS_MT6323 ++ tristate "LED Support for Mediatek MT6323 PMIC" ++ depends on LEDS_CLASS ++ depends on MFD_MT6397 ++ help ++ This option enables support for on-chip LED drivers found on ++ Mediatek MT6323 PMIC. ++ + config LEDS_S3C24XX + tristate "LED Support for Samsung S3C24XX GPIO LEDs" + depends on LEDS_CLASS +--- /dev/null ++++ b/drivers/leds/leds-mt6323.c +@@ -0,0 +1,502 @@ ++/* ++ * LED driver for Mediatek MT6323 PMIC ++ * ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Register field for MT6323_TOP_CKPDN0 to enable ++ * 32K clock common for LED device. ++ */ ++#define MT6323_RG_DRV_32K_CK_PDN BIT(11) ++#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11) ++ ++/* ++ * Register field for MT6323_TOP_CKPDN2 to enable ++ * individual clock for LED device. ++ */ ++#define MT6323_RG_ISINK_CK_PDN(i) BIT(i) ++#define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i) ++ ++/* ++ * Register field for MT6323_TOP_CKCON1 to select ++ * clock source. ++ */ ++#define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) ++ ++/* ++ * Register for MT6323_ISINK_CON0 to setup the ++ * duty cycle of the blink. ++ */ ++#define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i)) ++#define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8) ++#define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \ ++ MT6323_ISINK_DIM_DUTY_MASK) ++ ++/* Register to setup the period of the blink. */ ++#define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i)) ++#define MT6323_ISINK_DIM_FSEL_MASK (0xffff) ++#define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK) ++ ++/* Register to control the brightness. */ ++#define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i)) ++#define MT6323_ISINK_CH_STEP_SHIFT 12 ++#define MT6323_ISINK_CH_STEP_MASK (0x7 << 12) ++#define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \ ++ MT6323_ISINK_CH_STEP_MASK) ++#define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1) ++#define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \ ++ MT6323_ISINK_SFSTR0_TC_MASK) ++#define MT6323_ISINK_SFSTR0_EN_MASK BIT(0) ++#define MT6323_ISINK_SFSTR0_EN BIT(0) ++ ++/* Register to LED channel enablement. */ ++#define MT6323_ISINK_CH_EN_MASK(i) BIT(i) ++#define MT6323_ISINK_CH_EN(i) BIT(i) ++ ++#define MT6323_MAX_PERIOD 10000 ++#define MT6323_MAX_LEDS 4 ++#define MT6323_MAX_BRIGHTNESS 6 ++#define MT6323_UNIT_DUTY 3125 ++#define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\ ++ (p) * MT6323_UNIT_DUTY) ++ ++struct mt6323_leds; ++ ++/** ++ * struct mt6323_led - state container for the LED device ++ * @id: the identifier in MT6323 LED device ++ * @parent: the pointer to MT6323 LED controller ++ * @cdev: LED class device for this LED device ++ * @current_brightness: current state of the LED device ++ */ ++struct mt6323_led { ++ int id; ++ struct mt6323_leds *parent; ++ struct led_classdev cdev; ++ enum led_brightness current_brightness; ++}; ++ ++/** ++ * struct mt6323_leds - state container for holding LED controller ++ * of the driver ++ * @dev: the device pointer ++ * @hw: the underlying hardware providing shared ++ * bus for the register operations ++ * @lock: the lock among process context ++ * @led: the array that contains the state of individual ++ * LED device ++ */ ++struct mt6323_leds { ++ struct device *dev; ++ struct mt6397_chip *hw; ++ /* protect among process context */ ++ struct mutex lock; ++ struct mt6323_led *led[MT6323_MAX_LEDS]; ++}; ++ ++static int mt6323_led_hw_brightness(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ u32 con2_mask = 0, con2_val = 0; ++ int ret; ++ ++ /* ++ * Setup current output for the corresponding ++ * brightness level. ++ */ ++ con2_mask |= MT6323_ISINK_CH_STEP_MASK | ++ MT6323_ISINK_SFSTR0_TC_MASK | ++ MT6323_ISINK_SFSTR0_EN_MASK; ++ con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) | ++ MT6323_ISINK_SFSTR0_TC(2) | ++ MT6323_ISINK_SFSTR0_EN; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id), ++ con2_mask, con2_val); ++ return ret; ++} ++ ++static int mt6323_led_hw_off(struct led_classdev *cdev) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ status = MT6323_ISINK_CH_EN(led->id); ++ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, ++ MT6323_ISINK_CH_EN_MASK(led->id), ~status); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(100, 300); ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, ++ MT6323_RG_ISINK_CK_PDN_MASK(led->id), ++ MT6323_RG_ISINK_CK_PDN(led->id)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static enum led_brightness ++mt6323_get_led_hw_brightness(struct led_classdev *cdev) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status); ++ if (ret < 0) ++ return ret; ++ ++ if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id)) ++ return 0; ++ ++ ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status); ++ if (ret < 0) ++ return ret; ++ ++ if (!(status & MT6323_ISINK_CH_EN(led->id))) ++ return 0; ++ ++ ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status); ++ if (ret < 0) ++ return ret; ++ ++ return ((status & MT6323_ISINK_CH_STEP_MASK) ++ >> MT6323_ISINK_CH_STEP_SHIFT) + 1; ++} ++ ++static int mt6323_led_hw_on(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ /* ++ * Setup required clock source, enable the corresponding ++ * clock and channel and let work with continuous blink as ++ * the default. ++ */ ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1, ++ MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0); ++ if (ret < 0) ++ return ret; ++ ++ status = MT6323_RG_ISINK_CK_PDN(led->id); ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, ++ MT6323_RG_ISINK_CK_PDN_MASK(led->id), ++ ~status); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(100, 300); ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, ++ MT6323_ISINK_CH_EN_MASK(led->id), ++ MT6323_ISINK_CH_EN(led->id)); ++ if (ret < 0) ++ return ret; ++ ++ ret = mt6323_led_hw_brightness(cdev, brightness); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), ++ MT6323_ISINK_DIM_DUTY_MASK, ++ MT6323_ISINK_DIM_DUTY(31)); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), ++ MT6323_ISINK_DIM_FSEL_MASK, ++ MT6323_ISINK_DIM_FSEL(1000)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int mt6323_led_set_blink(struct led_classdev *cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned long period; ++ u8 duty_hw; ++ int ret; ++ ++ /* ++ * Units are in ms, if over the hardware able ++ * to support, fallback into software blink ++ */ ++ period = *delay_on + *delay_off; ++ ++ if (period > MT6323_MAX_PERIOD) ++ return -EINVAL; ++ ++ /* ++ * LED subsystem requires a default user ++ * friendly blink pattern for the LED so using ++ * 1Hz duty cycle 50% here if without specific ++ * value delay_on and delay off being assigned. ++ */ ++ if (!*delay_on && !*delay_off) { ++ *delay_on = 500; ++ *delay_off = 500; ++ } ++ ++ /* ++ * Calculate duty_hw based on the percentage of period during ++ * which the led is ON. ++ */ ++ duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); ++ ++ /* hardware doesn't support zero duty cycle. */ ++ if (!duty_hw) ++ return -EINVAL; ++ ++ mutex_lock(&leds->lock); ++ /* ++ * Set max_brightness as the software blink behavior ++ * when no blink brightness. ++ */ ++ if (!led->current_brightness) { ++ ret = mt6323_led_hw_on(cdev, cdev->max_brightness); ++ if (ret < 0) ++ goto out; ++ led->current_brightness = cdev->max_brightness; ++ } ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), ++ MT6323_ISINK_DIM_DUTY_MASK, ++ MT6323_ISINK_DIM_DUTY(duty_hw - 1)); ++ if (ret < 0) ++ goto out; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), ++ MT6323_ISINK_DIM_FSEL_MASK, ++ MT6323_ISINK_DIM_FSEL(period - 1)); ++out: ++ mutex_unlock(&leds->lock); ++ ++ return ret; ++} ++ ++static int mt6323_led_set_brightness(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ int ret; ++ ++ mutex_lock(&leds->lock); ++ ++ if (!led->current_brightness && brightness) { ++ ret = mt6323_led_hw_on(cdev, brightness); ++ if (ret < 0) ++ goto out; ++ } else if (brightness) { ++ ret = mt6323_led_hw_brightness(cdev, brightness); ++ if (ret < 0) ++ goto out; ++ } else { ++ ret = mt6323_led_hw_off(cdev); ++ if (ret < 0) ++ goto out; ++ } ++ ++ led->current_brightness = brightness; ++out: ++ mutex_unlock(&leds->lock); ++ ++ return ret; ++} ++ ++static int mt6323_led_set_dt_default(struct led_classdev *cdev, ++ struct device_node *np) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ const char *state; ++ int ret = 0; ++ ++ led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; ++ led->cdev.default_trigger = of_get_property(np, ++ "linux,default-trigger", ++ NULL); ++ ++ state = of_get_property(np, "default-state", NULL); ++ if (state) { ++ if (!strcmp(state, "keep")) { ++ ret = mt6323_get_led_hw_brightness(cdev); ++ if (ret < 0) ++ return ret; ++ led->current_brightness = ret; ++ ret = 0; ++ } else if (!strcmp(state, "on")) { ++ ret = ++ mt6323_led_set_brightness(cdev, cdev->max_brightness); ++ } else { ++ ret = mt6323_led_set_brightness(cdev, LED_OFF); ++ } ++ } ++ ++ return ret; ++} ++ ++static int mt6323_led_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *child; ++ struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); ++ struct mt6323_leds *leds; ++ struct mt6323_led *led; ++ int ret; ++ unsigned int status; ++ u32 reg; ++ ++ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, leds); ++ leds->dev = dev; ++ ++ /* ++ * leds->hw points to the underlying bus for the register ++ * controlled. ++ */ ++ leds->hw = hw; ++ mutex_init(&leds->lock); ++ ++ status = MT6323_RG_DRV_32K_CK_PDN; ++ ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, ++ MT6323_RG_DRV_32K_CK_PDN_MASK, ~status); ++ if (ret < 0) { ++ dev_err(leds->dev, ++ "Failed to update MT6323_TOP_CKPDN0 Register\n"); ++ return ret; ++ } ++ ++ for_each_available_child_of_node(np, child) { ++ ret = of_property_read_u32(child, "reg", ®); ++ if (ret) { ++ dev_err(dev, "Failed to read led 'reg' property\n"); ++ goto put_child_node; ++ } ++ ++ if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) { ++ dev_err(dev, "Invalid led reg %u\n", reg); ++ ret = -EINVAL; ++ goto put_child_node; ++ } ++ ++ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); ++ if (!led) { ++ ret = -ENOMEM; ++ goto put_child_node; ++ } ++ ++ leds->led[reg] = led; ++ leds->led[reg]->id = reg; ++ leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS; ++ leds->led[reg]->cdev.brightness_set_blocking = ++ mt6323_led_set_brightness; ++ leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; ++ leds->led[reg]->cdev.brightness_get = ++ mt6323_get_led_hw_brightness; ++ leds->led[reg]->parent = leds; ++ ++ ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child); ++ if (ret < 0) { ++ dev_err(leds->dev, ++ "Failed to LED set default from devicetree\n"); ++ goto put_child_node; ++ } ++ ++ ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register LED: %d\n", ++ ret); ++ goto put_child_node; ++ } ++ leds->led[reg]->cdev.dev->of_node = child; ++ } ++ ++ return 0; ++ ++put_child_node: ++ of_node_put(child); ++ return ret; ++} ++ ++static int mt6323_led_remove(struct platform_device *pdev) ++{ ++ struct mt6323_leds *leds = platform_get_drvdata(pdev); ++ int i; ++ ++ /* Turn the LEDs off on driver removal. */ ++ for (i = 0 ; leds->led[i] ; i++) ++ mt6323_led_hw_off(&leds->led[i]->cdev); ++ ++ regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, ++ MT6323_RG_DRV_32K_CK_PDN_MASK, ++ MT6323_RG_DRV_32K_CK_PDN); ++ ++ mutex_destroy(&leds->lock); ++ ++ return 0; ++} ++ ++static const struct of_device_id mt6323_led_dt_match[] = { ++ { .compatible = "mediatek,mt6323-led" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt6323_led_dt_match); ++ ++static struct platform_driver mt6323_led_driver = { ++ .probe = mt6323_led_probe, ++ .remove = mt6323_led_remove, ++ .driver = { ++ .name = "mt6323-led", ++ .of_match_table = mt6323_led_dt_match, ++ }, ++}; ++ ++module_platform_driver(mt6323_led_driver); ++ ++MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch b/target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch new file mode 100644 index 0000000000..79e11e8c69 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0021-mfd-mt6397-Align-the-placement-at-which-the-mfd_cell.patch @@ -0,0 +1,27 @@ +From 6e81b4fee93c004078465589128ba07b6855be02 Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Mon, 20 Mar 2017 14:47:27 +0800 +Subject: [PATCH 21/57] mfd: mt6397: Align the placement at which the mfd_cell + of LED is defined + +Align the placement as which the mfd_cell of LED is defined as the other +members done on the structure. + +Signed-off-by: Sean Wang +Acked-by: Lee Jones +--- + drivers/mfd/mt6397-core.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs + { + .name = "mt6323-regulator", + .of_compatible = "mediatek,mt6323-regulator" +- }, +- { ++ }, { + .name = "mt6323-led", + .of_compatible = "mediatek,mt6323-led" + }, diff --git a/target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch b/target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch new file mode 100644 index 0000000000..f01c841108 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0022-nand-make-bootrom-work-with-upstream-driver.patch @@ -0,0 +1,32 @@ +From 453ebd5d6b535388972fcea747025ced3afca5cc Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:47:06 +0200 +Subject: [PATCH 22/57] nand: make bootrom work with upstream driver + +Signed-off-by: John Crispin +--- + drivers/mtd/nand/mtk_nand.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/mtd/nand/mtk_nand.c ++++ b/drivers/mtd/nand/mtk_nand.c +@@ -1073,8 +1073,8 @@ static int mtk_nfc_ooblayout_free(struct + if (section >= eccsteps) + return -ERANGE; + +- oob_region->length = fdm->reg_size - fdm->ecc_size; +- oob_region->offset = section * fdm->reg_size + fdm->ecc_size; ++ oob_region->length = fdm->reg_size - 1; ++ oob_region->offset = section * fdm->reg_size + 1; + + return 0; + } +@@ -1114,7 +1114,7 @@ static void mtk_nfc_set_fdm(struct mtk_n + fdm->reg_size = NFI_FDM_MAX_SIZE; + + /* bad block mark storage */ +- fdm->ecc_size = 1; ++ fdm->ecc_size = fdm->reg_size; + } + + static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl, diff --git a/target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch b/target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch new file mode 100644 index 0000000000..153031b35a --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0023-rng-add-mediatek-hw-rng.patch @@ -0,0 +1,81 @@ +From 4ad0accdfb0941de1440906461c08bee715378d5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:57:44 +0200 +Subject: [PATCH 23/57] rng: add mediatek hw rng + +Signed-off-by: John Crispin +--- + drivers/char/hw_random/Kconfig | 14 ++++++++++++++ + drivers/char/hw_random/Makefile | 1 + + drivers/crypto/Kconfig | 18 ++++++++++++++++++ + drivers/crypto/Makefile | 1 + + 4 files changed, 34 insertions(+) + +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -166,6 +166,20 @@ config HW_RANDOM_IXP4XX + + If unsure, say Y. + ++config HW_RANDOM_MTK ++ tristate "Mediatek Random Number Generator support" ++ depends on HW_RANDOM ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ default y ++ ---help--- ++ This driver provides kernel-side support for the Random Number ++ Generator hardware found on Mediatek SoCs. ++ ++ To compile this driver as a module, choose M here. the ++ module will be called mtk-rng. ++ ++ If unsure, say Y. ++ + config HW_RANDOM_OMAP + tristate "OMAP Random Number Generator support" + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS +--- a/drivers/char/hw_random/Makefile ++++ b/drivers/char/hw_random/Makefile +@@ -35,4 +35,5 @@ obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-r + obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o + obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o + obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o ++obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o + obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -553,6 +553,24 @@ config CRYPTO_DEV_ROCKCHIP + This driver interfaces with the hardware crypto accelerator. + Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode. + ++config CRYPTO_DEV_MEDIATEK ++ tristate "MediaTek's EIP97 Cryptographic Engine driver" ++ depends on HAS_DMA ++ depends on (ARM && ARCH_MEDIATEK) || COMPILE_TEST ++ select CRYPTO_AES ++ select CRYPTO_AEAD ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_CTR ++ select CRYPTO_SHA1 ++ select CRYPTO_SHA256 ++ select CRYPTO_SHA512 ++ select CRYPTO_HMAC ++ help ++ This driver allows you to utilize the hardware crypto accelerator ++ EIP97 which can be found on the MT7623 MT2701, MT8521p, etc .... ++ Select this if you want to use it for AES/SHA1/SHA2 algorithms. ++ ++ + source "drivers/crypto/chelsio/Kconfig" + + endif # CRYPTO_HW +--- a/drivers/crypto/Makefile ++++ b/drivers/crypto/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += + obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o + obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o + obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/ ++obj-$(CONFIG_CRYPTO_DEV_MEDIATEK) += mediatek/ + obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o + obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o + n2_crypto-y := n2_core.o n2_asm.o diff --git a/target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch deleted file mode 100644 index d6fe977793..0000000000 --- a/target/linux/mediatek/patches-4.9/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 05be818061b9f2a0fa5ad0cde6881917ff14a2f2 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Wed, 6 Jan 2016 21:55:10 +0100 -Subject: [PATCH 024/102] dt-bindings: add MediaTek PCIe binding documentation - -Signed-off-by: John Crispin ---- - .../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 = , -+ , -+ ; -+ interrupt-names = "pcie0", "pcie1", "pcie2"; -+ clocks = <&topckgen CLK_TOP_ETHIF_SEL>; -+ clock-names = "pcie"; -+ power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>; -+ resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>, -+ <&hifsys MT2701_HIFSYS_PCIE1_RST>, -+ <&hifsys MT2701_HIFSYS_PCIE2_RST>; -+ reset-names = "pcie0", "pice1", "pcie2"; -+ -+ bus-range = <0x00 0xff>; -+ #address-cells = <3>; -+ #size-cells = <2>; -+ -+ mediatek,hifsys = <&hifsys>; -+ -+ ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* io space */ -+ 0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* pci memory */ -+ -+ status = "disabled"; -+ -+ pcie@1,0 { -+ device_type = "pci"; -+ reg = <0x0800 0 0 0 0>; -+ -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ -+ status = "disabled"; -+ }; -+ -+ pcie@2,0{ -+ device_type = "pci"; -+ reg = <0x1000 0 0 0 0>; -+ -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ -+ status = "disabled"; -+ }; -+ -+ pcie@3,0{ -+ device_type = "pci"; -+ reg = <0x1800 0 0 0 0>; -+ -+ #address-cells = <3>; -+ #size-cells = <2>; -+ ranges; -+ -+ status = "disabled"; -+ }; -+ }; -+ -+Board DTS: -+ -+ pcie-controller { -+ status = "okay"; -+ -+ pci@1,0 { -+ status = "okay"; -+ }; -+ }; diff --git a/target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch b/target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch new file mode 100644 index 0000000000..fbdfbe9041 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0024-media-rc-add-driver-for-IR-remote-receiver-on-MT7623.patch @@ -0,0 +1,1034 @@ +From 6e0336d1660725c06b6ab4f5361873538dbaa9f9 Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Fri, 13 Jan 2017 15:35:39 +0800 +Subject: [PATCH 24/57] media: rc: add driver for IR remote receiver on MT7623 + SoC + +This patch adds driver for IR controller on MT7623 SoC. +and should also work on similar Mediatek SoC. Currently +testing successfully on NEC and SONY remote controller +only but it should work on others (lirc, rc-5 and rc-6). + +Signed-off-by: Sean Wang +Reviewed-by: Sean Young +--- + drivers/media/rc/Kconfig | 11 ++ + drivers/media/rc/mtk-cir.c | 329 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 340 insertions(+) + create mode 100644 drivers/media/rc/mtk-cir.c + +--- a/drivers/media/rc/Kconfig ++++ b/drivers/media/rc/Kconfig +@@ -235,6 +235,17 @@ config IR_MESON + To compile this driver as a module, choose M here: the + module will be called meson-ir. + ++config IR_MTK ++ tristate "Mediatek IR remote receiver" ++ depends on RC_CORE ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ ---help--- ++ Say Y if you want to use the IR remote receiver available ++ on Mediatek SoCs. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called mtk-cir. ++ + config IR_NUVOTON + tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" + depends on PNP +--- /dev/null ++++ b/drivers/media/rc/mtk-cir.c +@@ -0,0 +1,329 @@ ++/* ++ * Driver for Mediatek IR Receiver Controller ++ * ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MTK_IR_DEV KBUILD_MODNAME ++ ++/* Register to enable PWM and IR */ ++#define MTK_CONFIG_HIGH_REG 0x0c ++/* Enable IR pulse width detection */ ++#define MTK_PWM_EN BIT(13) ++/* Enable IR hardware function */ ++#define MTK_IR_EN BIT(0) ++ ++/* Register to setting sample period */ ++#define MTK_CONFIG_LOW_REG 0x10 ++/* Field to set sample period */ ++#define CHK_PERIOD DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, \ ++ MTK_IR_CLK_PERIOD) ++#define MTK_CHK_PERIOD (((CHK_PERIOD) << 8) & (GENMASK(20, 8))) ++#define MTK_CHK_PERIOD_MASK (GENMASK(20, 8)) ++ ++/* Register to clear state of state machine */ ++#define MTK_IRCLR_REG 0x20 ++/* Bit to restart IR receiving */ ++#define MTK_IRCLR BIT(0) ++ ++/* Register containing pulse width data */ ++#define MTK_CHKDATA_REG(i) (0x88 + 4 * (i)) ++#define MTK_WIDTH_MASK (GENMASK(7, 0)) ++ ++/* Register to enable IR interrupt */ ++#define MTK_IRINT_EN_REG 0xcc ++/* Bit to enable interrupt */ ++#define MTK_IRINT_EN BIT(0) ++ ++/* Register to ack IR interrupt */ ++#define MTK_IRINT_CLR_REG 0xd0 ++/* Bit to clear interrupt status */ ++#define MTK_IRINT_CLR BIT(0) ++ ++/* Maximum count of samples */ ++#define MTK_MAX_SAMPLES 0xff ++/* Indicate the end of IR message */ ++#define MTK_IR_END(v, p) ((v) == MTK_MAX_SAMPLES && (p) == 0) ++/* Number of registers to record the pulse width */ ++#define MTK_CHKDATA_SZ 17 ++/* Source clock frequency */ ++#define MTK_IR_BASE_CLK 273000000 ++/* Frequency after IR internal divider */ ++#define MTK_IR_CLK_FREQ (MTK_IR_BASE_CLK / 4) ++/* Period for MTK_IR_CLK in ns*/ ++#define MTK_IR_CLK_PERIOD DIV_ROUND_CLOSEST(1000000000ul, \ ++ MTK_IR_CLK_FREQ) ++/* Sample period in ns */ ++#define MTK_IR_SAMPLE (MTK_IR_CLK_PERIOD * 0xc00) ++ ++/* struct mtk_ir - This is the main datasructure for holding the state ++ * of the driver ++ * @dev: The device pointer ++ * @rc: The rc instrance ++ * @irq: The IRQ that we are using ++ * @base: The mapped register i/o base ++ * @clk: The clock that we are using ++ */ ++struct mtk_ir { ++ struct device *dev; ++ struct rc_dev *rc; ++ void __iomem *base; ++ int irq; ++ struct clk *clk; ++}; ++ ++static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg) ++{ ++ u32 tmp; ++ ++ tmp = __raw_readl(ir->base + reg); ++ tmp = (tmp & ~mask) | val; ++ __raw_writel(tmp, ir->base + reg); ++} ++ ++static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg) ++{ ++ __raw_writel(val, ir->base + reg); ++} ++ ++static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg) ++{ ++ return __raw_readl(ir->base + reg); ++} ++ ++static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask) ++{ ++ u32 val; ++ ++ val = mtk_r32(ir, MTK_IRINT_EN_REG); ++ mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG); ++} ++ ++static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask) ++{ ++ u32 val; ++ ++ val = mtk_r32(ir, MTK_IRINT_EN_REG); ++ mtk_w32(ir, val | mask, MTK_IRINT_EN_REG); ++} ++ ++static irqreturn_t mtk_ir_irq(int irqno, void *dev_id) ++{ ++ struct mtk_ir *ir = dev_id; ++ u8 wid = 0; ++ u32 i, j, val; ++ DEFINE_IR_RAW_EVENT(rawir); ++ ++ /* Reset decoder state machine explicitly is required ++ * because 1) the longest duration for space MTK IR hardware ++ * could record is not safely long. e.g 12ms if rx resolution ++ * is 46us by default. There is still the risk to satisfying ++ * every decoder to reset themselves through long enough ++ * trailing spaces and 2) the IRQ handler guarantees that ++ * start of IR message is always contained in and starting ++ * from register MTK_CHKDATA_REG(0). ++ */ ++ ir_raw_event_reset(ir->rc); ++ ++ /* First message must be pulse */ ++ rawir.pulse = false; ++ ++ /* Handle all pulse and space IR controller captures */ ++ for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) { ++ val = mtk_r32(ir, MTK_CHKDATA_REG(i)); ++ dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val); ++ ++ for (j = 0 ; j < 4 ; j++) { ++ wid = (val & (MTK_WIDTH_MASK << j * 8)) >> j * 8; ++ rawir.pulse = !rawir.pulse; ++ rawir.duration = wid * (MTK_IR_SAMPLE + 1); ++ ir_raw_event_store_with_filter(ir->rc, &rawir); ++ } ++ } ++ ++ /* The maximum number of edges the IR controller can ++ * hold is MTK_CHKDATA_SZ * 4. So if received IR messages ++ * is over the limit, the last incomplete IR message would ++ * be appended trailing space and still would be sent into ++ * ir-rc-raw to decode. That helps it is possible that it ++ * has enough information to decode a scancode even if the ++ * trailing end of the message is missing. ++ */ ++ if (!MTK_IR_END(wid, rawir.pulse)) { ++ rawir.pulse = false; ++ rawir.duration = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); ++ ir_raw_event_store_with_filter(ir->rc, &rawir); ++ } ++ ++ ir_raw_event_handle(ir->rc); ++ ++ /* Restart controller for the next receive that would ++ * clear up all CHKDATA registers ++ */ ++ mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG); ++ ++ /* Clear interrupt status */ ++ mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG); ++ ++ return IRQ_HANDLED; ++} ++ ++static int mtk_ir_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *dn = dev->of_node; ++ struct resource *res; ++ struct mtk_ir *ir; ++ u32 val; ++ int ret = 0; ++ const char *map_name; ++ ++ ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL); ++ if (!ir) ++ return -ENOMEM; ++ ++ ir->dev = dev; ++ ++ if (!of_device_is_compatible(dn, "mediatek,mt7623-cir")) ++ return -ENODEV; ++ ++ ir->clk = devm_clk_get(dev, "clk"); ++ if (IS_ERR(ir->clk)) { ++ dev_err(dev, "failed to get a ir clock.\n"); ++ return PTR_ERR(ir->clk); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ir->base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(ir->base)) { ++ dev_err(dev, "failed to map registers\n"); ++ return PTR_ERR(ir->base); ++ } ++ ++ ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); ++ if (!ir->rc) { ++ dev_err(dev, "failed to allocate device\n"); ++ return -ENOMEM; ++ } ++ ++ ir->rc->priv = ir; ++ ir->rc->input_name = MTK_IR_DEV; ++ ir->rc->input_phys = MTK_IR_DEV "/input0"; ++ ir->rc->input_id.bustype = BUS_HOST; ++ ir->rc->input_id.vendor = 0x0001; ++ ir->rc->input_id.product = 0x0001; ++ ir->rc->input_id.version = 0x0001; ++ map_name = of_get_property(dn, "linux,rc-map-name", NULL); ++ ir->rc->map_name = map_name ?: RC_MAP_EMPTY; ++ ir->rc->dev.parent = dev; ++ ir->rc->driver_name = MTK_IR_DEV; ++ ir->rc->allowed_protocols = RC_BIT_ALL; ++ ir->rc->rx_resolution = MTK_IR_SAMPLE; ++ ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1); ++ ++ ret = devm_rc_register_device(dev, ir->rc); ++ if (ret) { ++ dev_err(dev, "failed to register rc device\n"); ++ return ret; ++ } ++ ++ platform_set_drvdata(pdev, ir); ++ ++ ir->irq = platform_get_irq(pdev, 0); ++ if (ir->irq < 0) { ++ dev_err(dev, "no irq resource\n"); ++ return -ENODEV; ++ } ++ ++ /* Enable interrupt after proper hardware ++ * setup and IRQ handler registration ++ */ ++ if (clk_prepare_enable(ir->clk)) { ++ dev_err(dev, "try to enable ir_clk failed\n"); ++ ret = -EINVAL; ++ goto exit_clkdisable_clk; ++ } ++ ++ mtk_irq_disable(ir, MTK_IRINT_EN); ++ ++ ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir); ++ if (ret) { ++ dev_err(dev, "failed request irq\n"); ++ goto exit_clkdisable_clk; ++ } ++ ++ /* Enable IR and PWM */ ++ val = mtk_r32(ir, MTK_CONFIG_HIGH_REG); ++ val |= MTK_PWM_EN | MTK_IR_EN; ++ mtk_w32(ir, val, MTK_CONFIG_HIGH_REG); ++ ++ /* Setting sample period */ ++ mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK, ++ MTK_CONFIG_LOW_REG); ++ ++ mtk_irq_enable(ir, MTK_IRINT_EN); ++ ++ dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n", ++ DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000)); ++ ++ return 0; ++ ++exit_clkdisable_clk: ++ clk_disable_unprepare(ir->clk); ++ ++ return ret; ++} ++ ++static int mtk_ir_remove(struct platform_device *pdev) ++{ ++ struct mtk_ir *ir = platform_get_drvdata(pdev); ++ ++ /* Avoid contention between remove handler and ++ * IRQ handler so that disabling IR interrupt and ++ * waiting for pending IRQ handler to complete ++ */ ++ mtk_irq_disable(ir, MTK_IRINT_EN); ++ synchronize_irq(ir->irq); ++ ++ clk_disable_unprepare(ir->clk); ++ ++ return 0; ++} ++ ++static const struct of_device_id mtk_ir_match[] = { ++ { .compatible = "mediatek,mt7623-cir" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtk_ir_match); ++ ++static struct platform_driver mtk_ir_driver = { ++ .probe = mtk_ir_probe, ++ .remove = mtk_ir_remove, ++ .driver = { ++ .name = MTK_IR_DEV, ++ .of_match_table = mtk_ir_match, ++ }, ++}; ++ ++module_platform_driver(mtk_ir_driver); ++ ++MODULE_DESCRIPTION("Mediatek IR Receiver Controller Driver"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_LICENSE("GPL"); +--- a/drivers/media/rc/Makefile ++++ b/drivers/media/rc/Makefile +@@ -37,3 +37,4 @@ obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o + obj-$(CONFIG_RC_ST) += st_rc.o + obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o + obj-$(CONFIG_IR_IMG) += img-ir/ ++obj-$(CONFIG_IR_MTK) += mtk-cir.o +--- a/drivers/media/rc/rc-main.c ++++ b/drivers/media/rc/rc-main.c +@@ -1355,7 +1355,7 @@ static struct device_type rc_dev_type = + .uevent = rc_dev_uevent, + }; + +-struct rc_dev *rc_allocate_device(void) ++struct rc_dev *rc_allocate_device(enum rc_driver_type type) + { + struct rc_dev *dev; + +@@ -1382,6 +1382,8 @@ struct rc_dev *rc_allocate_device(void) + dev->dev.class = &rc_class; + device_initialize(&dev->dev); + ++ dev->driver_type = type; ++ + __module_get(THIS_MODULE); + return dev; + } +@@ -1403,6 +1405,35 @@ void rc_free_device(struct rc_dev *dev) + } + EXPORT_SYMBOL_GPL(rc_free_device); + ++static void devm_rc_alloc_release(struct device *dev, void *res) ++{ ++ rc_free_device(*(struct rc_dev **)res); ++} ++ ++struct rc_dev *devm_rc_allocate_device(struct device *dev, ++ enum rc_driver_type type) ++{ ++ struct rc_dev **dr, *rc; ++ ++ dr = devres_alloc(devm_rc_alloc_release, sizeof(*dr), GFP_KERNEL); ++ if (!dr) ++ return NULL; ++ ++ rc = rc_allocate_device(type); ++ if (!rc) { ++ devres_free(dr); ++ return NULL; ++ } ++ ++ rc->dev.parent = dev; ++ rc->managed_alloc = true; ++ *dr = rc; ++ devres_add(dev, dr); ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(devm_rc_allocate_device); ++ + int rc_register_device(struct rc_dev *dev) + { + static bool raw_init = false; /* raw decoders loaded? */ +@@ -1536,6 +1567,33 @@ out_unlock: + } + EXPORT_SYMBOL_GPL(rc_register_device); + ++static void devm_rc_release(struct device *dev, void *res) ++{ ++ rc_unregister_device(*(struct rc_dev **)res); ++} ++ ++int devm_rc_register_device(struct device *parent, struct rc_dev *dev) ++{ ++ struct rc_dev **dr; ++ int ret; ++ ++ dr = devres_alloc(devm_rc_release, sizeof(*dr), GFP_KERNEL); ++ if (!dr) ++ return -ENOMEM; ++ ++ ret = rc_register_device(dev); ++ if (ret) { ++ devres_free(dr); ++ return ret; ++ } ++ ++ *dr = dev; ++ devres_add(parent, dr); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(devm_rc_register_device); ++ + void rc_unregister_device(struct rc_dev *dev) + { + if (!dev) +@@ -1557,7 +1615,8 @@ void rc_unregister_device(struct rc_dev + + ida_simple_remove(&rc_ida, dev->minor); + +- rc_free_device(dev); ++ if (!dev->managed_alloc) ++ rc_free_device(dev); + } + + EXPORT_SYMBOL_GPL(rc_unregister_device); +--- a/include/media/rc-core.h ++++ b/include/media/rc-core.h +@@ -68,6 +68,7 @@ enum rc_filter_type { + * struct rc_dev - represents a remote control device + * @dev: driver model's view of this device + * @initialized: 1 if the device init has completed, 0 otherwise ++ * @managed_alloc: devm_rc_allocate_device was used to create rc_dev + * @sysfs_groups: sysfs attribute groups + * @input_name: name of the input child device + * @input_phys: physical path to the input child device +@@ -131,6 +132,7 @@ enum rc_filter_type { + struct rc_dev { + struct device dev; + atomic_t initialized; ++ bool managed_alloc; + const struct attribute_group *sysfs_groups[5]; + const char *input_name; + const char *input_phys; +@@ -198,9 +200,19 @@ struct rc_dev { + /** + * rc_allocate_device - Allocates a RC device + * ++ * @rc_driver_type: specifies the type of the RC output to be allocated + * returns a pointer to struct rc_dev. + */ +-struct rc_dev *rc_allocate_device(void); ++struct rc_dev *rc_allocate_device(enum rc_driver_type); ++ ++/** ++ * devm_rc_allocate_device - Managed RC device allocation ++ * ++ * @dev: pointer to struct device ++ * @rc_driver_type: specifies the type of the RC output to be allocated ++ * returns a pointer to struct rc_dev. ++ */ ++struct rc_dev *devm_rc_allocate_device(struct device *dev, enum rc_driver_type); + + /** + * rc_free_device - Frees a RC device +@@ -217,6 +229,14 @@ void rc_free_device(struct rc_dev *dev); + int rc_register_device(struct rc_dev *dev); + + /** ++ * devm_rc_register_device - Manageded registering of a RC device ++ * ++ * @parent: pointer to struct device. ++ * @dev: pointer to struct rc_dev. ++ */ ++int devm_rc_register_device(struct device *parent, struct rc_dev *dev); ++ ++/** + * rc_unregister_device - Unregisters a RC device + * + * @dev: pointer to struct rc_dev. +--- a/drivers/media/common/siano/smsir.c ++++ b/drivers/media/common/siano/smsir.c +@@ -58,7 +58,7 @@ int sms_ir_init(struct smscore_device_t + struct rc_dev *dev; + + pr_debug("Allocating rc device\n"); +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!dev) + return -ENOMEM; + +--- a/drivers/media/i2c/ir-kbd-i2c.c ++++ b/drivers/media/i2c/ir-kbd-i2c.c +@@ -428,7 +428,7 @@ static int ir_probe(struct i2c_client *c + * If platform_data doesn't specify rc_dev, initialize it + * internally + */ +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rc) + return -ENOMEM; + } +--- a/drivers/media/pci/bt8xx/bttv-input.c ++++ b/drivers/media/pci/bt8xx/bttv-input.c +@@ -424,7 +424,7 @@ int bttv_input_init(struct bttv *btv) + return -ENODEV; + + ir = kzalloc(sizeof(*ir),GFP_KERNEL); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!ir || !rc) + goto err_out_free; + +--- a/drivers/media/pci/cx23885/cx23885-input.c ++++ b/drivers/media/pci/cx23885/cx23885-input.c +@@ -267,7 +267,6 @@ int cx23885_input_init(struct cx23885_de + struct cx23885_kernel_ir *kernel_ir; + struct rc_dev *rc; + char *rc_map; +- enum rc_driver_type driver_type; + u64 allowed_protos; + + int ret; +@@ -352,7 +351,7 @@ int cx23885_input_init(struct cx23885_de + pci_name(dev->pci)); + + /* input device */ +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rc) { + ret = -ENOMEM; + goto err_out_free; +@@ -371,7 +370,6 @@ int cx23885_input_init(struct cx23885_de + rc->input_id.product = dev->pci->device; + } + rc->dev.parent = &dev->pci->dev; +- rc->driver_type = driver_type; + rc->allowed_protocols = allowed_protos; + rc->priv = kernel_ir; + rc->open = cx23885_input_ir_open; +--- a/drivers/media/pci/cx88/cx88-input.c ++++ b/drivers/media/pci/cx88/cx88-input.c +@@ -272,7 +272,7 @@ int cx88_ir_init(struct cx88_core *core, + */ + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir || !dev) + goto err_out_free; + +@@ -482,7 +482,6 @@ int cx88_ir_init(struct cx88_core *core, + dev->scancode_mask = hardware_mask; + + if (ir->sampling) { +- dev->driver_type = RC_DRIVER_IR_RAW; + dev->timeout = 10 * 1000 * 1000; /* 10 ms */ + } else { + dev->driver_type = RC_DRIVER_SCANCODE; +--- a/drivers/media/pci/dm1105/dm1105.c ++++ b/drivers/media/pci/dm1105/dm1105.c +@@ -744,7 +744,7 @@ static int dm1105_ir_init(struct dm1105_ + struct rc_dev *dev; + int err = -ENOMEM; + +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!dev) + return -ENOMEM; + +@@ -753,7 +753,6 @@ static int dm1105_ir_init(struct dm1105_ + + dev->driver_name = MODULE_NAME; + dev->map_name = RC_MAP_DM1105_NEC; +- dev->driver_type = RC_DRIVER_SCANCODE; + dev->input_name = "DVB on-card IR receiver"; + dev->input_phys = dm1105->ir.input_phys; + dev->input_id.bustype = BUS_PCI; +--- a/drivers/media/pci/mantis/mantis_input.c ++++ b/drivers/media/pci/mantis/mantis_input.c +@@ -39,7 +39,7 @@ int mantis_input_init(struct mantis_pci + struct rc_dev *dev; + int err; + +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!dev) { + dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); + err = -ENOMEM; +--- a/drivers/media/pci/saa7134/saa7134-input.c ++++ b/drivers/media/pci/saa7134/saa7134-input.c +@@ -849,7 +849,7 @@ int saa7134_input_init1(struct saa7134_d + } + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!ir || !rc) { + err = -ENOMEM; + goto err_out_free; +--- a/drivers/media/pci/smipcie/smipcie-ir.c ++++ b/drivers/media/pci/smipcie/smipcie-ir.c +@@ -183,7 +183,7 @@ int smi_ir_init(struct smi_dev *dev) + struct rc_dev *rc_dev; + struct smi_rc *ir = &dev->ir; + +- rc_dev = rc_allocate_device(); ++ rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rc_dev) + return -ENOMEM; + +@@ -202,7 +202,6 @@ int smi_ir_init(struct smi_dev *dev) + rc_dev->input_id.product = dev->pci_dev->subsystem_device; + rc_dev->dev.parent = &dev->pci_dev->dev; + +- rc_dev->driver_type = RC_DRIVER_SCANCODE; + rc_dev->map_name = dev->info->rc_map; + + ir->rc_dev = rc_dev; +--- a/drivers/media/pci/ttpci/budget-ci.c ++++ b/drivers/media/pci/ttpci/budget-ci.c +@@ -177,7 +177,7 @@ static int msp430_ir_init(struct budget_ + struct rc_dev *dev; + int error; + +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!dev) { + printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); + return -ENOMEM; +--- a/drivers/media/rc/ati_remote.c ++++ b/drivers/media/rc/ati_remote.c +@@ -765,7 +765,6 @@ static void ati_remote_rc_init(struct at + struct rc_dev *rdev = ati_remote->rdev; + + rdev->priv = ati_remote; +- rdev->driver_type = RC_DRIVER_SCANCODE; + rdev->allowed_protocols = RC_BIT_OTHER; + rdev->driver_name = "ati_remote"; + +@@ -852,7 +851,7 @@ static int ati_remote_probe(struct usb_i + } + + ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL); +- rc_dev = rc_allocate_device(); ++ rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!ati_remote || !rc_dev) + goto exit_free_dev_rdev; + +--- a/drivers/media/rc/ene_ir.c ++++ b/drivers/media/rc/ene_ir.c +@@ -1012,7 +1012,7 @@ static int ene_probe(struct pnp_dev *pnp + + /* allocate memory */ + dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!dev || !rdev) + goto exit_free_dev_rdev; + +--- a/drivers/media/rc/fintek-cir.c ++++ b/drivers/media/rc/fintek-cir.c +@@ -496,7 +496,7 @@ static int fintek_probe(struct pnp_dev * + return ret; + + /* input device for IR remote (and tx) */ +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rdev) + goto exit_free_dev_rdev; + +--- a/drivers/media/rc/gpio-ir-recv.c ++++ b/drivers/media/rc/gpio-ir-recv.c +@@ -143,14 +143,13 @@ static int gpio_ir_recv_probe(struct pla + if (!gpio_dev) + return -ENOMEM; + +- rcdev = rc_allocate_device(); ++ rcdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rcdev) { + rc = -ENOMEM; + goto err_allocate_device; + } + + rcdev->priv = gpio_dev; +- rcdev->driver_type = RC_DRIVER_IR_RAW; + rcdev->input_name = GPIO_IR_DEVICE_NAME; + rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0"; + rcdev->input_id.bustype = BUS_HOST; +--- a/drivers/media/rc/igorplugusb.c ++++ b/drivers/media/rc/igorplugusb.c +@@ -190,7 +190,7 @@ static int igorplugusb_probe(struct usb_ + + usb_make_path(udev, ir->phys, sizeof(ir->phys)); + +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rc) + goto fail; + +@@ -198,7 +198,6 @@ static int igorplugusb_probe(struct usb_ + rc->input_phys = ir->phys; + usb_to_input_id(udev, &rc->input_id); + rc->dev.parent = &intf->dev; +- rc->driver_type = RC_DRIVER_IR_RAW; + /* + * This device can only store 36 pulses + spaces, which is not enough + * for the NEC protocol and many others. +--- a/drivers/media/rc/iguanair.c ++++ b/drivers/media/rc/iguanair.c +@@ -431,7 +431,7 @@ static int iguanair_probe(struct usb_int + struct usb_host_interface *idesc; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir || !rc) { + ret = -ENOMEM; + goto out; +--- a/drivers/media/rc/img-ir/img-ir-hw.c ++++ b/drivers/media/rc/img-ir/img-ir-hw.c +@@ -1071,7 +1071,7 @@ int img_ir_probe_hw(struct img_ir_priv * + } + + /* Allocate hardware decoder */ +- hw->rdev = rdev = rc_allocate_device(); ++ hw->rdev = rdev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rdev) { + dev_err(priv->dev, "cannot allocate input device\n"); + error = -ENOMEM; +--- a/drivers/media/rc/img-ir/img-ir-raw.c ++++ b/drivers/media/rc/img-ir/img-ir-raw.c +@@ -110,7 +110,7 @@ int img_ir_probe_raw(struct img_ir_priv + setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv); + + /* Allocate raw decoder */ +- raw->rdev = rdev = rc_allocate_device(); ++ raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rdev) { + dev_err(priv->dev, "cannot allocate raw input device\n"); + return -ENOMEM; +@@ -118,7 +118,6 @@ int img_ir_probe_raw(struct img_ir_priv + rdev->priv = priv; + rdev->map_name = RC_MAP_EMPTY; + rdev->input_name = "IMG Infrared Decoder Raw"; +- rdev->driver_type = RC_DRIVER_IR_RAW; + + /* Register raw decoder */ + error = rc_register_device(rdev); +--- a/drivers/media/rc/imon.c ++++ b/drivers/media/rc/imon.c +@@ -1951,7 +1951,7 @@ static struct rc_dev *imon_init_rdev(str + const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x88 }; + +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rdev) { + dev_err(ictx->dev, "remote control dev allocation failed\n"); + goto out; +@@ -1969,7 +1969,6 @@ static struct rc_dev *imon_init_rdev(str + rdev->dev.parent = ictx->dev; + + rdev->priv = ictx; +- rdev->driver_type = RC_DRIVER_SCANCODE; + rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ + rdev->change_protocol = imon_ir_change_protocol; + rdev->driver_name = MOD_NAME; +--- a/drivers/media/rc/ir-hix5hd2.c ++++ b/drivers/media/rc/ir-hix5hd2.c +@@ -222,7 +222,7 @@ static int hix5hd2_ir_probe(struct platf + return priv->irq; + } + +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rdev) + return -ENOMEM; + +--- a/drivers/media/rc/ite-cir.c ++++ b/drivers/media/rc/ite-cir.c +@@ -1472,7 +1472,7 @@ static int ite_probe(struct pnp_dev *pde + return ret; + + /* input device for IR remote (and tx) */ +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rdev) + goto exit_free_dev_rdev; + itdev->rdev = rdev; +--- a/drivers/media/rc/mceusb.c ++++ b/drivers/media/rc/mceusb.c +@@ -1220,7 +1220,7 @@ static struct rc_dev *mceusb_init_rc_dev + struct rc_dev *rc; + int ret; + +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rc) { + dev_err(dev, "remote dev allocation failed"); + goto out; +--- a/drivers/media/rc/meson-ir.c ++++ b/drivers/media/rc/meson-ir.c +@@ -131,7 +131,7 @@ static int meson_ir_probe(struct platfor + return ir->irq; + } + +- ir->rc = rc_allocate_device(); ++ ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir->rc) { + dev_err(dev, "failed to allocate rc device\n"); + return -ENOMEM; +--- a/drivers/media/rc/rc-loopback.c ++++ b/drivers/media/rc/rc-loopback.c +@@ -181,7 +181,7 @@ static int __init loop_init(void) + struct rc_dev *rc; + int ret; + +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rc) { + printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); + return -ENOMEM; +--- a/drivers/media/rc/st_rc.c ++++ b/drivers/media/rc/st_rc.c +@@ -235,7 +235,7 @@ static int st_rc_probe(struct platform_d + if (!rc_dev) + return -ENOMEM; + +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + + if (!rdev) + return -ENOMEM; +--- a/drivers/media/rc/streamzap.c ++++ b/drivers/media/rc/streamzap.c +@@ -291,7 +291,7 @@ static struct rc_dev *streamzap_init_rc_ + struct device *dev = sz->dev; + int ret; + +- rdev = rc_allocate_device(); ++ rdev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!rdev) { + dev_err(dev, "remote dev allocation failed\n"); + goto out; +--- a/drivers/media/rc/sunxi-cir.c ++++ b/drivers/media/rc/sunxi-cir.c +@@ -212,7 +212,7 @@ static int sunxi_ir_probe(struct platfor + goto exit_clkdisable_clk; + } + +- ir->rc = rc_allocate_device(); ++ ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir->rc) { + dev_err(dev, "failed to allocate device\n"); + ret = -ENOMEM; +--- a/drivers/media/rc/ttusbir.c ++++ b/drivers/media/rc/ttusbir.c +@@ -205,7 +205,7 @@ static int ttusbir_probe(struct usb_inte + int altsetting = -1; + + tt = kzalloc(sizeof(*tt), GFP_KERNEL); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!tt || !rc) { + ret = -ENOMEM; + goto out; +--- a/drivers/media/rc/winbond-cir.c ++++ b/drivers/media/rc/winbond-cir.c +@@ -1062,13 +1062,12 @@ wbcir_probe(struct pnp_dev *device, cons + if (err) + goto exit_free_data; + +- data->dev = rc_allocate_device(); ++ data->dev = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!data->dev) { + err = -ENOMEM; + goto exit_unregister_led; + } + +- data->dev->driver_type = RC_DRIVER_IR_RAW; + data->dev->driver_name = DRVNAME; + data->dev->input_name = WBCIR_NAME; + data->dev->input_phys = "wbcir/cir0"; +--- a/drivers/media/usb/au0828/au0828-input.c ++++ b/drivers/media/usb/au0828/au0828-input.c +@@ -298,7 +298,7 @@ int au0828_rc_register(struct au0828_dev + return -ENODEV; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_IR_RAW); + if (!ir || !rc) + goto error; + +@@ -343,7 +343,6 @@ int au0828_rc_register(struct au0828_dev + rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct); + rc->dev.parent = &dev->usbdev->dev; + rc->driver_name = "au0828-input"; +- rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | + RC_BIT_RC5; + +--- a/drivers/media/usb/cx231xx/cx231xx-input.c ++++ b/drivers/media/usb/cx231xx/cx231xx-input.c +@@ -72,7 +72,7 @@ int cx231xx_ir_init(struct cx231xx *dev) + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&dev->init_data, 0, sizeof(dev->init_data)); +- dev->init_data.rc_dev = rc_allocate_device(); ++ dev->init_data.rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!dev->init_data.rc_dev) + return -ENOMEM; + +--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c ++++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +@@ -147,7 +147,7 @@ static int dvb_usbv2_remote_init(struct + if (!d->rc.map_name) + return 0; + +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(d->rc.driver_type); + if (!dev) { + ret = -ENOMEM; + goto err; +@@ -162,7 +162,6 @@ static int dvb_usbv2_remote_init(struct + /* TODO: likely RC-core should took const char * */ + dev->driver_name = (char *) d->props->driver_name; + dev->map_name = d->rc.map_name; +- dev->driver_type = d->rc.driver_type; + dev->allowed_protocols = d->rc.allowed_protos; + dev->change_protocol = d->rc.change_protocol; + dev->priv = d; +--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c ++++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c +@@ -265,7 +265,7 @@ static int rc_core_dvb_usb_remote_init(s + int err, rc_interval; + struct rc_dev *dev; + +- dev = rc_allocate_device(); ++ dev = rc_allocate_device(d->props.rc.core.driver_type); + if (!dev) + return -ENOMEM; + +@@ -273,7 +273,6 @@ static int rc_core_dvb_usb_remote_init(s + dev->map_name = d->props.rc.core.rc_codes; + dev->change_protocol = d->props.rc.core.change_protocol; + dev->allowed_protocols = d->props.rc.core.allowed_protos; +- dev->driver_type = d->props.rc.core.driver_type; + usb_to_input_id(d->udev, &dev->input_id); + dev->input_name = "IR-receiver inside an USB DVB receiver"; + dev->input_phys = d->rc_phys; +--- a/drivers/media/usb/em28xx/em28xx-input.c ++++ b/drivers/media/usb/em28xx/em28xx-input.c +@@ -713,7 +713,7 @@ static int em28xx_ir_init(struct em28xx + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rc) + goto error; + +--- a/drivers/media/usb/tm6000/tm6000-input.c ++++ b/drivers/media/usb/tm6000/tm6000-input.c +@@ -429,7 +429,7 @@ int tm6000_ir_init(struct tm6000_core *d + return 0; + + ir = kzalloc(sizeof(*ir), GFP_ATOMIC); +- rc = rc_allocate_device(); ++ rc = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!ir || !rc) + goto out; + +@@ -456,7 +456,6 @@ int tm6000_ir_init(struct tm6000_core *d + ir->polling = 50; + INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key); + } +- rc->driver_type = RC_DRIVER_SCANCODE; + + snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", + dev->name); diff --git a/target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch deleted file mode 100644 index 1ab8ce287a..0000000000 --- a/target/linux/mediatek/patches-4.9/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch +++ /dev/null @@ -1,698 +0,0 @@ -From 8ab1d4e0a9a68e03f472dee1c036a01d0198c20c Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 5 Jan 2016 20:20:04 +0100 -Subject: [PATCH 025/102] PCI: mediatek: add support for PCIe found on - MT7623/MT2701 - -Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports -a single Root complex (RC) with 3 Root Ports. The SoCs supports a Gen2 -1-lan Link on each port. - -Signed-off-by: John Crispin ---- - arch/arm/mach-mediatek/Kconfig | 1 + - drivers/pci/host/Kconfig | 11 + - drivers/pci/host/Makefile | 1 + - drivers/pci/host/pcie-mediatek.c | 641 ++++++++++++++++++++++++++++++++++++++ - 4 files changed, 654 insertions(+) - create mode 100644 drivers/pci/host/pcie-mediatek.c - ---- a/arch/arm/mach-mediatek/Kconfig -+++ b/arch/arm/mach-mediatek/Kconfig -@@ -29,6 +29,7 @@ config MACH_MT6592 - config MACH_MT7623 - bool "MediaTek MT7623 SoCs support" - default ARCH_MEDIATEK -+ select MIGHT_HAVE_PCI - - config MACH_MT8127 - bool "MediaTek MT8127 SoCs support" ---- a/drivers/pci/host/Kconfig -+++ b/drivers/pci/host/Kconfig -@@ -301,4 +301,15 @@ config VMD - To compile this driver as a module, choose M here: the - module will be called vmd. - -+config PCIE_MTK -+ bool "Mediatek PCIe Controller" -+ depends on MACH_MT2701 || MACH_MT7623 -+ depends on OF -+ depends on PCI -+ help -+ Say Y here if you want to enable PCI controller support on Mediatek MT7623. -+ MT7623 PCIe supports single Root complex (RC) with 3 Root Ports. -+ Each port supports a Gen2 1-lan Link. -+ PCIe include one Host/PCI bridge and 3 PCIe MAC. -+ - endmenu ---- a/drivers/pci/host/Makefile -+++ b/drivers/pci/host/Makefile -@@ -33,3 +33,4 @@ obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-arm - obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o - obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o - obj-$(CONFIG_VMD) += vmd.o -+obj-$(CONFIG_PCIE_MTK) += pcie-mediatek.o ---- /dev/null -+++ b/drivers/pci/host/pcie-mediatek.c -@@ -0,0 +1,641 @@ -+/* -+ * Mediatek MT2701/MT7623 SoC PCIE support -+ * -+ * Copyright (C) 2015 Mediatek -+ * Copyright (C) 2015 Ziv Huang -+ * Copyright (C) 2015 John Crispin -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MEMORY_BASE 0x80000000 -+ -+/* PCIE Registers */ -+#define PCICFG 0x00 -+#define PCIINT 0x08 -+#define PCIENA 0x0c -+#define CFGADDR 0x20 -+#define CFGDATA 0x24 -+#define MEMBASE 0x28 -+#define IOBASE 0x2c -+ -+/* per Port Registers */ -+#define BAR0SETUP 0x10 -+#define IMBASEBAR0 0x18 -+#define PCIE_CLASS 0x34 -+#define PCIE_SISTAT 0x50 -+ -+#define MTK_PCIE_HIGH_PERF BIT(14) -+#define PCIEP0_BASE 0x2000 -+#define PCIEP1_BASE 0x3000 -+#define PCIEP2_BASE 0x4000 -+ -+#define PHY_P0_CTL 0x9000 -+#define PHY_P1_CTL 0xa000 -+#define PHY_P2_CTL 0x4000 -+ -+#define RSTCTL_PCIE0_RST BIT(24) -+#define RSTCTL_PCIE1_RST BIT(25) -+#define RSTCTL_PCIE2_RST BIT(26) -+ -+#define HIFSYS_SYSCFG1 0x14 -+#define HIFSYS_SYSCFG1_PHY2_MASK (0x3 << 20) -+ -+#define MTK_PHY_CLK 0xb00 -+#define MTK_PHY_CLKDRV_OFFSET BIT(2) -+#define MTK_PHY_CLKDRV_OFFSET_MASK 0xe -+#define MTK_PHY_PLL 0xb04 -+#define MTK_PHY_CLKDRV_AMP BIT(30) -+#define MTK_PHY_CLKDRV_AMP_MASK 0xe0000000 -+#define MTK_PHY_REFCLK_SEL 0xc00 -+#define MTK_PHY_XTAL_EXT_EN (BIT(17) | BIT(12)) -+#define MTK_PHY_XTAL_EXT_EN_MASK 0x33000 -+#define MTK_PHY_PLL_BC 0xc08 -+#define MTK_PHY_PLL_BC_PE2H 0xc0 -+#define MTK_PHY_PLL_BC_PE2H_MASK 0x380000 -+#define MTK_PHY_PLL_IC 0xc0c -+#define MTK_PHY_PLL_IC_BR_PE2H BIT(28) -+#define MTK_PHY_PLL_IC_BR_PE2H_MASK 0x30000000 -+#define MTK_PHY_PLL_IC_PE2H BIT(12) -+#define MTK_PHY_PLL_IC_PE2H_MASK 0xf000 -+#define MTK_PHY_PLL_IR 0xc10 -+#define MTK_PHY_PLL_IR_PE2H BIT(17) -+#define MTK_PHY_PLL_IR_PE2H_MASK 0xf0000 -+#define MTK_PHY_PLL_BP 0xc14 -+#define MTK_PHY_PLL_BP_PE2H (BIT(19) | BIT(17)) -+#define MTK_PHY_PLL_BP_PE2H_MASK 0xf0000 -+#define MTK_PHY_SSC_DELTA1 0xc3c -+#define MTK_PHY_SSC_DELTA1_PE2H (0x3c << 16) -+#define MTK_PHY_SSC_DELTA1_PE2H_MASK 0xffff0000 -+#define MTK_PHY_SSC_DELTA 0xc48 -+#define MTK_PHY_SSC_DELTA_PE2H 0x36 -+#define MTK_PHY_SSC_DELTA_PE2H_MASK 0xffff -+ -+#define MAX_PORT_NUM 3 -+ -+struct mtk_pcie_port { -+ int id; -+ int enable; -+ int irq; -+ u32 link; -+ void __iomem *phy_base; -+ struct reset_control *rstc; -+}; -+ -+#define mtk_foreach_port(pcie, p) \ -+ for ((p) = pcie->port; \ -+ (p) != &pcie->port[MAX_PORT_NUM]; (p)++) -+ -+struct mtk_pcie { -+ struct device *dev; -+ void __iomem *pcie_base; -+ struct regmap *hifsys; -+ -+ struct resource io; -+ struct resource pio; -+ struct resource mem; -+ struct resource prefetch; -+ struct resource busn; -+ -+ u32 io_bus_addr; -+ u32 mem_bus_addr; -+ -+ struct clk *clk; -+ -+ struct mtk_pcie_port port[MAX_PORT_NUM]; -+ int pcie_card_link; -+}; -+ -+static struct mtk_pcie_port_data { -+ u32 base; -+ u32 perst_n; -+ u32 interrupt_en; -+} mtk_pcie_port_data[MAX_PORT_NUM] = { -+ { PCIEP0_BASE, BIT(1), BIT(20) }, -+ { PCIEP1_BASE, BIT(2), BIT(21) }, -+ { PCIEP2_BASE, BIT(3), BIT(22) }, -+}; -+ -+static const struct mtk_phy_init { -+ uint32_t reg; -+ uint32_t mask; -+ uint32_t val; -+} mtk_phy_init[] = { -+ { MTK_PHY_REFCLK_SEL, MTK_PHY_XTAL_EXT_EN_MASK, MTK_PHY_XTAL_EXT_EN }, -+ { MTK_PHY_PLL, MTK_PHY_CLKDRV_AMP_MASK, MTK_PHY_CLKDRV_AMP }, -+ { MTK_PHY_CLK, MTK_PHY_CLKDRV_OFFSET_MASK, MTK_PHY_CLKDRV_OFFSET }, -+ { MTK_PHY_SSC_DELTA1, MTK_PHY_SSC_DELTA1_PE2H_MASK, MTK_PHY_SSC_DELTA1_PE2H }, -+ { MTK_PHY_SSC_DELTA, MTK_PHY_SSC_DELTA_PE2H_MASK, MTK_PHY_SSC_DELTA_PE2H }, -+ { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_BR_PE2H_MASK, MTK_PHY_PLL_IC_BR_PE2H }, -+ { MTK_PHY_PLL_BC, MTK_PHY_PLL_BC_PE2H_MASK, MTK_PHY_PLL_BC_PE2H }, -+ { MTK_PHY_PLL_IR, MTK_PHY_PLL_IR_PE2H_MASK, MTK_PHY_PLL_IR_PE2H }, -+ { MTK_PHY_PLL_IC, MTK_PHY_PLL_IC_PE2H_MASK, MTK_PHY_PLL_IC_PE2H }, -+ { MTK_PHY_PLL_BP, MTK_PHY_PLL_BP_PE2H_MASK, MTK_PHY_PLL_BP_PE2H }, -+}; -+ -+static struct mtk_pcie *sys_to_pcie(struct pci_sys_data *sys) -+{ -+ return sys->private_data; -+} -+ -+static void pcie_w32(struct mtk_pcie *pcie, u32 val, unsigned reg) -+{ -+ iowrite32(val, pcie->pcie_base + reg); -+} -+ -+static u32 pcie_r32(struct mtk_pcie *pcie, unsigned reg) -+{ -+ return ioread32(pcie->pcie_base + reg); -+} -+ -+static void pcie_m32(struct mtk_pcie *pcie, u32 mask, u32 val, unsigned reg) -+{ -+ u32 v = pcie_r32(pcie, reg); -+ -+ v &= mask; -+ v |= val; -+ pcie_w32(pcie, v, reg); -+} -+ -+static int pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where, -+ int size, u32 *val) -+{ -+ struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata); -+ unsigned int slot = PCI_SLOT(devfn); -+ u8 func = PCI_FUNC(devfn); -+ u32 address; -+ u32 data; -+ u32 num = 0; -+ -+ if (bus) -+ num = bus->number; -+ -+ address = (((where & 0xf00) >> 8) << 24) | -+ (num << 16) | -+ (slot << 11) | -+ (func << 8) | -+ (where & 0xfc); -+ -+ pcie_w32(pcie, address, CFGADDR); -+ data = pcie_r32(pcie, CFGDATA); -+ -+ switch (size) { -+ case 1: -+ *val = (data >> ((where & 3) << 3)) & 0xff; -+ break; -+ case 2: -+ *val = (data >> ((where & 3) << 3)) & 0xffff; -+ break; -+ case 4: -+ *val = data; -+ break; -+ } -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int pcie_config_write(struct pci_bus *bus, unsigned int devfn, int where, -+ int size, u32 val) -+{ -+ struct mtk_pcie *pcie = sys_to_pcie(bus->sysdata); -+ unsigned int slot = PCI_SLOT(devfn); -+ u8 func = PCI_FUNC(devfn); -+ u32 address; -+ u32 data; -+ u32 num = 0; -+ -+ if (bus) -+ num = bus->number; -+ -+ address = (((where & 0xf00) >> 8) << 24) | -+ (num << 16) | (slot << 11) | (func << 8) | (where & 0xfc); -+ pcie_w32(pcie, address, CFGADDR); -+ data = pcie_r32(pcie, CFGDATA); -+ -+ switch (size) { -+ case 1: -+ data = (data & ~(0xff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ break; -+ case 2: -+ data = (data & ~(0xffff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ break; -+ case 4: -+ data = val; -+ break; -+ } -+ pcie_w32(pcie, data, CFGDATA); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static struct pci_ops mtk_pcie_ops = { -+ .read = pcie_config_read, -+ .write = pcie_config_write, -+}; -+ -+static int __init mtk_pcie_setup(int nr, struct pci_sys_data *sys) -+{ -+ struct mtk_pcie *pcie = sys_to_pcie(sys); -+ -+ request_resource(&ioport_resource, &pcie->pio); -+ request_resource(&iomem_resource, &pcie->mem); -+ -+ pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); -+ pci_add_resource_offset(&sys->resources, &pcie->pio, sys->io_offset); -+ pci_add_resource(&sys->resources, &pcie->busn); -+ -+ return 1; -+} -+ -+static struct pci_bus * __init mtk_pcie_scan_bus(int nr, -+ struct pci_sys_data *sys) -+{ -+ struct mtk_pcie *pcie = sys_to_pcie(sys); -+ struct pci_bus *bus; -+ -+ bus = pci_create_root_bus(pcie->dev, sys->busnr, &mtk_pcie_ops, sys, -+ &sys->resources); -+ if (!bus) -+ return NULL; -+ -+ pci_scan_child_bus(bus); -+ -+ return bus; -+} -+ -+static int __init mtk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ struct mtk_pcie *pcie = sys_to_pcie(dev->bus->sysdata); -+ struct mtk_pcie_port *port; -+ int irq = -1; -+ -+ mtk_foreach_port(pcie, port) -+ if (port->id == slot) -+ irq = port->irq; -+ -+ return irq; -+} -+ -+static void mtk_pcie_configure_phy(struct mtk_pcie *pcie, -+ struct mtk_pcie_port *port) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mtk_phy_init); i++) { -+ void __iomem *phy_addr = port->phy_base + mtk_phy_init[i].reg; -+ u32 val = ioread32(phy_addr); -+ -+ val &= ~mtk_phy_init[i].mask; -+ val |= mtk_phy_init[i].val; -+ iowrite32(val, phy_addr); -+ } -+ usleep_range(5000, 6000); -+} -+ -+static void mtk_pcie_configure_rc(struct mtk_pcie *pcie, -+ struct mtk_pcie_port *port, -+ struct pci_bus *bus) -+{ -+ u32 val = 0; -+ -+ pcie_config_write(bus, -+ port->id << 3, -+ PCI_BASE_ADDRESS_0, 4, MEMORY_BASE); -+ -+ pcie_config_read(bus, -+ port->id << 3, PCI_BASE_ADDRESS_0, 4, &val); -+ -+ /* Configure RC Credit */ -+ pcie_config_read(bus, port->id << 3, 0x73c, 4, &val); -+ val &= ~(0x9fff) << 16; -+ val |= 0x806c << 16; -+ pcie_config_write(bus, port->id << 3, 0x73c, 4, val); -+ -+ /* Configure RC FTS number */ -+ pcie_config_read(bus, port->id << 3, 0x70c, 4, &val); -+ val &= ~(0xff3) << 8; -+ val |= 0x50 << 8; -+ pcie_config_write(bus, port->id << 3, 0x70c, 4, val); -+} -+ -+static int mtk_pcie_preinit(struct mtk_pcie *pcie) -+{ -+ struct mtk_pcie_port *port; -+ u32 val = 0; -+ struct pci_bus bus; -+ struct pci_sys_data sys; -+ -+ memset(&bus, 0, sizeof(bus)); -+ memset(&sys, 0, sizeof(sys)); -+ bus.sysdata = (void *)&sys; -+ sys.private_data = (void *)pcie; -+ -+ pcibios_min_io = 0; -+ pcibios_min_mem = 0; -+ -+ /* The PHY on Port 2 is shared with USB */ -+ if (pcie->port[2].enable) -+ regmap_update_bits(pcie->hifsys, HIFSYS_SYSCFG1, -+ HIFSYS_SYSCFG1_PHY2_MASK, 0x0); -+ -+ /* PCIe RC Reset */ -+ mtk_foreach_port(pcie, port) -+ if (port->enable) -+ reset_control_assert(port->rstc); -+ usleep_range(1000, 2000); -+ mtk_foreach_port(pcie, port) -+ if (port->enable) -+ reset_control_deassert(port->rstc); -+ usleep_range(1000, 2000); -+ -+ /* Configure PCIe PHY */ -+ mtk_foreach_port(pcie, port) -+ if (port->enable) -+ mtk_pcie_configure_phy(pcie, port); -+ -+ /* PCIe EP reset */ -+ val = 0; -+ mtk_foreach_port(pcie, port) -+ if (port->enable) -+ val |= mtk_pcie_port_data[port->id].perst_n; -+ pcie_w32(pcie, pcie_r32(pcie, PCICFG) | val, PCICFG); -+ usleep_range(1000, 2000); -+ pcie_w32(pcie, pcie_r32(pcie, PCICFG) & ~val, PCICFG); -+ usleep_range(1000, 2000); -+ msleep(100); -+ -+ /* check the link status */ -+ val = 0; -+ mtk_foreach_port(pcie, port) { -+ if (port->enable) { -+ u32 base = mtk_pcie_port_data[port->id].base; -+ -+ if ((pcie_r32(pcie, base + PCIE_SISTAT) & 0x1)) -+ port->link = 1; -+ else -+ reset_control_assert(port->rstc); -+ } -+ } -+ -+ mtk_foreach_port(pcie, port) -+ if (port->link) -+ pcie->pcie_card_link++; -+ -+ if (!pcie->pcie_card_link) -+ return -ENODEV; -+ -+ pcie_w32(pcie, pcie->mem_bus_addr, MEMBASE); -+ pcie_w32(pcie, pcie->io_bus_addr, IOBASE); -+ -+ mtk_foreach_port(pcie, port) { -+ if (port->link) { -+ u32 base = mtk_pcie_port_data[port->id].base; -+ u32 inte = mtk_pcie_port_data[port->id].interrupt_en; -+ -+ pcie_m32(pcie, 0, inte, PCIENA); -+ pcie_w32(pcie, 0x7fff0001, base + BAR0SETUP); -+ pcie_w32(pcie, MEMORY_BASE, base + IMBASEBAR0); -+ pcie_w32(pcie, 0x06040001, base + PCIE_CLASS); -+ } -+ } -+ -+ mtk_foreach_port(pcie, port) -+ if (port->link) -+ mtk_pcie_configure_rc(pcie, port, &bus); -+ -+ return 0; -+} -+ -+static int mtk_pcie_parse_dt(struct mtk_pcie *pcie) -+{ -+ struct device_node *np = pcie->dev->of_node, *port; -+ struct of_pci_range_parser parser; -+ struct of_pci_range range; -+ struct resource res; -+ int err; -+ -+ pcie->hifsys = syscon_regmap_lookup_by_phandle(np, "mediatek,hifsys"); -+ if (IS_ERR(pcie->hifsys)) { -+ dev_err(pcie->dev, "missing \"mediatek,hifsys\" phandle\n"); -+ return PTR_ERR(pcie->hifsys); -+ } -+ -+ if (of_pci_range_parser_init(&parser, np)) { -+ dev_err(pcie->dev, "missing \"ranges\" property\n"); -+ return -EINVAL; -+ } -+ -+ for_each_of_pci_range(&parser, &range) { -+ err = of_pci_range_to_resource(&range, np, &res); -+ if (err < 0) { -+ dev_err(pcie->dev, "failed to read resource range\n"); -+ return err; -+ } -+ -+ switch (res.flags & IORESOURCE_TYPE_BITS) { -+ case IORESOURCE_IO: -+ memcpy(&pcie->pio, &res, sizeof(res)); -+ pcie->pio.start = (resource_size_t)range.pci_addr; -+ pcie->pio.end = (resource_size_t) -+ (range.pci_addr + range.size - 1); -+ pcie->io_bus_addr = (resource_size_t)range.cpu_addr; -+ break; -+ -+ case IORESOURCE_MEM: -+ if (res.flags & IORESOURCE_PREFETCH) { -+ memcpy(&pcie->prefetch, &res, sizeof(res)); -+ pcie->prefetch.name = "prefetchable"; -+ pcie->prefetch.start = -+ (resource_size_t)range.pci_addr; -+ pcie->prefetch.end = (resource_size_t) -+ (range.pci_addr + range.size - 1); -+ } else { -+ memcpy(&pcie->mem, &res, sizeof(res)); -+ pcie->mem.name = "non-prefetchable"; -+ pcie->mem.start = (resource_size_t) -+ range.pci_addr; -+ pcie->prefetch.end = (resource_size_t) -+ (range.pci_addr + range.size - 1); -+ pcie->mem_bus_addr = (resource_size_t) -+ range.cpu_addr; -+ } -+ break; -+ } -+ } -+ -+ err = of_pci_parse_bus_range(np, &pcie->busn); -+ if (err < 0) { -+ dev_err(pcie->dev, "failed to parse ranges property: %d\n", -+ err); -+ pcie->busn.name = np->name; -+ pcie->busn.start = 0; -+ pcie->busn.end = 0xff; -+ pcie->busn.flags = IORESOURCE_BUS; -+ } -+ -+ /* parse root ports */ -+ for_each_child_of_node(np, port) { -+ unsigned int index; -+ char rst[] = "pcie0"; -+ -+ err = of_pci_get_devfn(port); -+ if (err < 0) { -+ dev_err(pcie->dev, "failed to parse address: %d\n", -+ err); -+ return err; -+ } -+ -+ index = PCI_SLOT(err); -+ if (index > MAX_PORT_NUM) { -+ dev_err(pcie->dev, "invalid port number: %d\n", index); -+ continue; -+ } -+ index--; -+ pcie->port[index].id = index; -+ -+ if (!of_device_is_available(port)) -+ continue; -+ -+ rst[4] += index; -+ pcie->port[index].rstc = devm_reset_control_get(pcie->dev, -+ rst); -+ if (!IS_ERR(pcie->port[index].rstc)) -+ pcie->port[index].enable = 1; -+ } -+ return 0; -+} -+ -+static int mtk_pcie_get_resources(struct mtk_pcie *pcie) -+{ -+ struct platform_device *pdev = to_platform_device(pcie->dev); -+ struct mtk_pcie_port *port; -+ struct resource *res; -+ -+ pcie->clk = devm_clk_get(&pdev->dev, "pcie"); -+ if (IS_ERR(pcie->clk)) { -+ dev_err(&pdev->dev, "Failed to get pcie clk\n"); -+ return PTR_ERR(pcie->clk); -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ pcie->pcie_base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(pcie->pcie_base)) { -+ dev_err(&pdev->dev, "Failed to get pcie range\n"); -+ return PTR_ERR(pcie->pcie_base); -+ } -+ -+ mtk_foreach_port(pcie, port) { -+ if (!port->enable) -+ continue; -+ res = platform_get_resource(pdev, IORESOURCE_MEM, port->id + 1); -+ port->phy_base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(port->phy_base)) { -+ dev_err(&pdev->dev, "Failed to get pcie phy%d range %p\n", -+ port->id, port->phy_base); -+ return PTR_ERR(port->phy_base); -+ } -+ port->irq = platform_get_irq(pdev, port->id); -+ } -+ -+ return clk_prepare_enable(pcie->clk); -+} -+ -+static int mtk_pcie_probe(struct platform_device *pdev) -+{ -+ struct mtk_pcie *pcie; -+ struct hw_pci hw; -+ int ret; -+ -+ pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); -+ if (!pcie) -+ return -ENOMEM; -+ -+ pcie->dev = &pdev->dev; -+ ret = mtk_pcie_parse_dt(pcie); -+ if (ret < 0) -+ return ret; -+ -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_sync(&pdev->dev); -+ -+ ret = mtk_pcie_get_resources(pcie); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to request resources: %d\n", ret); -+ goto err_out; -+ } -+ -+ ret = mtk_pcie_preinit(pcie); -+ if (ret) -+ return ret; -+ -+ memset(&hw, 0, sizeof(hw)); -+ hw.nr_controllers = 1; -+ hw.private_data = (void **)&pcie; -+ hw.setup = mtk_pcie_setup; -+ hw.map_irq = mtk_pcie_map_irq; -+ hw.scan = mtk_pcie_scan_bus; -+ -+ pci_common_init_dev(pcie->dev, &hw); -+ platform_set_drvdata(pdev, pcie); -+ -+ return 0; -+ -+err_out: -+ clk_disable_unprepare(pcie->clk); -+ pm_runtime_put_sync(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ -+ return ret; -+} -+ -+static const struct of_device_id mtk_pcie_ids[] = { -+ { .compatible = "mediatek,mt2701-pcie" }, -+ { .compatible = "mediatek,mt7623-pcie" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mtk_pcie_ids); -+ -+static struct platform_driver mtk_pcie_driver = { -+ .probe = mtk_pcie_probe, -+ .driver = { -+ .name = "mediatek-pcie", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(mtk_pcie_ids), -+ }, -+}; -+ -+static int __init mtk_pcie_init(void) -+{ -+ return platform_driver_register(&mtk_pcie_driver); -+} -+ -+module_init(mtk_pcie_init); diff --git a/target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch b/target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch new file mode 100644 index 0000000000..24e13d1a3c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0025-dt-bindings-net-dsa-add-Mediatek-MT7530-binding.patch @@ -0,0 +1,110 @@ +From 3b9b46b5705214b16c5356284ad68be32ae56a26 Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Wed, 29 Mar 2017 17:38:19 +0800 +Subject: [PATCH 25/57] dt-bindings: net: dsa: add Mediatek MT7530 binding + +Add device-tree binding for Mediatek MT7530 switch. + +Cc: devicetree@vger.kernel.org +Signed-off-by: Sean Wang +Acked-by: Rob Herring +--- + .../devicetree/bindings/net/dsa/mt7530.txt | 92 ++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt +@@ -0,0 +1,92 @@ ++Mediatek MT7530 Ethernet switch ++================================ ++ ++Required properties: ++ ++- compatible: Must be compatible = "mediatek,mt7530"; ++- #address-cells: Must be 1. ++- #size-cells: Must be 0. ++- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part ++ on multi-chip module belong to MT7623A has or the remotely standalone ++ chip as the function MT7623N reference board provided for. ++- core-supply: Phandle to the regulator node necessary for the core power. ++- io-supply: Phandle to the regulator node necessary for the I/O power. ++ See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt ++ for details for the regulator setup on these boards. ++ ++If the property mediatek,mcm isn't defined, following property is required ++ ++- reset-gpios: Should be a gpio specifier for a reset line. ++ ++Else, following properties are required ++ ++- resets : Phandle pointing to the system reset controller with ++ line index for the ethsys. ++- reset-names : Should be set to "mcm". ++ ++Required properties for the child nodes within ports container: ++ ++- reg: Port address described must be 6 for CPU port and from 0 to 5 for ++ user ports. ++- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled ++ "cpu". ++ ++See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional ++required, optional properties and how the integrated switch subnodes must ++be specified. ++ ++Example: ++ ++ &mdio0 { ++ switch@0 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ core-supply = <&mt6323_vpa_reg>; ++ io-supply = <&mt6323_vemc3v3_reg>; ++ reset-gpios = <&pio 33 0>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ port@0 { ++ reg = <0>; ++ label = "lan0"; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "wan"; ++ }; ++ ++ port@6 { ++ reg = <6>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "trgmii"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++ }; diff --git a/target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch b/target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch new file mode 100644 index 0000000000..8a6d593624 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0026-net-mediatek-backport-v4.10-driver.patch @@ -0,0 +1,1788 @@ +From 99d9d02a05df503184be094de336e7515fe3e235 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:26:29 +0200 +Subject: [PATCH 26/57] net: mediatek: backport v4.10 driver + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 49 ++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 16 +- + drivers/net/ethernet/mediatek/mtk_hnat/Makefile | 4 + + drivers/net/ethernet/mediatek/mtk_hnat/hnat.c | 315 +++++++++++++++ + drivers/net/ethernet/mediatek/mtk_hnat/hnat.h | 425 +++++++++++++++++++++ + .../net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c | 259 +++++++++++++ + .../net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c | 289 ++++++++++++++ + .../net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h | 44 +++ + 8 files changed, 1378 insertions(+), 23 deletions(-) + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/Makefile + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat.h + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -462,8 +462,8 @@ static void mtk_stats_update(struct mtk_ + } + } + +-static struct rtnl_link_stats64 *mtk_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *storage) ++static struct rtnl_link_stats64 * mtk_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *storage) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; +@@ -615,7 +615,7 @@ static int mtk_tx_map(struct sk_buff *sk + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_dma *itxd, *txd; +- struct mtk_tx_buf *tx_buf; ++ struct mtk_tx_buf *itx_buf, *tx_buf; + dma_addr_t mapped_addr; + unsigned int nr_frags; + int i, n_desc = 1; +@@ -629,8 +629,8 @@ static int mtk_tx_map(struct sk_buff *sk + fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; + txd4 |= fport; + +- tx_buf = mtk_desc_to_tx_buf(ring, itxd); +- memset(tx_buf, 0, sizeof(*tx_buf)); ++ itx_buf = mtk_desc_to_tx_buf(ring, itxd); ++ memset(itx_buf, 0, sizeof(*itx_buf)); + + if (gso) + txd4 |= TX_DMA_TSO; +@@ -649,9 +649,11 @@ static int mtk_tx_map(struct sk_buff *sk + return -ENOMEM; + + WRITE_ONCE(itxd->txd1, mapped_addr); +- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; +- dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); +- dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb)); ++ itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; ++ itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : ++ MTK_TX_FLAGS_FPORT1; ++ dma_unmap_addr_set(itx_buf, dma_addr0, mapped_addr); ++ dma_unmap_len_set(itx_buf, dma_len0, skb_headlen(skb)); + + /* TX SG offload */ + txd = itxd; +@@ -687,11 +689,13 @@ static int mtk_tx_map(struct sk_buff *sk + last_frag * TX_DMA_LS0)); + WRITE_ONCE(txd->txd4, fport); + +- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; + tx_buf = mtk_desc_to_tx_buf(ring, txd); + memset(tx_buf, 0, sizeof(*tx_buf)); +- ++ tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; ++ tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : ++ MTK_TX_FLAGS_FPORT1; ++ + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len0, frag_map_size); + frag_size -= frag_map_size; +@@ -700,7 +704,7 @@ static int mtk_tx_map(struct sk_buff *sk + } + + /* store skb to cleanup */ +- tx_buf->skb = skb; ++ itx_buf->skb = skb; + + WRITE_ONCE(itxd->txd4, txd4); + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | +@@ -845,7 +849,7 @@ static int mtk_start_xmit(struct sk_buff + drop: + spin_unlock(ð->page_lock); + stats->tx_dropped++; +- dev_kfree_skb(skb); ++ dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + +@@ -1014,17 +1018,16 @@ static int mtk_poll_tx(struct mtk_eth *e + + while ((cpu != dma) && budget) { + u32 next_cpu = desc->txd2; +- int mac; ++ int mac = 0; + + desc = mtk_qdma_phys_to_virt(ring, desc->txd2); + if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0) + break; + +- mac = (desc->txd4 >> TX_DMA_FPORT_SHIFT) & +- TX_DMA_FPORT_MASK; +- mac--; +- + tx_buf = mtk_desc_to_tx_buf(ring, desc); ++ if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) ++ mac = 1; ++ + skb = tx_buf->skb; + if (!skb) { + condition = 1; +@@ -1848,6 +1851,12 @@ static int mtk_hw_init(struct mtk_eth *e + /* GE2, Force 1000M/FD, FC ON */ + mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1)); + ++ /* Indicates CDM to parse the MTK special tag from CPU ++ * which also is working out for untag packets. ++ */ ++ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + +@@ -1910,10 +1919,9 @@ static int __init mtk_init(struct net_de + + /* If the mac address is invalid, use random mac address */ + if (!is_valid_ether_addr(dev->dev_addr)) { +- random_ether_addr(dev->dev_addr); ++ eth_hw_addr_random(dev); + dev_err(eth->dev, "generated random MAC address %pM\n", + dev->dev_addr); +- dev->addr_assign_type = NET_ADDR_RANDOM; + } + + return mtk_phy_connect(dev); +@@ -2247,7 +2255,6 @@ static const struct net_device_ops mtk_n + .ndo_set_mac_address = mtk_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mtk_do_ioctl, +- .ndo_change_mtu = eth_change_mtu, + .ndo_tx_timeout = mtk_tx_timeout, + .ndo_get_stats64 = mtk_get_stats64, + .ndo_fix_features = mtk_fix_features, +@@ -2320,6 +2327,8 @@ static int mtk_add_mac(struct mtk_eth *e + eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; + + eth->netdev[id]->irq = eth->irq[0]; ++ eth->netdev[id]->dev.of_node = np; ++ + return 0; + + free_netdev: +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -70,6 +70,10 @@ + /* Frame Engine Interrupt Grouping Register */ + #define MTK_FE_INT_GRP 0x20 + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMQ_IG_CTRL 0x1400 ++#define MTK_CDMQ_STAG_EN BIT(0) ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + +@@ -406,12 +410,18 @@ struct mtk_hw_stats { + struct u64_stats_sync syncp; + }; + +-/* PDMA descriptor can point at 1-2 segments. This enum allows us to track how +- * memory was allocated so that it can be freed properly +- */ + enum mtk_tx_flags { ++ /* PDMA descriptor can point at 1-2 segments. This enum allows us to ++ * track how memory was allocated so that it can be freed properly. ++ */ + MTK_TX_FLAGS_SINGLE0 = 0x01, + MTK_TX_FLAGS_PAGE0 = 0x02, ++ ++ /* MTK_TX_FLAGS_FPORTx allows tracking which port the transmitted ++ * SKB out instead of looking up through hardware TX descriptor. ++ */ ++ MTK_TX_FLAGS_FPORT0 = 0x04, ++ MTK_TX_FLAGS_FPORT1 = 0x08, + }; + + /* This enum allows us to identify how the clock is defined on the array of the +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/Makefile +@@ -0,0 +1,4 @@ ++ccflags-y=-Werror ++ ++obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtkhnat.o ++mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c +@@ -0,0 +1,315 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hnat.h" ++ ++struct hnat_priv *host; ++ ++static void cr_set_bits(void __iomem * reg, u32 bs) ++{ ++ u32 val = readl(reg); ++ ++ val |= bs; ++ writel(val, reg); ++} ++ ++static void cr_clr_bits(void __iomem * reg, u32 bs) ++{ ++ u32 val = readl(reg); ++ ++ val &= ~bs; ++ writel(val, reg); ++} ++ ++static void cr_set_field(void __iomem * reg, u32 field, u32 val) ++{ ++ unsigned int tv = readl(reg); ++ ++ tv &= ~field; ++ tv |= ((val) << (ffs((unsigned int)field) - 1)); ++ writel(tv, reg); ++} ++ ++static int hnat_start(void) ++{ ++ u32 foe_table_sz; ++ ++ /* mapp the FOE table */ ++ foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry); ++ host->foe_table_cpu = ++ dma_alloc_coherent(host->dev, foe_table_sz, &host->foe_table_dev, ++ GFP_KERNEL); ++ if (!host->foe_table_cpu) ++ return -1; ++ ++ writel(host->foe_table_dev, host->ppe_base + PPE_TB_BASE); ++ memset(host->foe_table_cpu, 0, foe_table_sz); ++ ++ /* setup hashing */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ETRY_NUM, TABLE_4K); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, HASH_MODE, HASH_MODE_1); ++ writel(HASH_SEED_KEY, host->ppe_base + PPE_HASH_SEED); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, XMODE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TB_ENTRY_SIZE, ENTRY_64B); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, SMA, SMA_FWD_CPU_BUILD_ENTRY); ++ ++ /* set ip proto */ ++ writel(0xFFFFFFFF, host->ppe_base + PPE_IP_PROT_CHK); ++ ++ /* setup caching */ ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 1); ++ ++ /* enable FOE */ ++ cr_set_bits(host->ppe_base + PPE_FLOW_CFG, ++ BIT_IPV4_NAT_EN | BIT_IPV4_NAPT_EN | ++ BIT_IPV4_NAT_FRAG_EN | BIT_IPV4_HASH_GREK); ++ ++ /* setup FOE aging */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_MNP, 1000); ++ cr_set_field(host->ppe_base + PPE_UNB_AGE, UNB_DLTA, 3); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 1); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_0, UDP_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_0, NTU_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_1, FIN_DLTA, 5); ++ cr_set_field(host->ppe_base + PPE_BND_AGE_1, TCP_DLTA, 5); ++ ++ /* setup FOE ka */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, KA_CFG, 3); ++ cr_set_field(host->ppe_base + PPE_KA, KA_T, 1); ++ cr_set_field(host->ppe_base + PPE_KA, TCP_KA, 1); ++ cr_set_field(host->ppe_base + PPE_KA, UDP_KA, 1); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_1, NTU_KA, 1); ++ ++ /* setup FOE rate limit */ ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_0, QURT_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_0, HALF_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BIND_LMT_1, FULL_LMT, 16383); ++ cr_set_field(host->ppe_base + PPE_BNDR, BIND_RATE, 1); ++ ++ /* setup FOE cf gen */ ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 1); ++ writel(0, host->ppe_base + PPE_DFT_CPORT); // pdma ++ //writel(0x55555555, host->ppe_base + PPE_DFT_CPORT); //qdma ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, TTL0_DRP, 1); ++ ++ /* fwd packets from gmac to PPE */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_PPE); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_PPE); ++ ++ dev_info(host->dev, "hwnat start\n"); ++ ++ return 0; ++} ++ ++static int ppe_busy_wait(void) ++{ ++ unsigned long t_start = jiffies; ++ u32 r = 0; ++ ++ while (1) { ++ r = readl((host->ppe_base + 0x0)); ++ if (!(r & BIT(31))) ++ return 0; ++ if (time_after(jiffies, t_start + HZ)) ++ break; ++ usleep_range(10, 20); ++ } ++ ++ dev_err(host->dev, "ppe:%s timeout\n", __func__); ++ ++ return -1; ++} ++ ++static void hnat_stop(void) ++{ ++ u32 foe_table_sz; ++ struct foe_entry *entry, *end; ++ u32 r1 = 0, r2 = 0; ++ ++ /* discard all traffic while we disable the PPE */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_DISCARD); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_DISCARD); ++ ++ if (ppe_busy_wait()) { ++ reset_control_reset(host->rstc); ++ msleep(2000); ++ return; ++ } ++ ++ entry = host->foe_table_cpu; ++ end = host->foe_table_cpu + FOE_4TB_SIZ; ++ while (entry < end) { ++ entry->bfib1.state = INVALID; ++ entry++; ++ } ++ ++ /* disable caching */ ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 1); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_X_MODE, 0); ++ cr_set_field(host->ppe_base + PPE_CAH_CTRL, CAH_EN, 0); ++ ++ /* flush cache has to be ahead of hnat diable --*/ ++ cr_set_field(host->ppe_base + PPE_GLO_CFG, PPE_EN, 0); ++ ++ /* disable FOE */ ++ cr_clr_bits(host->ppe_base + PPE_FLOW_CFG, ++ BIT_IPV4_NAPT_EN | BIT_IPV4_NAT_EN | ++ BIT_IPV4_NAT_FRAG_EN | ++ BIT_FUC_FOE | BIT_FMC_FOE | BIT_FUC_FOE); ++ ++ /* disable FOE aging */ ++ cr_set_field(host->ppe_base + PPE_TB_CFG, NTU_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UNBD_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, TCP_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, UDP_AGE, 0); ++ cr_set_field(host->ppe_base + PPE_TB_CFG, FIN_AGE, 0); ++ ++ r1 = readl(host->fe_base + 0x100); ++ r2 = readl(host->fe_base + 0x10c); ++ ++ dev_info(host->dev, "0x100 = 0x%x, 0x10c = 0x%x\n", r1, r2); ++ ++ if (((r1 & 0xff00) >> 0x8) >= (r1 & 0xff) || ++ ((r1 & 0xff00) >> 0x8) >= (r2 & 0xff)) { ++ dev_info(host->dev, "reset pse\n"); ++ writel(0x1, host->fe_base + 0x4); ++ } ++ ++ /* free the FOE table */ ++ foe_table_sz = FOE_4TB_SIZ * sizeof(struct foe_entry); ++ dma_free_coherent(NULL, foe_table_sz, host->foe_table_cpu, ++ host->foe_table_dev); ++ writel(0, host->ppe_base + PPE_TB_BASE); ++ ++ if (ppe_busy_wait()) { ++ reset_control_reset(host->rstc); ++ msleep(2000); ++ return; ++ } ++ ++ /* send all traffic back to the DMA engine */ ++ cr_clr_bits(host->fe_base + GDMA1_FWD_CFG, GDM1_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA1_FWD_CFG, ++ BITS_GDM1_ALL_FRC_P_CPU_PDMA); ++ cr_clr_bits(host->fe_base + GDMA2_FWD_CFG, GDM2_ALL_FRC_MASK); ++ cr_set_bits(host->fe_base + GDMA2_FWD_CFG, ++ BITS_GDM2_ALL_FRC_P_CPU_PDMA); ++} ++ ++static int hnat_probe(struct platform_device *pdev) ++{ ++ int err = 0; ++ struct resource *res ; ++ const char *name; ++ struct device_node *np; ++ ++ host = devm_kzalloc(&pdev->dev, sizeof(struct hnat_priv), GFP_KERNEL); ++ if (!host) ++ return -ENOMEM; ++ ++ host->dev = &pdev->dev; ++ np = host->dev->of_node; ++ ++ err = of_property_read_string(np, "mtketh-wan", &name); ++ if (err < 0) ++ return -EINVAL; ++ ++ strncpy(host->wan, (char *)name, IFNAMSIZ); ++ dev_info(&pdev->dev, "wan = %s\n", host->wan); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENOENT; ++ ++ host->fe_base = devm_ioremap_nocache(&pdev->dev, res->start, ++ res->end - res->start + 1); ++ if (!host->fe_base) ++ return -EADDRNOTAVAIL; ++ ++ host->ppe_base = host->fe_base + 0xe00; ++ err = hnat_init_debugfs(host); ++ if (err) ++ return err; ++ ++ host->rstc = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(host->rstc)) ++ return PTR_ERR(host->rstc); ++ ++ err = hnat_start(); ++ if (err) ++ goto err_out; ++ ++ err = hnat_register_nf_hooks(); ++ if (err) ++ goto err_out; ++ ++ return 0; ++ ++err_out: ++ hnat_stop(); ++ hnat_deinit_debugfs(host); ++ return err; ++} ++ ++static int hnat_remove(struct platform_device *pdev) ++{ ++ hnat_unregister_nf_hooks(); ++ hnat_stop(); ++ hnat_deinit_debugfs(host); ++ ++ return 0; ++} ++ ++const struct of_device_id of_hnat_match[] = { ++ { .compatible = "mediatek,mt7623-hnat" }, ++ {}, ++}; ++ ++static struct platform_driver hnat_driver = { ++ .probe = hnat_probe, ++ .remove = hnat_remove, ++ .driver = { ++ .name = "mediatek_soc_hnat", ++ .of_match_table = of_hnat_match, ++ }, ++}; ++ ++module_platform_driver(hnat_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_AUTHOR("John Crispin "); ++MODULE_DESCRIPTION("Mediatek Hardware NAT"); +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h +@@ -0,0 +1,425 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/*--------------------------------------------------------------------------*/ ++/* Register Offset*/ ++/*--------------------------------------------------------------------------*/ ++#define PPE_GLO_CFG 0x00 ++#define PPE_FLOW_CFG 0x04 ++#define PPE_IP_PROT_CHK 0x08 ++#define PPE_IP_PROT_0 0x0C ++#define PPE_IP_PROT_1 0x10 ++#define PPE_IP_PROT_2 0x14 ++#define PPE_IP_PROT_3 0x18 ++#define PPE_TB_CFG 0x1C ++#define PPE_TB_BASE 0x20 ++#define PPE_TB_USED 0x24 ++#define PPE_BNDR 0x28 ++#define PPE_BIND_LMT_0 0x2C ++#define PPE_BIND_LMT_1 0x30 ++#define PPE_KA 0x34 ++#define PPE_UNB_AGE 0x38 ++#define PPE_BND_AGE_0 0x3C ++#define PPE_BND_AGE_1 0x40 ++#define PPE_HASH_SEED 0x44 ++#define PPE_DFT_CPORT 0x48 ++#define PPE_MCAST_PPSE 0x84 ++#define PPE_MCAST_L_0 0x88 ++#define PPE_MCAST_H_0 0x8C ++#define PPE_MCAST_L_1 0x90 ++#define PPE_MCAST_H_1 0x94 ++#define PPE_MCAST_L_2 0x98 ++#define PPE_MCAST_H_2 0x9C ++#define PPE_MCAST_L_3 0xA0 ++#define PPE_MCAST_H_3 0xA4 ++#define PPE_MCAST_L_4 0xA8 ++#define PPE_MCAST_H_4 0xAC ++#define PPE_MCAST_L_5 0xB0 ++#define PPE_MCAST_H_5 0xB4 ++#define PPE_MCAST_L_6 0xBC ++#define PPE_MCAST_H_6 0xC0 ++#define PPE_MCAST_L_7 0xC4 ++#define PPE_MCAST_H_7 0xC8 ++#define PPE_MCAST_L_8 0xCC ++#define PPE_MCAST_H_8 0xD0 ++#define PPE_MCAST_L_9 0xD4 ++#define PPE_MCAST_H_9 0xD8 ++#define PPE_MCAST_L_A 0xDC ++#define PPE_MCAST_H_A 0xE0 ++#define PPE_MCAST_L_B 0xE4 ++#define PPE_MCAST_H_B 0xE8 ++#define PPE_MCAST_L_C 0xEC ++#define PPE_MCAST_H_C 0xF0 ++#define PPE_MCAST_L_D 0xF4 ++#define PPE_MCAST_H_D 0xF8 ++#define PPE_MCAST_L_E 0xFC ++#define PPE_MCAST_H_E 0xE0 ++#define PPE_MCAST_L_F 0x100 ++#define PPE_MCAST_H_F 0x104 ++#define PPE_MTU_DRP 0x108 ++#define PPE_MTU_VLYR_0 0x10C ++#define PPE_MTU_VLYR_1 0x110 ++#define PPE_MTU_VLYR_2 0x114 ++#define PPE_VPM_TPID 0x118 ++#define PPE_CAH_CTRL 0x120 ++#define PPE_CAH_TAG_SRH 0x124 ++#define PPE_CAH_LINE_RW 0x128 ++#define PPE_CAH_WDATA 0x12C ++#define PPE_CAH_RDATA 0x130 ++ ++#define GDMA1_FWD_CFG 0x500 ++#define GDMA2_FWD_CFG 0x1500 ++/*--------------------------------------------------------------------------*/ ++/* Register Mask*/ ++/*--------------------------------------------------------------------------*/ ++/* PPE_TB_CFG mask */ ++#define TB_ETRY_NUM (0x7 << 0) /* RW */ ++#define TB_ENTRY_SIZE (0x1 << 3) /* RW */ ++#define SMA (0x3 << 4) /* RW */ ++#define NTU_AGE (0x1 << 7) /* RW */ ++#define UNBD_AGE (0x1 << 8) /* RW */ ++#define TCP_AGE (0x1 << 9) /* RW */ ++#define UDP_AGE (0x1 << 10) /* RW */ ++#define FIN_AGE (0x1 << 11) /* RW */ ++#define KA_CFG (0x3<< 12) ++#define HASH_MODE (0x3 << 14) /* RW */ ++#define XMODE (0x3 << 18) /* RW */ ++ ++/*PPE_CAH_CTRL mask*/ ++#define CAH_EN (0x1 << 0) /* RW */ ++#define CAH_X_MODE (0x1 << 9) /* RW */ ++ ++/*PPE_UNB_AGE mask*/ ++#define UNB_DLTA (0xff << 0) /* RW */ ++#define UNB_MNP (0xffff << 16) /* RW */ ++ ++/*PPE_BND_AGE_0 mask*/ ++#define UDP_DLTA (0xffff << 0) /* RW */ ++#define NTU_DLTA (0xffff << 16) /* RW */ ++ ++/*PPE_BND_AGE_1 mask*/ ++#define TCP_DLTA (0xffff << 0) /* RW */ ++#define FIN_DLTA (0xffff << 16) /* RW */ ++ ++/*PPE_KA mask*/ ++#define KA_T (0xffff << 0) /* RW */ ++#define TCP_KA (0xff << 16) /* RW */ ++#define UDP_KA (0xff << 24) /* RW */ ++ ++/*PPE_BIND_LMT_0 mask*/ ++#define QURT_LMT (0x3ff << 0) /* RW */ ++#define HALF_LMT (0x3ff << 16) /* RW */ ++ ++/*PPE_BIND_LMT_1 mask*/ ++#define FULL_LMT (0x3fff << 0) /* RW */ ++#define NTU_KA (0xff << 16) /* RW */ ++ ++/*PPE_BNDR mask*/ ++#define BIND_RATE (0xffff << 0) /* RW */ ++#define PBND_RD_PRD (0xffff << 16) /* RW */ ++ ++/*PPE_GLO_CFG mask*/ ++#define PPE_EN (0x1 << 0) /* RW */ ++#define TTL0_DRP (0x1 << 4) /* RW */ ++ ++/*GDMA1_FWD_CFG mask */ ++#define GDM1_UFRC_MASK (0x7 << 12) /* RW */ ++#define GDM1_BFRC_MASK (0x7 << 8) /*RW*/ ++#define GDM1_MFRC_MASK (0x7 << 4) /*RW*/ ++#define GDM1_OFRC_MASK (0x7 << 0) /*RW*/ ++#define GDM1_ALL_FRC_MASK (GDM1_UFRC_MASK | GDM1_BFRC_MASK | GDM1_MFRC_MASK | GDM1_OFRC_MASK) ++ ++#define GDM2_UFRC_MASK (0x7 << 12) /* RW */ ++#define GDM2_BFRC_MASK (0x7 << 8) /*RW*/ ++#define GDM2_MFRC_MASK (0x7 << 4) /*RW*/ ++#define GDM2_OFRC_MASK (0x7 << 0) /*RW*/ ++#define GDM2_ALL_FRC_MASK (GDM2_UFRC_MASK | GDM2_BFRC_MASK | GDM2_MFRC_MASK | GDM2_OFRC_MASK) ++ ++/*--------------------------------------------------------------------------*/ ++/* Descriptor Structure */ ++/*--------------------------------------------------------------------------*/ ++#define HNAT_SKB_CB(__skb) ((struct hnat_skb_cb *)&((__skb)->cb[40])) ++struct hnat_skb_cb { ++ __u16 iif; ++}; ++ ++struct hnat_unbind_info_blk { ++ u32 time_stamp:8; ++ u32 pcnt:16; /* packet count */ ++ u32 preb:1; ++ u32 pkt_type:3; ++ u32 state:2; ++ u32 udp:1; ++ u32 sta:1; /* static entry */ ++} __attribute__ ((packed)); ++ ++struct hnat_bind_info_blk { ++ u32 time_stamp:15; ++ u32 ka:1; /* keep alive */ ++ u32 vlan_layer:3; ++ u32 psn:1; /* egress packet has PPPoE session */ ++ u32 vpm:1; /* 0:ethertype remark, 1:0x8100(CR default) */ ++ u32 ps:1; /* packet sampling */ ++ u32 cah:1; /* cacheable flag */ ++ u32 rmt:1; /* remove tunnel ip header (6rd/dslite only) */ ++ u32 ttl:1; ++ u32 pkt_type:3; ++ u32 state:2; ++ u32 udp:1; ++ u32 sta:1; /* static entry */ ++} __attribute__ ((packed)); ++ ++struct hnat_info_blk2 { ++ u32 qid:4; /* QID in Qos Port */ ++ u32 fqos:1; /* force to PSE QoS port */ ++ u32 dp:3; /* force to PSE port x ++ 0:PSE,1:GSW, 2:GMAC,4:PPE,5:QDMA,7=DROP */ ++ u32 mcast:1; /* multicast this packet to CPU */ ++ u32 pcpl:1; /* OSBN */ ++ u32 mlen:1; /* 0:post 1:pre packet length in meter */ ++ u32 alen:1; /* 0:post 1:pre packet length in accounting */ ++ u32 port_mg:6; /* port meter group */ ++ u32 port_ag:6; /* port account group */ ++ u32 dscp:8; /* DSCP value */ ++} __attribute__ ((packed)); ++ ++struct hnat_ipv4_hnapt { ++ union { ++ struct hnat_bind_info_blk bfib1; ++ struct hnat_unbind_info_blk udib1; ++ u32 info_blk1; ++ }; ++ u32 sip; ++ u32 dip; ++ u16 dport; ++ u16 sport; ++ union { ++ struct hnat_info_blk2 iblk2; ++ u32 info_blk2; ++ }; ++ u32 new_sip; ++ u32 new_dip; ++ u16 new_dport; ++ u16 new_sport; ++ u32 resv1; ++ u32 resv2; ++ u32 resv3:26; ++ u32 act_dp:6; /* UDF */ ++ u16 vlan1; ++ u16 etype; ++ u32 dmac_hi; ++ u16 vlan2; ++ u16 dmac_lo; ++ u32 smac_hi; ++ u16 pppoe_id; ++ u16 smac_lo; ++} __attribute__ ((packed)); ++ ++struct foe_entry { ++ union { ++ struct hnat_unbind_info_blk udib1; ++ struct hnat_bind_info_blk bfib1; ++ struct hnat_ipv4_hnapt ipv4_hnapt; ++ }; ++}; ++ ++#define HNAT_AC_BYTE_LO(x) (0x2000 + (x * 16)) ++#define HNAT_AC_BYTE_HI(x) (0x2004 + (x * 16)) ++#define HNAT_AC_PACKET(x) (0x2008 + (x * 16)) ++#define HNAT_COUNTER_MAX 64 ++#define HNAT_AC_TIMER_INTERVAL (HZ) ++ ++struct hnat_accounting { ++ u64 bytes; ++ u64 packets; ++}; ++ ++struct hnat_priv { ++ struct device *dev; ++ void __iomem *fe_base; ++ void __iomem *ppe_base; ++ struct foe_entry *foe_table_cpu; ++ dma_addr_t foe_table_dev; ++ u8 enable; ++ u8 enable1; ++ struct dentry *root; ++ struct debugfs_regset32 *regset; ++ ++ struct timer_list ac_timer; ++ struct hnat_accounting acct[HNAT_COUNTER_MAX]; ++ ++ /*devices we plays for*/ ++ char wan[IFNAMSIZ]; ++ ++ struct reset_control *rstc; ++}; ++ ++enum FoeEntryState { ++ INVALID = 0, ++ UNBIND = 1, ++ BIND = 2, ++ FIN = 3 ++}; ++/*--------------------------------------------------------------------------*/ ++/* Common Definition*/ ++/*--------------------------------------------------------------------------*/ ++ ++#define FOE_4TB_SIZ 4096 ++#define HASH_SEED_KEY 0x12345678 ++ ++/*PPE_TB_CFG value*/ ++#define ENTRY_80B 1 ++#define ENTRY_64B 0 ++#define TABLE_1K 0 ++#define TABLE_2K 1 ++#define TABLE_4K 2 ++#define TABLE_8K 3 ++#define TABLE_16K 4 ++#define SMA_DROP 0 /* Drop the packet */ ++#define SMA_DROP2 1 /* Drop the packet */ ++#define SMA_ONLY_FWD_CPU 2 /* Only Forward to CPU */ ++#define SMA_FWD_CPU_BUILD_ENTRY 3 /* Forward to CPU and build new FOE entry */ ++#define HASH_MODE_0 0 ++#define HASH_MODE_1 1 ++#define HASH_MODE_2 2 ++#define HASH_MODE_3 3 ++ ++/*PPE_FLOW_CFG*/ ++#define BIT_FUC_FOE BIT(2) ++#define BIT_FMC_FOE BIT(1) ++#define BIT_FBC_FOE BIT(0) ++#define BIT_IPV4_NAT_EN BIT(12) ++#define BIT_IPV4_NAPT_EN BIT(13) ++#define BIT_IPV4_NAT_FRAG_EN BIT(17) ++#define BIT_IPV4_HASH_GREK BIT(19) ++ ++/*GDMA1_FWD_CFG value */ ++#define BITS_GDM1_UFRC_P_PPE (NR_PPE_PORT << 12) ++#define BITS_GDM1_BFRC_P_PPE (NR_PPE_PORT << 8) ++#define BITS_GDM1_MFRC_P_PPE (NR_PPE_PORT << 4) ++#define BITS_GDM1_OFRC_P_PPE (NR_PPE_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_PPE (BITS_GDM1_UFRC_P_PPE | BITS_GDM1_BFRC_P_PPE | BITS_GDM1_MFRC_P_PPE | BITS_GDM1_OFRC_P_PPE) ++ ++#define BITS_GDM1_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12) ++#define BITS_GDM1_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8) ++#define BITS_GDM1_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4) ++#define BITS_GDM1_OFRC_P_CPU_PDMA (NR_PDMA_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_CPU_PDMA (BITS_GDM1_UFRC_P_CPU_PDMA | BITS_GDM1_BFRC_P_CPU_PDMA | BITS_GDM1_MFRC_P_CPU_PDMA | BITS_GDM1_OFRC_P_CPU_PDMA) ++ ++#define BITS_GDM1_UFRC_P_CPU_QDMA (NR_QDMA_PORT << 12) ++#define BITS_GDM1_BFRC_P_CPU_QDMA (NR_QDMA_PORT << 8) ++#define BITS_GDM1_MFRC_P_CPU_QDMA (NR_QDMA_PORT << 4) ++#define BITS_GDM1_OFRC_P_CPU_QDMA (NR_QDMA_PORT << 0) ++#define BITS_GDM1_ALL_FRC_P_CPU_QDMA (BITS_GDM1_UFRC_P_CPU_QDMA | BITS_GDM1_BFRC_P_CPU_QDMA | BITS_GDM1_MFRC_P_CPU_QDMA | BITS_GDM1_OFRC_P_CPU_QDMA) ++ ++#define BITS_GDM1_UFRC_P_DISCARD (NR_DISCARD << 12) ++#define BITS_GDM1_BFRC_P_DISCARD (NR_DISCARD << 8) ++#define BITS_GDM1_MFRC_P_DISCARD (NR_DISCARD << 4) ++#define BITS_GDM1_OFRC_P_DISCARD (NR_DISCARD << 0) ++#define BITS_GDM1_ALL_FRC_P_DISCARD (BITS_GDM1_UFRC_P_DISCARD | BITS_GDM1_BFRC_P_DISCARD | BITS_GDM1_MFRC_P_DISCARD | BITS_GDM1_OFRC_P_DISCARD) ++ ++#define BITS_GDM2_UFRC_P_PPE (NR_PPE_PORT << 12) ++#define BITS_GDM2_BFRC_P_PPE (NR_PPE_PORT << 8) ++#define BITS_GDM2_MFRC_P_PPE (NR_PPE_PORT << 4) ++#define BITS_GDM2_OFRC_P_PPE (NR_PPE_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_PPE (BITS_GDM2_UFRC_P_PPE | BITS_GDM2_BFRC_P_PPE | BITS_GDM2_MFRC_P_PPE | BITS_GDM2_OFRC_P_PPE) ++ ++#define BITS_GDM2_UFRC_P_CPU_PDMA (NR_PDMA_PORT << 12) ++#define BITS_GDM2_BFRC_P_CPU_PDMA (NR_PDMA_PORT << 8) ++#define BITS_GDM2_MFRC_P_CPU_PDMA (NR_PDMA_PORT << 4) ++#define BITS_GDM2_OFRC_P_CPU_PDMA (NR_PDMA_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_CPU_PDMA (BITS_GDM2_UFRC_P_CPU_PDMA | BITS_GDM2_BFRC_P_CPU_PDMA | BITS_GDM2_MFRC_P_CPU_PDMA | BITS_GDM2_OFRC_P_CPU_PDMA) ++ ++#define BITS_GDM2_UFRC_P_CPU_QDMA (NR_QDMA_PORT << 12) ++#define BITS_GDM2_BFRC_P_CPU_QDMA (NR_QDMA_PORT << 8) ++#define BITS_GDM2_MFRC_P_CPU_QDMA (NR_QDMA_PORT << 4) ++#define BITS_GDM2_OFRC_P_CPU_QDMA (NR_QDMA_PORT << 0) ++#define BITS_GDM2_ALL_FRC_P_CPU_QDMA (BITS_GDM2_UFRC_P_CPU_QDMA | BITS_GDM2_BFRC_P_CPU_QDMA | BITS_GDM2_MFRC_P_CPU_QDMA | BITS_GDM2_OFRC_P_CPU_QDMA) ++ ++#define BITS_GDM2_UFRC_P_DISCARD (NR_DISCARD << 12) ++#define BITS_GDM2_BFRC_P_DISCARD (NR_DISCARD << 8) ++#define BITS_GDM2_MFRC_P_DISCARD (NR_DISCARD << 4) ++#define BITS_GDM2_OFRC_P_DISCARD (NR_DISCARD << 0) ++#define BITS_GDM2_ALL_FRC_P_DISCARD (BITS_GDM2_UFRC_P_DISCARD | BITS_GDM2_BFRC_P_DISCARD | BITS_GDM2_MFRC_P_DISCARD | BITS_GDM2_OFRC_P_DISCARD) ++ ++#define hnat_is_enabled(host) (host->enable) ++#define hnat_enabled(host) (host->enable = 1) ++#define hnat_disabled(host) (host->enable = 0) ++#define hnat_is_enabled1(host) (host->enable1) ++#define hnat_enabled1(host) (host->enable1 = 1) ++#define hnat_disabled1(host) (host->enable1 = 0) ++ ++#define entry_hnat_is_bound(e) (e->bfib1.state == BIND) ++#define entry_hnat_state(e) (e->bfib1.state) ++ ++#define skb_hnat_is_hashed(skb) (skb_hnat_entry(skb)!=0x3fff && skb_hnat_entry(skb)< FOE_4TB_SIZ) ++#define FROM_GE_LAN(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_LAN) ++#define FROM_GE_WAN(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_WAN) ++#define FROM_GE_PPD(skb) (HNAT_SKB_CB(skb)->iif == FOE_MAGIC_GE_PPD) ++#define FOE_MAGIC_GE_WAN 0x7273 ++#define FOE_MAGIC_GE_LAN 0x7272 ++#define FOE_INVALID 0xffff ++ ++#define TCP_FIN_SYN_RST 0x0C /* Ingress packet is TCP fin/syn/rst (for IPv4 NAPT/DS-Lite or IPv6 5T-route/6RD) */ ++#define UN_HIT 0x0D/* FOE Un-hit */ ++#define HIT_UNBIND 0x0E/* FOE Hit unbind */ ++#define HIT_UNBIND_RATE_REACH 0xf ++#define HNAT_HIT_BIND_OLD_DUP_HDR 0x15 ++#define HNAT_HIT_BIND_FORCE_TO_CPU 0x16 ++ ++#define HIT_BIND_KEEPALIVE_MC_NEW_HDR 0x14 ++#define HIT_BIND_KEEPALIVE_DUP_OLD_HDR 0x15 ++#define IPV4_HNAPT 0 ++#define IPV4_HNAT 1 ++#define IP_FORMAT(addr) \ ++ ((unsigned char *)&addr)[3], \ ++ ((unsigned char *)&addr)[2], \ ++ ((unsigned char *)&addr)[1], \ ++ ((unsigned char *)&addr)[0] ++ ++/*PSE Ports*/ ++#define NR_PDMA_PORT 0 ++#define NR_GMAC1_PORT 1 ++#define NR_GMAC2_PORT 2 ++#define NR_PPE_PORT 4 ++#define NR_QDMA_PORT 5 ++#define NR_DISCARD 7 ++#define IS_LAN(dev) (!strncmp(dev->name, "lan", 3)) ++#define IS_WAN(dev) (!strcmp(dev->name, host->wan)) ++#define IS_BR(dev) (!strncmp(dev->name, "br", 2)) ++#define IS_IPV4_HNAPT(x) (((x)->bfib1.pkt_type == IPV4_HNAPT) ? 1: 0) ++#define IS_IPV4_HNAT(x) (((x)->bfib1.pkt_type == IPV4_HNAT) ? 1 : 0) ++#define IS_IPV4_GRP(x) (IS_IPV4_HNAPT(x) | IS_IPV4_HNAT(x)) ++ ++#define es(entry) (entry_state[entry->bfib1.state]) ++#define ei(entry, end) (FOE_4TB_SIZ - (int)(end - entry)) ++#define pt(entry) (packet_type[entry->ipv4_hnapt.bfib1.pkt_type]) ++#define ipv4_smac(mac,e) ({mac[0]=e->ipv4_hnapt.smac_hi[3]; mac[1]=e->ipv4_hnapt.smac_hi[2];\ ++ mac[2]=e->ipv4_hnapt.smac_hi[1]; mac[3]=e->ipv4_hnapt.smac_hi[0];\ ++ mac[4]=e->ipv4_hnapt.smac_lo[1]; mac[5]=e->ipv4_hnapt.smac_lo[0];}) ++#define ipv4_dmac(mac,e) ({mac[0]=e->ipv4_hnapt.dmac_hi[3]; mac[1]=e->ipv4_hnapt.dmac_hi[2];\ ++ mac[2]=e->ipv4_hnapt.dmac_hi[1]; mac[3]=e->ipv4_hnapt.dmac_hi[0];\ ++ mac[4]=e->ipv4_hnapt.dmac_lo[1]; mac[5]=e->ipv4_hnapt.dmac_lo[0];}) ++ ++extern struct hnat_priv *host; ++ ++extern void hnat_deinit_debugfs(struct hnat_priv *h); ++extern int __init hnat_init_debugfs(struct hnat_priv *h); ++extern int hnat_register_nf_hooks(void); ++extern void hnat_unregister_nf_hooks(void); ++ +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c +@@ -0,0 +1,489 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++#include ++#include ++ ++#include "hnat.h" ++ ++static const char *entry_state[] = { ++ "INVALID", ++ "UNBIND", ++ "BIND", ++ "FIN" ++}; ++ ++static const char *packet_type[] = { ++ "IPV4_HNAPT", ++ "IPV4_HNAT", ++ "IPV6_1T_ROUTE", ++ "IPV4_DSLITE", ++ "IPV6_3T_ROUTE", ++ "IPV6_5T_ROUTE", ++ "IPV6_6RD", ++}; ++ ++static int hnat_debug_show(struct seq_file *m, void *private) ++{ ++ struct hnat_priv *h = host; ++ struct foe_entry *entry, *end; ++ ++ entry = h->foe_table_cpu; ++ end = h->foe_table_cpu + FOE_4TB_SIZ; ++ while (entry < end) { ++ if (!entry->bfib1.state) { ++ entry++; ++ continue; ++ } ++ ++ if (IS_IPV4_HNAPT(entry)) { ++ __be32 saddr = htonl(entry->ipv4_hnapt.sip); ++ __be32 daddr = htonl(entry->ipv4_hnapt.dip); ++ __be32 nsaddr = htonl(entry->ipv4_hnapt.new_sip); ++ __be32 ndaddr = htonl(entry->ipv4_hnapt.new_dip); ++ unsigned char h_dest[ETH_ALEN]; ++ unsigned char h_source[ETH_ALEN]; ++ ++ *((u32*) h_source) = swab32(entry->ipv4_hnapt.smac_hi); ++ *((u16*) &h_source[4]) = swab16(entry->ipv4_hnapt.smac_lo); ++ *((u32*) h_dest) = swab32(entry->ipv4_hnapt.dmac_hi); ++ *((u16*) &h_dest[4]) = swab16(entry->ipv4_hnapt.dmac_lo); ++ seq_printf(m, ++ "(%p)0x%05x|state=%s|type=%s|%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|etype=0x%04x|info1=0x%x|info2=0x%x|vlan1=%d|vlan2=%d\n", ++ (void *)h->foe_table_dev + ((void *)(entry) - (void *)h->foe_table_cpu), ++ ei(entry, end), es(entry), pt(entry), ++ &saddr, entry->ipv4_hnapt.sport, ++ &daddr, entry->ipv4_hnapt.dport, ++ &nsaddr, entry->ipv4_hnapt.new_sport, ++ &ndaddr, entry->ipv4_hnapt.new_dport, h_source, ++ h_dest, ntohs(entry->ipv4_hnapt.etype), ++ entry->ipv4_hnapt.info_blk1, ++ entry->ipv4_hnapt.info_blk2, ++ entry->ipv4_hnapt.vlan1, ++ entry->ipv4_hnapt.vlan2); ++ } else ++ seq_printf(m, "0x%05x state=%s\n", ++ ei(entry, end), es(entry)); ++ entry++; ++ } ++ ++ return 0; ++} ++ ++static int hnat_debug_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, hnat_debug_show, file->private_data); ++} ++ ++static const struct file_operations hnat_debug_fops = { ++ .open = hnat_debug_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++#define QDMA_TX_SCH_TX 0x1a14 ++ ++static ssize_t hnat_sched_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX); ++ int enable; ++ int max_rate; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ ++ if (id) ++ reg >>= 16; ++ reg &= 0xffff; ++ enable = !! (reg & BIT(11)); ++ max_rate = ((reg >> 4) & 0x7f); ++ reg &= 0xf; ++ while (reg--) ++ max_rate *= 10; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "EN\tMAX\n%d\t%d\n", enable, max_rate); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static ssize_t hnat_sched_write(struct file *file, ++ const char __user *buf, size_t length, loff_t *offset) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ char line[64]; ++ int enable, rate, exp = 0, shift = 0; ++ size_t size; ++ u32 reg = readl(h->fe_base + QDMA_TX_SCH_TX); ++ u32 val = 0; ++ ++ if (length > sizeof(line)) ++ return -EINVAL; ++ ++ if (copy_from_user(line, buf, length)) ++ return -EFAULT; ++ ++ sscanf(line, "%d %d", &enable, &rate); ++ ++ while (rate > 127) { ++ rate /= 10; ++ exp++; ++ } ++ ++ if (enable) ++ val |= BIT(11); ++ val |= (rate & 0x7f) << 4; ++ val |= exp & 0xf; ++ if (id) ++ shift = 16; ++ reg &= ~(0xffff << shift); ++ reg |= val << shift; ++ writel(reg, h->fe_base + QDMA_TX_SCH_TX); ++ ++ size = strlen(line); ++ *offset += size; ++ ++ return length; ++} ++ ++static const struct file_operations hnat_sched_fops = { ++ .open = simple_open, ++ .read = hnat_sched_show, ++ .write = hnat_sched_write, ++ .llseek = default_llseek, ++}; ++ ++#define QTX_CFG(x) (0x1800 + (x * 0x10)) ++#define QTX_SCH(x) (0x1804 + (x * 0x10)) ++ ++static ssize_t hnat_queue_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct hnat_priv *h = host; ++ int id = (int) file->private_data; ++ u32 reg = readl(h->fe_base + QTX_SCH(id)); ++ u32 cfg = readl(h->fe_base + QTX_CFG(id)); ++ int scheduler = !!(reg & BIT(31)); ++ int min_rate_en = !!(reg & BIT(27)); ++ int min_rate = (reg >> 20) & 0x7f; ++ int min_rate_exp = (reg >> 16) & 0xf; ++ int max_rate_en = !!(reg & BIT(11)); ++ int max_weight = (reg >> 12) & 0xf; ++ int max_rate = (reg >> 4) & 0x7f; ++ int max_rate_exp = reg & 0xf; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ while (min_rate_exp--) ++ min_rate *= 10; ++ ++ while (max_rate_exp--) ++ max_rate *= 10; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "scheduler: %d\nhw resv: %d\nsw resv: %d\n", ++ scheduler, (cfg >> 8) & 0xff, cfg & 0xff); ++ len += scnprintf(buf + len, buf_len - len, ++ "\tEN\tRATE\t\tWEIGHT\n"); ++ len += scnprintf(buf + len, buf_len - len, ++ "max\t%d\t%8d\t%d\n", max_rate_en, max_rate, max_weight); ++ len += scnprintf(buf + len, buf_len - len, ++ "min\t%d\t%8d\t-\n", min_rate_en, min_rate); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static ssize_t hnat_queue_write(struct file *file, ++ const char __user *buf, size_t length, loff_t *offset) ++{ ++ int id = (int) file->private_data; ++ struct hnat_priv *h = host; ++ char line[64]; ++ int max_enable, max_rate, max_exp = 0; ++ int min_enable, min_rate, min_exp = 0; ++ int weight; ++ int resv; ++ int scheduler; ++ size_t size; ++ u32 reg = readl(h->fe_base + QTX_SCH(id)); ++ ++ if (length > sizeof(line)) ++ return -EINVAL; ++ ++ if (copy_from_user(line, buf, length)) ++ return -EFAULT; ++ ++ sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate, &max_enable, &max_rate, &weight, &resv); ++ ++ while (max_rate > 127) { ++ max_rate /= 10; ++ max_exp++; ++ } ++ ++ while (min_rate > 127) { ++ min_rate /= 10; ++ min_exp++; ++ } ++ ++ reg &= 0x70000000; ++ if (scheduler) ++ reg |= BIT(31); ++ if (min_enable) ++ reg |= BIT(27); ++ reg |= (min_rate & 0x7f) << 20; ++ reg |= (min_exp & 0xf) << 16; ++ if (max_enable) ++ reg |= BIT(11); ++ reg |= (weight & 0xf) << 12; ++ reg |= (max_rate & 0x7f) << 4; ++ reg |= max_exp & 0xf; ++ writel(reg, h->fe_base + QTX_SCH(id)); ++ ++ resv &= 0xff; ++ reg = readl(h->fe_base + QTX_CFG(id)); ++ reg &= 0xffff0000; ++ reg |= (resv << 8) | resv; ++ writel(reg, h->fe_base + QTX_CFG(id)); ++ ++ size = strlen(line); ++ *offset += size; ++ ++ return length; ++} ++ ++static const struct file_operations hnat_queue_fops = { ++ .open = simple_open, ++ .read = hnat_queue_show, ++ .write = hnat_queue_write, ++ .llseek = default_llseek, ++}; ++ ++static void hnat_ac_timer_handle(unsigned long priv) ++{ ++ struct hnat_priv *h = (struct hnat_priv*) priv; ++ int i; ++ ++ for (i = 0; i < HNAT_COUNTER_MAX; i++) { ++ u32 b_hi, b_lo; ++ u64 b; ++ ++ b_lo = readl(h->fe_base + HNAT_AC_BYTE_LO(i)); ++ b_hi = readl(h->fe_base + HNAT_AC_BYTE_HI(i)); ++ b = b_hi; ++ b <<= 32; ++ b += b_lo; ++ h->acct[i].bytes += b; ++ h->acct[i].packets += readl(h->fe_base + HNAT_AC_PACKET(i)); ++ } ++ ++ mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL); ++} ++ ++static ssize_t hnat_counter_show(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct hnat_priv *h = host; ++ int id = (int) file->private_data; ++ char *buf; ++ unsigned int len = 0, buf_len = 1500; ++ ssize_t ret_cnt; ++ int id2 = id + (HNAT_COUNTER_MAX / 2); ++ ++ buf = kzalloc(buf_len, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ len += scnprintf(buf + len, buf_len - len, ++ "tx pkts : %llu\ntx bytes: %llu\nrx pktks : %llu\nrx bytes : %llu\n", ++ h->acct[id].packets, h->acct[id].bytes, ++ h->acct[id2].packets, h->acct[id2].bytes); ++ ++ if (len > buf_len) ++ len = buf_len; ++ ++ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ ++ kfree(buf); ++ return ret_cnt; ++} ++ ++static const struct file_operations hnat_counter_fops = { ++ .open = simple_open, ++ .read = hnat_counter_show, ++ .llseek = default_llseek, ++}; ++ ++#define dump_register(nm) \ ++{ \ ++ .name = __stringify(nm), \ ++ .offset = PPE_ ##nm , \ ++} ++ ++static const struct debugfs_reg32 hnat_regs[] = { ++ dump_register(GLO_CFG), ++ dump_register(FLOW_CFG), ++ dump_register(IP_PROT_CHK), ++ dump_register(IP_PROT_0), ++ dump_register(IP_PROT_1), ++ dump_register(IP_PROT_2), ++ dump_register(IP_PROT_3), ++ dump_register(TB_CFG), ++ dump_register(TB_BASE), ++ dump_register(TB_USED), ++ dump_register(BNDR), ++ dump_register(BIND_LMT_0), ++ dump_register(BIND_LMT_1), ++ dump_register(KA), ++ dump_register(UNB_AGE), ++ dump_register(BND_AGE_0), ++ dump_register(BND_AGE_1), ++ dump_register(HASH_SEED), ++ dump_register(DFT_CPORT), ++ dump_register(MCAST_PPSE), ++ dump_register(MCAST_L_0), ++ dump_register(MCAST_H_0), ++ dump_register(MCAST_L_1), ++ dump_register(MCAST_H_1), ++ dump_register(MCAST_L_2), ++ dump_register(MCAST_H_2), ++ dump_register(MCAST_L_3), ++ dump_register(MCAST_H_3), ++ dump_register(MCAST_L_4), ++ dump_register(MCAST_H_4), ++ dump_register(MCAST_L_5), ++ dump_register(MCAST_H_5), ++ dump_register(MCAST_L_6), ++ dump_register(MCAST_H_6), ++ dump_register(MCAST_L_7), ++ dump_register(MCAST_H_7), ++ dump_register(MCAST_L_8), ++ dump_register(MCAST_H_8), ++ dump_register(MCAST_L_9), ++ dump_register(MCAST_H_9), ++ dump_register(MCAST_L_A), ++ dump_register(MCAST_H_A), ++ dump_register(MCAST_L_B), ++ dump_register(MCAST_H_B), ++ dump_register(MCAST_L_C), ++ dump_register(MCAST_H_C), ++ dump_register(MCAST_L_D), ++ dump_register(MCAST_H_D), ++ dump_register(MCAST_L_E), ++ dump_register(MCAST_H_E), ++ dump_register(MCAST_L_F), ++ dump_register(MCAST_H_F), ++ dump_register(MTU_DRP), ++ dump_register(MTU_VLYR_0), ++ dump_register(MTU_VLYR_1), ++ dump_register(MTU_VLYR_2), ++ dump_register(VPM_TPID), ++ dump_register(VPM_TPID), ++ dump_register(CAH_CTRL), ++ dump_register(CAH_TAG_SRH), ++ dump_register(CAH_LINE_RW), ++ dump_register(CAH_WDATA), ++ dump_register(CAH_RDATA), ++}; ++ ++int __init hnat_init_debugfs(struct hnat_priv *h) ++{ ++ int ret = 0; ++ struct dentry *root; ++ struct dentry *file; ++ int i; ++ char name[16]; ++ ++ root = debugfs_create_dir("hnat", NULL); ++ if (!root) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err0; ++ } ++ h->root = root; ++ h->regset = kzalloc(sizeof(*h->regset), GFP_KERNEL); ++ if (!h->regset) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ h->regset->regs = hnat_regs; ++ h->regset->nregs = ARRAY_SIZE(hnat_regs); ++ h->regset->base = h->ppe_base; ++ ++ file = debugfs_create_regset32("regdump", S_IRUGO, root, h->regset); ++ if (!file) { ++ dev_err(h->dev, "%s:err at %d\n", __func__, __LINE__); ++ ret = -ENOMEM; ++ goto err1; ++ } ++ debugfs_create_file("all_entry", S_IRUGO, root, h, &hnat_debug_fops); ++ for (i = 0; i < HNAT_COUNTER_MAX / 2; i++) { ++ snprintf(name, sizeof(name), "counter%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_counter_fops); ++ } ++ ++ for (i = 0; i < 2; i++) { ++ snprintf(name, sizeof(name), "scheduler%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_sched_fops); ++ } ++ ++ for (i = 0; i < 16; i++) { ++ snprintf(name, sizeof(name), "queue%d", i); ++ debugfs_create_file(name, S_IRUGO, root, (void *)i, &hnat_queue_fops); ++ } ++ ++ setup_timer(&h->ac_timer, hnat_ac_timer_handle, (unsigned long) h); ++ mod_timer(&h->ac_timer, jiffies + HNAT_AC_TIMER_INTERVAL); ++ ++ return 0; ++ ++ err1: ++ debugfs_remove_recursive(root); ++ err0: ++ return ret; ++} ++ ++void hnat_deinit_debugfs(struct hnat_priv *h) ++{ ++ del_timer(&h->ac_timer); ++ debugfs_remove_recursive(h->root); ++ h->root = NULL; ++} +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c +@@ -0,0 +1,289 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "nf_hnat_mtk.h" ++#include "hnat.h" ++ ++#include "../mtk_eth_soc.h" ++ ++static unsigned int skb_to_hnat_info(struct sk_buff *skb, ++ const struct net_device *dev, ++ struct foe_entry *foe) ++{ ++ struct foe_entry entry = { 0 }; ++ int lan = IS_LAN(dev); ++ struct ethhdr *eth; ++ struct iphdr *iph; ++ struct tcphdr *tcph; ++ struct udphdr *udph; ++ int tcp = 0; ++ int ipv4 = 0; ++ u32 gmac; ++ ++ eth = eth_hdr(skb); ++ switch (ntohs(eth->h_proto)) { ++ case ETH_P_IP: ++ ipv4 = 1; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ iph = ip_hdr(skb); ++ switch (iph->protocol) { ++ case IPPROTO_TCP: ++ tcph = tcp_hdr(skb); ++ tcp = 1; ++ break; ++ ++ case IPPROTO_UDP: ++ udph = udp_hdr(skb); ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ entry.ipv4_hnapt.etype = htons(ETH_P_IP); ++ ++ if (lan) { ++ entry.ipv4_hnapt.etype = htons(ETH_P_8021Q); ++ entry.bfib1.vlan_layer = 1; ++ entry.ipv4_hnapt.vlan1 = BIT(dev->name[3] - '0'); ++ } ++ ++ if (dev->priv_flags & IFF_802_1Q_VLAN) { ++ struct vlan_dev_priv *vlan = vlan_dev_priv(dev); ++ ++ entry.ipv4_hnapt.etype = htons(ETH_P_8021Q); ++ entry.bfib1.vlan_layer = 1; ++ if (lan) ++ entry.ipv4_hnapt.vlan2 = vlan->vlan_id; ++ else ++ entry.ipv4_hnapt.vlan1 = vlan->vlan_id; ++ } ++ ++ entry.ipv4_hnapt.dmac_hi = swab32(*((u32*) eth->h_dest)); ++ entry.ipv4_hnapt.dmac_lo = swab16(*((u16*) ð->h_dest[4])); ++ entry.ipv4_hnapt.smac_hi = swab32(*((u32*) eth->h_source)); ++ entry.ipv4_hnapt.smac_lo = swab16(*((u16*) ð->h_source[4])); ++ entry.ipv4_hnapt.pppoe_id = 0; ++ entry.bfib1.psn = 0; ++ entry.ipv4_hnapt.bfib1.vpm = 1; ++ ++ if (ipv4) ++ entry.ipv4_hnapt.bfib1.pkt_type = IPV4_HNAPT; ++ ++ entry.ipv4_hnapt.new_sip = ntohl(iph->saddr); ++ entry.ipv4_hnapt.new_dip = ntohl(iph->daddr); ++ entry.ipv4_hnapt.iblk2.dscp = iph->tos; ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ entry.ipv4_hnapt.iblk2.qid = skb->mark & 0x7; ++ if (lan) ++ entry.ipv4_hnapt.iblk2.qid += 8; ++ entry.ipv4_hnapt.iblk2.fqos = 1; ++#endif ++ if (tcp) { ++ entry.ipv4_hnapt.new_sport = ntohs(tcph->source); ++ entry.ipv4_hnapt.new_dport = ntohs(tcph->dest); ++ entry.ipv4_hnapt.bfib1.udp = 0; ++ } else { ++ entry.ipv4_hnapt.new_sport = ntohs(udph->source); ++ entry.ipv4_hnapt.new_dport = ntohs(udph->dest); ++ entry.ipv4_hnapt.bfib1.udp = 1; ++ } ++ ++ if (IS_LAN(dev)) ++ gmac = NR_GMAC1_PORT; ++ else if (IS_WAN(dev)) ++ gmac = NR_GMAC2_PORT; ++ ++ if (is_multicast_ether_addr(ð->h_dest[0])) ++ entry.ipv4_hnapt.iblk2.mcast = 1; ++ else ++ entry.ipv4_hnapt.iblk2.mcast = 0; ++ ++ entry.ipv4_hnapt.iblk2.dp = gmac; ++ entry.ipv4_hnapt.iblk2.port_mg = 0x3f; ++ entry.ipv4_hnapt.iblk2.port_ag = (skb->mark >> 3) & 0x1f; ++ if (IS_LAN(dev)) ++ entry.ipv4_hnapt.iblk2.port_ag += 32; ++ entry.bfib1.time_stamp = readl((host->fe_base + 0x0010)) & (0xFFFF); ++ entry.ipv4_hnapt.bfib1.ttl = 1; ++ entry.ipv4_hnapt.bfib1.cah = 1; ++ entry.ipv4_hnapt.bfib1.ka = 1; ++ entry.bfib1.state = BIND; ++ ++ entry.ipv4_hnapt.sip = foe->ipv4_hnapt.sip; ++ entry.ipv4_hnapt.dip = foe->ipv4_hnapt.dip; ++ entry.ipv4_hnapt.sport = foe->ipv4_hnapt.sport; ++ entry.ipv4_hnapt.dport = foe->ipv4_hnapt.dport; ++ ++ memcpy(foe, &entry, sizeof(entry)); ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_nf_post_routing(struct sk_buff *skb, ++ const struct net_device *out, ++ unsigned int (*fn)(struct sk_buff *, const struct net_device *), ++ const char *func) ++{ ++ struct foe_entry *entry; ++ struct nf_conn *ct; ++ enum ip_conntrack_info ctinfo; ++ const struct nf_conn_help *help; ++ ++ if ((skb->mark & 0x7) < 4) ++ return 0; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (!ct) ++ return 0; ++ ++ /* rcu_read_lock()ed by nf_hook_slow */ ++ help = nfct_help(ct); ++ if (help && rcu_dereference(help->helper)) ++ return 0; ++ ++ if ((FROM_GE_WAN(skb) || FROM_GE_LAN(skb)) && ++ skb_hnat_is_hashed(skb) && ++ (skb_hnat_reason(skb) == HIT_BIND_KEEPALIVE_DUP_OLD_HDR)) ++ return -1; ++ ++ if ((IS_LAN(out) && FROM_GE_WAN(skb)) || ++ (IS_WAN(out) && FROM_GE_LAN(skb))) { ++ if (!skb_hnat_is_hashed(skb)) ++ return 0; ++ ++ entry = &host->foe_table_cpu[skb_hnat_entry(skb)]; ++ if (entry_hnat_is_bound(entry)) ++ return 0; ++ ++ if (skb_hnat_reason(skb) == HIT_UNBIND_RATE_REACH && ++ skb_hnat_alg(skb) == 0) { ++ if (fn && fn(skb, out)) ++ return 0; ++ skb_to_hnat_info(skb, out, entry); ++ } ++ } ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_nf_pre_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (IS_WAN(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_WAN; ++ else if (IS_LAN(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_MAGIC_GE_LAN; ++ else if (!IS_BR(state->in)) ++ HNAT_SKB_CB(skb)->iif = FOE_INVALID; ++ ++ return NF_ACCEPT; ++} ++ ++static unsigned int hnat_get_nexthop(struct sk_buff *skb, const struct net_device *out) { ++ ++ u32 nexthop; ++ struct neighbour *neigh; ++ struct dst_entry *dst = skb_dst(skb); ++ struct rtable *rt = (struct rtable *)dst; ++ struct net_device *dev = (__force struct net_device *)out; ++ ++ rcu_read_lock_bh(); ++ nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr); ++ neigh = __ipv4_neigh_lookup_noref(dev, nexthop); ++ if (unlikely(!neigh)) { ++ dev_err(host->dev, "%s:++ no neigh\n", __func__); ++ return -1; ++ } ++ ++ /* why do we get all zero ethernet address ? */ ++ if (!is_valid_ether_addr(neigh->ha)){ ++ rcu_read_unlock_bh(); ++ return -1; ++ } ++ ++ memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN); ++ memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN); ++ ++ rcu_read_unlock_bh(); ++ ++ return 0; ++} ++ ++static unsigned int mtk_hnat_ipv4_nf_post_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (!mtk_hnat_nf_post_routing(skb, state->out, hnat_get_nexthop, __func__)) ++ return NF_ACCEPT; ++ ++ return NF_DROP; ++} ++ ++static unsigned int mtk_hnat_br_nf_post_routing(void *priv, ++ struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ if (!mtk_hnat_nf_post_routing(skb, state->out , 0, __func__)) ++ return NF_ACCEPT; ++ ++ return NF_DROP; ++} ++ ++static struct nf_hook_ops mtk_hnat_nf_ops[] __read_mostly = { ++ { ++ .hook = mtk_hnat_nf_pre_routing, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_PRE_ROUTING, ++ .priority = NF_IP_PRI_FIRST, ++ }, { ++ .hook = mtk_hnat_ipv4_nf_post_routing, ++ .pf = NFPROTO_IPV4, ++ .hooknum = NF_INET_POST_ROUTING, ++ .priority = NF_IP_PRI_LAST, ++ }, { ++ .hook = mtk_hnat_nf_pre_routing, ++ .pf = NFPROTO_BRIDGE, ++ .hooknum = NF_BR_PRE_ROUTING, ++ .priority = NF_BR_PRI_FIRST, ++ }, { ++ .hook = mtk_hnat_br_nf_post_routing, ++ .pf = NFPROTO_BRIDGE, ++ .hooknum = NF_BR_POST_ROUTING, ++ .priority = NF_BR_PRI_LAST - 1, ++ }, ++}; ++ ++int hnat_register_nf_hooks(void) ++{ ++ return nf_register_hooks(mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} ++ ++void hnat_unregister_nf_hooks(void) ++{ ++ nf_unregister_hooks(mtk_hnat_nf_ops, ++ ARRAY_SIZE(mtk_hnat_nf_ops)); ++} +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h +@@ -0,0 +1,44 @@ ++/* This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2014-2016 Sean Wang ++ * Copyright (C) 2016-2017 John Crispin ++ */ ++ ++#ifndef NF_HNAT_MTK_H ++#define NF_HNAT_MTK_H ++ ++#include ++#include ++ ++#define HNAT_SKB_CB2(__skb) ((struct hnat_skb_cb2 *)&((__skb)->cb[44])) ++struct hnat_skb_cb2 { ++ __u32 magic; ++}; ++ ++struct hnat_desc { ++ u32 entry:14; ++ u32 crsn:5; ++ u32 sport:4; ++ u32 alg:9; ++} __attribute__ ((packed)); ++ ++#define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic) ++#define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn) ++#define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry) ++#define skb_hnat_sport(skb) (((struct hnat_desc *)(skb->head))->sport) ++#define skb_hnat_alg(skb) (((struct hnat_desc *)(skb->head))->alg) ++ ++u32 hnat_tx(struct sk_buff *skb); ++u32 hnat_set_skb_info(struct sk_buff *skb, u32 *rxd); ++u32 hnat_reg(struct net_device *, void __iomem *); ++u32 hnat_unreg(void); ++ ++#endif ++ diff --git a/target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch deleted file mode 100644 index 8784166ca6..0000000000 --- a/target/linux/mediatek/patches-4.9/0026-scpsys-various-fixes.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 59aafd667d2880c90776931b6102b8252214d93c Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Sun, 21 Feb 2016 13:52:12 +0100 -Subject: [PATCH 026/102] scpsys: various fixes - ---- - drivers/clk/mediatek/clk-mt2701.c | 2 ++ - drivers/soc/mediatek/mtk-scpsys-mt2701.c | 8 -------- - include/dt-bindings/power/mt2701-power.h | 4 ++-- - 3 files changed, 4 insertions(+), 10 deletions(-) - ---- a/drivers/clk/mediatek/clk-mt2701.c -+++ b/drivers/clk/mediatek/clk-mt2701.c -@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_register_reset_controller(node, 1, 0x34); - } - CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init); - diff --git a/target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch new file mode 100644 index 0000000000..d21c8eedb1 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0027-net-next-mediatek-fix-DQL-support.patch @@ -0,0 +1,93 @@ +From f974e397b806f7b16d11cc1542538616291924f1 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Sat, 23 Apr 2016 11:57:21 +0200 +Subject: [PATCH 27/57] net-next: mediatek: fix DQL support + +The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The +current code will assign the TX traffic of each MAC to its own DQL. This +results in the amount of data, that DQL says is in the queue incorrect. As +the data from multiple devices is infact enqueued. This makes any decision +based on these value non deterministic. Fix this by tracking all TX +traffic, regardless of the MAC it belongs to in the DQL of all devices +using the DMA. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 35 +++++++++++++++++------------ + 1 file changed, 21 insertions(+), 14 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -710,7 +710,16 @@ static int mtk_tx_map(struct sk_buff *sk + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- netdev_sent_queue(dev, skb->len); ++ /* we have a single DMA ring so BQL needs to be updated for all devices ++ * sitting on this ring ++ */ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ netdev_sent_queue(eth->netdev[i], skb->len); ++ } ++ + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -1002,21 +1011,18 @@ static int mtk_poll_tx(struct mtk_eth *e + struct mtk_tx_dma *desc; + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; +- unsigned int done[MTK_MAX_DEVS]; +- unsigned int bytes[MTK_MAX_DEVS]; ++ int total = 0, done = 0; ++ unsigned int bytes = 0; + u32 cpu, dma; + static int condition; +- int total = 0, i; +- +- memset(done, 0, sizeof(done)); +- memset(bytes, 0, sizeof(bytes)); ++ int i; + + cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); + dma = mtk_r32(eth, MTK_QTX_DRX_PTR); + + desc = mtk_qdma_phys_to_virt(ring, cpu); + +- while ((cpu != dma) && budget) { ++ while ((cpu != dma) && done < budget) { + u32 next_cpu = desc->txd2; + int mac = 0; + +@@ -1035,9 +1041,8 @@ static int mtk_poll_tx(struct mtk_eth *e + } + + if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { +- bytes[mac] += skb->len; +- done[mac]++; +- budget--; ++ bytes += skb->len; ++ done++; + } + mtk_tx_unmap(eth, tx_buf); + +@@ -1049,11 +1054,13 @@ static int mtk_poll_tx(struct mtk_eth *e + + mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + ++ /* we have a single DMA ring so BQL needs to be updated for all devices ++ * sitting on this ring ++ */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i] || !done[i]) ++ if (!eth->netdev[i]) + continue; +- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); +- total += done[i]; ++ netdev_completed_queue(eth->netdev[i], done, bytes); + } + + if (mtk_queue_stopped(eth) && diff --git a/target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch b/target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch new file mode 100644 index 0000000000..2ba1cb80d3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0028-net-next-dsa-add-Mediatek-tag-RX-TX-handler.patch @@ -0,0 +1,192 @@ +From 5c01c03920c63630864d2b8641924a8c7c6cb62f Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Wed, 29 Mar 2017 17:38:20 +0800 +Subject: [PATCH 28/57] net-next: dsa: add Mediatek tag RX/TX handler + +Add the support for the 4-bytes tag for DSA port distinguishing inserted +allowing receiving and transmitting the packet via the particular port. +The tag is being added after the source MAC address in the ethernet +header. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +--- + include/net/dsa.h | 1 + + net/dsa/Kconfig | 2 + + net/dsa/Makefile | 1 + + net/dsa/dsa.c | 3 ++ + net/dsa/dsa_priv.h | 3 ++ + net/dsa/tag_mtk.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 6 files changed, 127 insertions(+) + create mode 100644 net/dsa/tag_mtk.c + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -27,6 +27,7 @@ enum dsa_tag_protocol { + DSA_TAG_PROTO_EDSA, + DSA_TAG_PROTO_BRCM, + DSA_TAG_PROTO_QCA, ++ DSA_TAG_PROTO_MTK, + DSA_TAG_LAST, /* MUST BE LAST */ + }; + +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -41,4 +41,6 @@ config NET_DSA_TAG_TRAILER + config NET_DSA_TAG_QCA + bool + ++config NET_DSA_TAG_MTK ++ bool + endif +--- a/net/dsa/Makefile ++++ b/net/dsa/Makefile +@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += ta + dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o + dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o + dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o ++dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o +--- a/net/dsa/dsa.c ++++ b/net/dsa/dsa.c +@@ -57,6 +57,9 @@ const struct dsa_device_ops *dsa_device_ + #ifdef CONFIG_NET_DSA_TAG_QCA + [DSA_TAG_PROTO_QCA] = &qca_netdev_ops, + #endif ++#ifdef CONFIG_NET_DSA_TAG_MTK ++ [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops, ++#endif + [DSA_TAG_PROTO_NONE] = &none_ops, + }; + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -84,4 +84,7 @@ extern const struct dsa_device_ops brcm_ + /* tag_qca.c */ + extern const struct dsa_device_ops qca_netdev_ops; + ++/* tag_mtk.c */ ++extern const struct dsa_device_ops mtk_netdev_ops; ++ + #endif +--- /dev/null ++++ b/net/dsa/tag_mtk.c +@@ -0,0 +1,117 @@ ++/* ++ * Mediatek DSA Tag support ++ * Copyright (C) 2017 Landen Chao ++ * Sean Wang ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include "dsa_priv.h" ++ ++#define MTK_HDR_LEN 4 ++#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) ++#define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0) ++ ++static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct dsa_slave_priv *p = netdev_priv(dev); ++ u8 *mtk_tag; ++ ++ if (skb_cow_head(skb, MTK_HDR_LEN) < 0) ++ goto out_free; ++ ++ skb_push(skb, MTK_HDR_LEN); ++ ++ memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN); ++ ++ /* Build the tag after the MAC Source Address */ ++ mtk_tag = skb->data + 2 * ETH_ALEN; ++ mtk_tag[0] = 0; ++ mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; ++ mtk_tag[2] = 0; ++ mtk_tag[3] = 0; ++ ++ return skb; ++ ++out_free: ++ kfree_skb(skb); ++ return NULL; ++} ++ ++static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, ++ struct packet_type *pt, struct net_device *orig_dev) ++{ ++ struct dsa_switch_tree *dst = dev->dsa_ptr; ++ struct dsa_switch *ds; ++ int port; ++ __be16 *phdr, hdr; ++ ++ if (unlikely(!dst)) ++ goto out_drop; ++ ++ skb = skb_unshare(skb, GFP_ATOMIC); ++ if (!skb) ++ goto out; ++ ++ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) ++ goto out_drop; ++ ++ /* The MTK header is added by the switch between src addr ++ * and ethertype at this point, skb->data points to 2 bytes ++ * after src addr so header should be 2 bytes right before. ++ */ ++ phdr = (__be16 *)(skb->data - 2); ++ hdr = ntohs(*phdr); ++ ++ /* Remove MTK tag and recalculate checksum. */ ++ skb_pull_rcsum(skb, MTK_HDR_LEN); ++ ++ memmove(skb->data - ETH_HLEN, ++ skb->data - ETH_HLEN - MTK_HDR_LEN, ++ 2 * ETH_ALEN); ++ ++ /* This protocol doesn't support cascading multiple ++ * switches so it's safe to assume the switch is first ++ * in the tree. ++ */ ++ ds = dst->ds[0]; ++ if (!ds) ++ goto out_drop; ++ ++ /* Get source port information */ ++ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); ++ if (!ds->ports[port].netdev) ++ goto out_drop; ++ ++ /* Update skb & forward the frame accordingly */ ++ skb_push(skb, ETH_HLEN); ++ ++ skb->pkt_type = PACKET_HOST; ++ skb->dev = ds->ports[port].netdev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->dev->stats.rx_packets++; ++ skb->dev->stats.rx_bytes += skb->len; ++ ++ netif_receive_skb(skb); ++ ++ return 0; ++ ++out_drop: ++ kfree_skb(skb); ++out: ++ return 0; ++} ++ ++const struct dsa_device_ops mtk_netdev_ops = { ++ .xmit = mtk_tag_xmit, ++ .rcv = mtk_tag_rcv, ++}; diff --git a/target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch b/target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch new file mode 100644 index 0000000000..5c7e6e43cd --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0029-net-next-ethernet-mediatek-add-CDM-able-to-recognize.patch @@ -0,0 +1,48 @@ +From de3c04b820e1d396bf12e88ea87271a84f6fedb7 Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Wed, 29 Mar 2017 17:38:21 +0800 +Subject: [PATCH 29/57] net-next: ethernet: mediatek: add CDM able to recognize + the tag for DSA + +The patch adds the setup for allowing CDM can recognize these packets with +carrying port-distinguishing tag. Otherwise, these tagging packets will be +handled incorrectly by CDM. The setup is also working out for general +untag packets as well. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ + 2 files changed, 10 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1864,6 +1864,12 @@ static int mtk_hw_init(struct mtk_eth *e + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); + ++ /* Indicates CDM to parse the MTK special tag from CPU ++ * which also is working out for untag packets. ++ */ ++ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -74,6 +74,10 @@ + #define MTK_CDMQ_IG_CTRL 0x1400 + #define MTK_CDMQ_STAG_EN BIT(0) + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMQ_IG_CTRL 0x1400 ++#define MTK_CDMQ_STAG_EN BIT(0) ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + diff --git a/target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch b/target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch new file mode 100644 index 0000000000..47a06838a3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0030-net-next-dsa-add-dsa-support-for-Mediatek-MT7530-swi.patch @@ -0,0 +1,1584 @@ +From 6a0a62dec3c582db4260f411294770448efc3d6c Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Wed, 29 Mar 2017 17:38:23 +0800 +Subject: [PATCH 30/57] net-next: dsa: add dsa support for Mediatek MT7530 + switch + +MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on +Mediatek router platforms such as MT7623A or MT7623N platform which +includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY. +Among these ports, The port from 0 to 4 are the user ports connecting +with the remote devices while the port 5 and 6 are the CPU ports +connecting into Mediatek Ethernet GMAC. + +For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC +through either the TRGMII or RGMII which could be controlled by phy-mode +in the dt-bindings to specify which mode is preferred to use. And for +port 5, only RGMII can be specified. However, currently, only port 6 is +being supported in this DSA driver. + +The driver is made with the reference to qca8k and other existing DSA +driver. The most of the essential callbacks of the DSA are already +support in the driver, including tag insert for user port distinguishing, +port control, bridge offloading, STP setup and ethtool operation to allow +DSA to model each user port into a standalone netdevice as the other DSA +driver had done. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +--- + drivers/net/dsa/Kconfig | 8 + + drivers/net/dsa/Makefile | 2 +- + drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.h | 390 ++++++++++++++++ + 4 files changed, 1525 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/dsa/mt7530.c + create mode 100644 drivers/net/dsa/mt7530.h + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -34,4 +34,12 @@ config NET_DSA_QCA8K + This enables support for the Qualcomm Atheros QCA8K Ethernet + switch chips. + ++config NET_DSA_MT7530 ++ tristate "Mediatek MT7530 Ethernet switch support" ++ depends on NET_DSA ++ select NET_DSA_TAG_MTK ++ ---help--- ++ This enables support for the Mediatek MT7530 Ethernet switch ++ chip. ++ + endmenu +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -1,6 +1,6 @@ + obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o + obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o + obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +- ++obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-y += b53/ + obj-y += mv88e6xxx/ +--- /dev/null ++++ b/drivers/net/dsa/mt7530.c +@@ -0,0 +1,1126 @@ ++/* ++ * Mediatek MT7530 DSA Switch driver ++ * Copyright (C) 2017 Sean Wang ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mt7530.h" ++ ++/* String, offset, and register size in bytes if different from 4 bytes */ ++static const struct mt7530_mib_desc mt7530_mib[] = { ++ MIB_DESC(1, 0x00, "TxDrop"), ++ MIB_DESC(1, 0x04, "TxCrcErr"), ++ MIB_DESC(1, 0x08, "TxUnicast"), ++ MIB_DESC(1, 0x0c, "TxMulticast"), ++ MIB_DESC(1, 0x10, "TxBroadcast"), ++ MIB_DESC(1, 0x14, "TxCollision"), ++ MIB_DESC(1, 0x18, "TxSingleCollision"), ++ MIB_DESC(1, 0x1c, "TxMultipleCollision"), ++ MIB_DESC(1, 0x20, "TxDeferred"), ++ MIB_DESC(1, 0x24, "TxLateCollision"), ++ MIB_DESC(1, 0x28, "TxExcessiveCollistion"), ++ MIB_DESC(1, 0x2c, "TxPause"), ++ MIB_DESC(1, 0x30, "TxPktSz64"), ++ MIB_DESC(1, 0x34, "TxPktSz65To127"), ++ MIB_DESC(1, 0x38, "TxPktSz128To255"), ++ MIB_DESC(1, 0x3c, "TxPktSz256To511"), ++ MIB_DESC(1, 0x40, "TxPktSz512To1023"), ++ MIB_DESC(1, 0x44, "Tx1024ToMax"), ++ MIB_DESC(2, 0x48, "TxBytes"), ++ MIB_DESC(1, 0x60, "RxDrop"), ++ MIB_DESC(1, 0x64, "RxFiltering"), ++ MIB_DESC(1, 0x6c, "RxMulticast"), ++ MIB_DESC(1, 0x70, "RxBroadcast"), ++ MIB_DESC(1, 0x74, "RxAlignErr"), ++ MIB_DESC(1, 0x78, "RxCrcErr"), ++ MIB_DESC(1, 0x7c, "RxUnderSizeErr"), ++ MIB_DESC(1, 0x80, "RxFragErr"), ++ MIB_DESC(1, 0x84, "RxOverSzErr"), ++ MIB_DESC(1, 0x88, "RxJabberErr"), ++ MIB_DESC(1, 0x8c, "RxPause"), ++ MIB_DESC(1, 0x90, "RxPktSz64"), ++ MIB_DESC(1, 0x94, "RxPktSz65To127"), ++ MIB_DESC(1, 0x98, "RxPktSz128To255"), ++ MIB_DESC(1, 0x9c, "RxPktSz256To511"), ++ MIB_DESC(1, 0xa0, "RxPktSz512To1023"), ++ MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"), ++ MIB_DESC(2, 0xa8, "RxBytes"), ++ MIB_DESC(1, 0xb0, "RxCtrlDrop"), ++ MIB_DESC(1, 0xb4, "RxIngressDrop"), ++ MIB_DESC(1, 0xb8, "RxArlDrop"), ++}; ++ ++static struct mt7530_priv *lpriv; ++static void mt7530_port_disable(struct dsa_switch *ds, int port, ++ struct phy_device *phy); ++static int mt7530_cpu_port_enable(struct mt7530_priv *priv, ++ int port); ++ ++static int ++mt7623_trgmii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->ethernet, TRGMII_BASE(reg), val); ++ if (ret < 0) ++ dev_err(priv->dev, ++ "failed to priv write register\n"); ++ return ret; ++} ++ ++static u32 ++mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg) ++{ ++ int ret; ++ u32 val; ++ ++ ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val); ++ if (ret < 0) { ++ dev_err(priv->dev, ++ "failed to priv read register\n"); ++ return ret; ++ } ++ ++ return val; ++} ++ ++static void ++mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg, ++ u32 mask, u32 set) ++{ ++ u32 val; ++ ++ val = mt7623_trgmii_read(priv, reg); ++ val &= ~mask; ++ val |= set; ++ mt7623_trgmii_write(priv, reg, val); ++} ++ ++static void ++mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7623_trgmii_rmw(priv, reg, 0, val); ++} ++ ++static void ++mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7623_trgmii_rmw(priv, reg, val, 0); ++} ++ ++static int ++core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad) ++{ ++ struct mii_bus *bus = priv->bus; ++ int value, ret; ++ ++ /* Write the desired MMD Devad */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the desired MMD register address */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); ++ if (ret < 0) ++ goto err; ++ ++ /* Select the Function : DATA with no post increment */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); ++ if (ret < 0) ++ goto err; ++ ++ /* Read the content of the MMD's selected register */ ++ value = bus->read(bus, 0, MII_MMD_DATA); ++ ++ return value; ++err: ++ dev_err(&bus->dev, "failed to read mmd register\n"); ++ ++ return ret; ++} ++ ++static int ++core_write_mmd_indirect(struct mt7530_priv *priv, int prtad, ++ int devad, u32 data) ++{ ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ /* Write the desired MMD Devad */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the desired MMD register address */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); ++ if (ret < 0) ++ goto err; ++ ++ /* Select the Function : DATA with no post increment */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the data into MMD's selected register */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, data); ++err: ++ if (ret < 0) ++ dev_err(&bus->dev, ++ "failed to write mmd register\n"); ++ return ret; ++} ++ ++static void ++core_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set) ++{ ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2); ++ val &= ~mask; ++ val |= set; ++ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++core_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ core_rmw(priv, reg, 0, val); ++} ++ ++static void ++core_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ core_rmw(priv, reg, val, 0); ++} ++ ++static int ++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ lo = val & 0xffff; ++ hi = val >> 16; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) ++ goto err; ++ ++ ret = bus->write(bus, 0x1f, r, lo); ++ if (ret < 0) ++ goto err; ++ ++ ret = bus->write(bus, 0x1f, 0x10, hi); ++err: ++ if (ret < 0) ++ dev_err(&bus->dev, ++ "failed to write mt7530 register\n"); ++ return ret; ++} ++ ++static u32 ++mt7530_mii_read(struct mt7530_priv *priv, u32 reg) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) { ++ dev_err(&bus->dev, ++ "failed to read mt7530 register\n"); ++ return ret; ++ } ++ ++ lo = bus->read(bus, 0x1f, r); ++ hi = bus->read(bus, 0x1f, 0x10); ++ ++ return (hi << 16) | (lo & 0xffff); ++} ++ ++static void ++mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ mt7530_mii_write(priv, reg, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static u32 ++_mt7530_read(u32 reg) ++{ ++ struct mt7530_priv *priv = lpriv; ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = mt7530_mii_read(priv, reg); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return val; ++} ++ ++static u32 ++mt7530_read(struct mt7530_priv *priv, u32 reg) ++{ ++ return _mt7530_read(reg); ++} ++ ++static void ++mt7530_rmw(struct mt7530_priv *priv, u32 reg, ++ u32 mask, u32 set) ++{ ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = mt7530_mii_read(priv, reg); ++ val &= ~mask; ++ val |= set; ++ mt7530_mii_write(priv, reg, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7530_rmw(priv, reg, 0, val); ++} ++ ++static void ++mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7530_rmw(priv, reg, val, 0); ++} ++ ++static int ++mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp) ++{ ++ u32 val; ++ int ret; ++ ++ /* Set the command operating upon the MAC address entries */ ++ val = ATC_BUSY | ATC_MAT(0) | cmd; ++ mt7530_write(priv, MT7530_ATC, val); ++ ++ ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val, ++ !(val & ATC_BUSY), 20, 20000); ++ if (ret < 0) { ++ dev_err(priv->dev, "reset timeout\n"); ++ return ret; ++ } ++ ++ /* Additional sanity for read command if the specified ++ * entry is invalid ++ */ ++ val = mt7530_read(priv, MT7530_ATC); ++ if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID)) ++ return -EINVAL; ++ ++ if (rsp) ++ *rsp = val; ++ ++ return 0; ++} ++ ++static void ++mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb) ++{ ++ u32 reg[3]; ++ int i; ++ ++ /* Read from ARL table into an array */ ++ for (i = 0; i < 3; i++) { ++ reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4)); ++ ++ dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n", ++ __func__, __LINE__, i, reg[i]); ++ } ++ ++ fdb->vid = (reg[1] >> CVID) & CVID_MASK; ++ fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK; ++ fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK; ++ fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK; ++ fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK; ++ fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK; ++ fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK; ++ fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK; ++ fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK; ++ fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT; ++} ++ ++static void ++mt7530_fdb_write(struct mt7530_priv *priv, u16 vid, ++ u8 port_mask, const u8 *mac, ++ u8 aging, u8 type) ++{ ++ u32 reg[3] = { 0 }; ++ int i; ++ ++ reg[1] |= vid & CVID_MASK; ++ reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER; ++ reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP; ++ /* STATIC_ENT indicate that entry is static wouldn't ++ * be aged out and STATIC_EMP specified as erasing an ++ * entry ++ */ ++ reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS; ++ reg[1] |= mac[5] << MAC_BYTE_5; ++ reg[1] |= mac[4] << MAC_BYTE_4; ++ reg[0] |= mac[3] << MAC_BYTE_3; ++ reg[0] |= mac[2] << MAC_BYTE_2; ++ reg[0] |= mac[1] << MAC_BYTE_1; ++ reg[0] |= mac[0] << MAC_BYTE_0; ++ ++ /* Write array into the ARL table */ ++ for (i = 0; i < 3; i++) ++ mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]); ++} ++ ++static int ++mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 ncpo1, ssc_delta, trgint, i; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ trgint = 0; ++ ncpo1 = 0x0c80; ++ ssc_delta = 0x87; ++ break; ++ case PHY_INTERFACE_MODE_TRGMII: ++ trgint = 1; ++ ncpo1 = 0x1400; ++ ssc_delta = 0x57; ++ break; ++ default: ++ dev_err(priv->dev, "xMII mode %d not supported\n", mode); ++ return -EINVAL; ++ } ++ ++ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, ++ P6_INTF_MODE(trgint)); ++ ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) ++ mt7530_write(priv, MT7530_TRGMII_TD_ODT(i), ++ TD_DM_DRVP(8) | TD_DM_DRVN(8)); ++ ++ /* Setup core clock for MT7530 */ ++ if (!trgint) { ++ /* Disable MT7530 core clock */ ++ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ ++ /* Disable PLL, since phy_device has not yet been created ++ * provided for phy_[read,write]_mmd_indirect is called, we ++ * provide our own core_write_mmd_indirect to complete this ++ * function. ++ */ ++ core_write_mmd_indirect(priv, ++ CORE_GSWPLL_GRP1, ++ MDIO_MMD_VEND2, ++ 0); ++ ++ /* Set core clock into 500Mhz */ ++ core_write(priv, CORE_GSWPLL_GRP2, ++ RG_GSWPLL_POSDIV_500M(1) | ++ RG_GSWPLL_FBKDIV_500M(25)); ++ ++ /* Enable PLL */ ++ core_write(priv, CORE_GSWPLL_GRP1, ++ RG_GSWPLL_EN_PRE | ++ RG_GSWPLL_POSDIV_200M(2) | ++ RG_GSWPLL_FBKDIV_200M(32)); ++ ++ /* Enable MT7530 core clock */ ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ } ++ ++ /* Setup the MT7530 TRGMII Tx Clock */ ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); ++ core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); ++ core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); ++ core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); ++ core_write(priv, CORE_PLL_GROUP4, ++ RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | ++ RG_SYSPLL_BIAS_LPF_EN); ++ core_write(priv, CORE_PLL_GROUP2, ++ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | ++ RG_SYSPLL_POSDIV(1)); ++ core_write(priv, CORE_PLL_GROUP7, ++ RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | ++ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, ++ REG_GSWCK_EN | REG_TRGMIICK_EN); ++ ++ if (!trgint) ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt7530_rmw(priv, MT7530_TRGMII_RD(i), ++ RD_TAP_MASK, RD_TAP(16)); ++ else ++ mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII); ++ ++ return 0; ++} ++ ++static int ++mt7623_pad_clk_setup(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int i; ++ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i), ++ TD_DM_DRVP(8) | TD_DM_DRVN(8)); ++ ++ mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL); ++ mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST); ++ ++ return 0; ++} ++ ++static void ++mt7530_mib_reset(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH); ++ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE); ++} ++ ++static void ++mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable) ++{ ++ u32 mask = PMCR_TX_EN | PMCR_RX_EN; ++ ++ if (enable) ++ mt7530_set(priv, MT7530_PMCR_P(port), mask); ++ else ++ mt7530_clear(priv, MT7530_PMCR_P(port), mask); ++} ++ ++static int ++mt7530_setup(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret, i; ++ u32 id, val; ++ struct device_node *dn; ++ ++ /* The parent node of master_netdev which holds the common system ++ * controller also is the container for two GMACs nodes representing ++ * as two netdev instances. ++ */ ++ dn = ds->master_netdev->dev.of_node->parent; ++ priv->ethernet = syscon_node_to_regmap(dn); ++ if (IS_ERR(priv->ethernet)) ++ return PTR_ERR(priv->ethernet); ++ ++ regulator_set_voltage(priv->core_pwr, 1000000, 1000000); ++ ret = regulator_enable(priv->core_pwr); ++ if (ret < 0) { ++ dev_err(priv->dev, ++ "Failed to enable core power: %d\n", ret); ++ return ret; ++ } ++ ++ regulator_set_voltage(priv->io_pwr, 3300000, 3300000); ++ ret = regulator_enable(priv->io_pwr); ++ if (ret < 0) { ++ dev_err(priv->dev, "Failed to enable io pwr: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Reset whole chip through gpio pin or memory-mapped registers for ++ * different type of hardware ++ */ ++ if (priv->mcm) { ++ reset_control_assert(priv->rstc); ++ usleep_range(1000, 1100); ++ reset_control_deassert(priv->rstc); ++ } else { ++ gpiod_set_value_cansleep(priv->reset, 0); ++ usleep_range(1000, 1100); ++ gpiod_set_value_cansleep(priv->reset, 1); ++ } ++ ++ /* Waiting for MT7530 got to stable */ ++ ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0, ++ 20, 1000000); ++ if (ret < 0) { ++ dev_err(priv->dev, "reset timeout\n"); ++ return ret; ++ } ++ ++ id = mt7530_read(priv, MT7530_CREV); ++ id >>= CHIP_NAME_SHIFT; ++ if (id != MT7530_ID) { ++ dev_err(priv->dev, "chip %x can't be supported\n", id); ++ return -ENODEV; ++ } ++ ++ /* Reset the switch through internal reset */ ++ mt7530_write(priv, MT7530_SYS_CTRL, ++ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | ++ SYS_CTRL_REG_RST); ++ ++ /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ ++ val = mt7530_read(priv, MT7530_MHWTRAP); ++ val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; ++ val |= MHWTRAP_MANUAL; ++ mt7530_write(priv, MT7530_MHWTRAP, val); ++ ++ /* Enable and reset MIB counters */ ++ mt7530_mib_reset(ds); ++ ++ mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ ++ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, ++ PCR_MATRIX_CLR); ++ ++ if (dsa_is_cpu_port(ds, i)) ++ mt7530_cpu_port_enable(priv, i); ++ else ++ mt7530_port_disable(ds, i, NULL); ++ } ++ ++ /* Flush the FDB table */ ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ return mdiobus_read_nested(priv->bus, port, regnum); ++} ++ ++int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ return mdiobus_write_nested(priv->bus, port, regnum, val); ++} ++ ++static void ++mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) ++ strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name, ++ ETH_GSTRING_LEN); ++} ++ ++static void ++mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ const struct mt7530_mib_desc *mib; ++ u32 reg, i; ++ u64 hi; ++ ++ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) { ++ mib = &mt7530_mib[i]; ++ reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset; ++ ++ data[i] = mt7530_read(priv, reg); ++ if (mib->size == 2) { ++ hi = mt7530_read(priv, reg + 4); ++ data[i] |= hi << 32; ++ } ++ } ++} ++ ++static int ++mt7530_get_sset_count(struct dsa_switch *ds) ++{ ++ return ARRAY_SIZE(mt7530_mib); ++} ++ ++static void mt7530_adjust_link(struct dsa_switch *ds, int port, ++ struct phy_device *phydev) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ if (phy_is_pseudo_fixed_link(phydev)) { ++ dev_dbg(priv->dev, "phy-mode for master device = %x\n", ++ phydev->interface); ++ ++ /* Setup TX circuit incluing relevant PAD and driving */ ++ mt7530_pad_clk_setup(ds, phydev->interface); ++ ++ /* Setup RX circuit, relevant PAD and driving on the host ++ * which must be placed after the setup on the device side is ++ * all finished. ++ */ ++ mt7623_pad_clk_setup(ds); ++ } ++} ++ ++static int ++mt7530_cpu_port_enable(struct mt7530_priv *priv, ++ int port) ++{ ++ /* Enable Mediatek header mode on the cpu port */ ++ mt7530_write(priv, MT7530_PVC_P(port), ++ PORT_SPEC_TAG); ++ ++ /* Setup the MAC by default for the cpu port */ ++ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); ++ ++ /* Disable auto learning on the cpu port */ ++ mt7530_set(priv, MT7530_PSC_P(port), SA_DIS); ++ ++ /* Unknown unicast frame fordwarding to the cpu port */ ++ mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port))); ++ ++ /* CPU port gets connected to all user ports of ++ * the switch ++ */ ++ mt7530_write(priv, MT7530_PCR_P(port), ++ PCR_MATRIX(priv->ds->enabled_port_mask)); ++ ++ return 0; ++} ++ ++static int ++mt7530_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Setup the MAC for the user port */ ++ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK); ++ ++ /* Allow the user port gets connected to the cpu port and also ++ * restore the port matrix if the port is the member of a certain ++ * bridge. ++ */ ++ priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ priv->ports[port].enable = true; ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ priv->ports[port].pm); ++ mt7530_port_set_status(priv, port, 1); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static void ++mt7530_port_disable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Clear up all port matrix which could be restored in the next ++ * enablement for the port. ++ */ ++ priv->ports[port].enable = false; ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ PCR_MATRIX_CLR); ++ mt7530_port_set_status(priv, port, 0); ++ ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static void ++mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = MT7530_STP_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = MT7530_STP_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = MT7530_STP_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = MT7530_STP_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ default: ++ stp_state = MT7530_STP_FORWARDING; ++ break; ++ } ++ ++ mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state); ++} ++ ++static int ++mt7530_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 port_bitmap = BIT(MT7530_CPU_PORT); ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Add this port to the port matrix of the other ports in the ++ * same bridge. If the port is disabled, port matrix is kept ++ * and not being setup until the port becomes enabled. ++ */ ++ if (ds->enabled_port_mask & BIT(i) && i != port) { ++ if (ds->ports[i].bridge_dev != bridge) ++ continue; ++ if (priv->ports[i].enable) ++ mt7530_set(priv, MT7530_PCR_P(i), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[i].pm |= PCR_MATRIX(BIT(port)); ++ ++ port_bitmap |= BIT(i); ++ } ++ } ++ ++ /* Add the all other ports to this port matrix. */ ++ if (priv->ports[port].enable) ++ mt7530_rmw(priv, MT7530_PCR_P(port), ++ PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap)); ++ priv->ports[port].pm |= PCR_MATRIX(port_bitmap); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static void ++mt7530_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Remove this port from the port matrix of the other ports ++ * in the same bridge. If the port is disabled, port matrix ++ * is kept and not being setup until the port becomes enabled. ++ */ ++ if (ds->enabled_port_mask & BIT(i) && i != port) { ++ if (ds->ports[i].bridge_dev != bridge) ++ continue; ++ if (priv->ports[i].enable) ++ mt7530_clear(priv, MT7530_PCR_P(i), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[i].pm &= ~PCR_MATRIX(BIT(port)); ++ } ++ } ++ ++ /* Set the cpu port to be the only one in the port matrix of ++ * this port. ++ */ ++ if (priv->ports[port].enable) ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ PCR_MATRIX(BIT(MT7530_CPU_PORT))); ++ priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++mt7530_port_fdb_prepare(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb, ++ struct switchdev_trans *trans) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret; ++ ++ /* Because auto-learned entrie shares the same FDB table. ++ * an entry is reserved with no port_mask to make sure fdb_add ++ * is called while the entry is still available. ++ */ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT); ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static void ++mt7530_port_fdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb, ++ struct switchdev_trans *trans) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u8 port_mask = BIT(port); ++ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT); ++ mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++mt7530_port_fdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret; ++ u8 port_mask = BIT(port); ++ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP); ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++mt7530_port_fdb_dump(struct dsa_switch *ds, int port, ++ struct switchdev_obj_port_fdb *fdb, ++ int (*cb)(struct switchdev_obj *obj)) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ struct mt7530_fdb _fdb = { 0 }; ++ int cnt = MT7530_NUM_FDB_RECORDS; ++ int ret = 0; ++ u32 rsp = 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp); ++ if (ret < 0) ++ goto err; ++ ++ do { ++ if (rsp & ATC_SRCH_HIT) { ++ mt7530_fdb_read(priv, &_fdb); ++ if (_fdb.port_mask & BIT(port)) { ++ ether_addr_copy(fdb->addr, _fdb.mac); ++ fdb->vid = _fdb.vid; ++ fdb->ndm_state = _fdb.noarp ? ++ NUD_NOARP : NUD_REACHABLE; ++ ret = cb(&fdb->obj); ++ if (ret < 0) ++ break; ++ } ++ } ++ } while (--cnt && ++ !(rsp & ATC_SRCH_END) && ++ !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp)); ++err: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static enum dsa_tag_protocol ++mtk_get_tag_protocol(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { ++ dev_warn(priv->dev, ++ "port not matched with tagging CPU port\n"); ++ return DSA_TAG_PROTO_NONE; ++ } else { ++ return DSA_TAG_PROTO_MTK; ++ } ++} ++ ++static struct dsa_switch_ops mt7530_switch_ops = { ++ .get_tag_protocol = mtk_get_tag_protocol, ++ .setup = mt7530_setup, ++ .get_strings = mt7530_get_strings, ++ .phy_read = mt7530_phy_read, ++ .phy_write = mt7530_phy_write, ++ .get_ethtool_stats = mt7530_get_ethtool_stats, ++ .get_sset_count = mt7530_get_sset_count, ++ .adjust_link = mt7530_adjust_link, ++ .port_enable = mt7530_port_enable, ++ .port_disable = mt7530_port_disable, ++ .port_stp_state_set = mt7530_stp_state_set, ++ .port_bridge_join = mt7530_port_bridge_join, ++ .port_bridge_leave = mt7530_port_bridge_leave, ++ .port_fdb_prepare = mt7530_port_fdb_prepare, ++ .port_fdb_add = mt7530_port_fdb_add, ++ .port_fdb_del = mt7530_port_fdb_del, ++ .port_fdb_dump = mt7530_port_fdb_dump, ++}; ++ ++static int ++mt7530_probe(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv; ++ struct device_node *dn; ++ ++ dn = mdiodev->dev.of_node; ++ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); ++ if (!priv->ds) ++ return -ENOMEM; ++ ++ /* Use medatek,mcm property to distinguish hardware type that would ++ * casues a little bit differences on power-on sequence. ++ */ ++ priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); ++ if (priv->mcm) { ++ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); ++ ++ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); ++ if (IS_ERR(priv->rstc)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->rstc); ++ } ++ } ++ ++ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); ++ if (IS_ERR(priv->core_pwr)) ++ return PTR_ERR(priv->core_pwr); ++ ++ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); ++ if (IS_ERR(priv->io_pwr)) ++ return PTR_ERR(priv->io_pwr); ++ ++ /* Not MCM that indicates switch works as the remote standalone ++ * integrated circuit so the GPIO pin would be used to complete ++ * the reset, otherwise memory-mapped register accessing used ++ * through syscon provides in the case of MCM. ++ */ ++ if (!priv->mcm) { ++ priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(priv->reset)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->reset); ++ } ++ } ++ ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ priv->ds->priv = priv; ++ priv->ds->ops = &mt7530_switch_ops; ++ mutex_init(&priv->reg_mutex); ++ lpriv = priv; ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return dsa_register_switch(priv->ds, &mdiodev->dev); ++} ++ ++static void ++mt7530_remove(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ int ret = 0; ++ ++ ret = regulator_disable(priv->core_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, ++ "Failed to disable core power: %d\n", ret); ++ ++ ret = regulator_disable(priv->io_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, "Failed to disable io pwr: %d\n", ++ ret); ++ ++ dsa_unregister_switch(priv->ds); ++ mutex_destroy(&priv->reg_mutex); ++} ++ ++static const struct of_device_id mt7530_of_match[] = { ++ { .compatible = "mediatek,mt7530" }, ++ { /* sentinel */ }, ++}; ++ ++static struct mdio_driver mt7530_mdio_driver = { ++ .probe = mt7530_probe, ++ .remove = mt7530_remove, ++ .mdiodrv.driver = { ++ .name = "mt7530", ++ .of_match_table = mt7530_of_match, ++ }, ++}; ++ ++mdio_module_driver(mt7530_mdio_driver); ++ ++MODULE_AUTHOR("Sean Wang "); ++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:mediatek-mt7530"); +--- /dev/null ++++ b/drivers/net/dsa/mt7530.h +@@ -0,0 +1,390 @@ ++/* ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __MT7530_H ++#define __MT7530_H ++ ++#define MT7530_NUM_PORTS 7 ++#define MT7530_CPU_PORT 6 ++#define MT7530_NUM_FDB_RECORDS 2048 ++ ++#define NUM_TRGMII_CTRL 5 ++ ++#define TRGMII_BASE(x) (0x10000 + (x)) ++ ++/* Registers to ethsys access */ ++#define ETHSYS_CLKCFG0 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++#define SYSC_REG_RSTCTRL 0x34 ++#define RESET_MCM BIT(2) ++ ++/* Registers to mac forward control for unknown frames */ ++#define MT7530_MFC 0x10 ++#define BC_FFP(x) (((x) & 0xff) << 24) ++#define UNM_FFP(x) (((x) & 0xff) << 16) ++#define UNU_FFP(x) (((x) & 0xff) << 8) ++#define UNU_FFP_MASK UNU_FFP(~0) ++ ++/* Registers for address table access */ ++#define MT7530_ATA1 0x74 ++#define STATIC_EMP 0 ++#define STATIC_ENT 3 ++#define MT7530_ATA2 0x78 ++ ++/* Register for address table write data */ ++#define MT7530_ATWD 0x7c ++ ++/* Register for address table control */ ++#define MT7530_ATC 0x80 ++#define ATC_HASH (((x) & 0xfff) << 16) ++#define ATC_BUSY BIT(15) ++#define ATC_SRCH_END BIT(14) ++#define ATC_SRCH_HIT BIT(13) ++#define ATC_INVALID BIT(12) ++#define ATC_MAT(x) (((x) & 0xf) << 8) ++#define ATC_MAT_MACTAB ATC_MAT(0) ++ ++enum mt7530_fdb_cmd { ++ MT7530_FDB_READ = 0, ++ MT7530_FDB_WRITE = 1, ++ MT7530_FDB_FLUSH = 2, ++ MT7530_FDB_START = 4, ++ MT7530_FDB_NEXT = 5, ++}; ++ ++/* Registers for table search read address */ ++#define MT7530_TSRA1 0x84 ++#define MAC_BYTE_0 24 ++#define MAC_BYTE_1 16 ++#define MAC_BYTE_2 8 ++#define MAC_BYTE_3 0 ++#define MAC_BYTE_MASK 0xff ++ ++#define MT7530_TSRA2 0x88 ++#define MAC_BYTE_4 24 ++#define MAC_BYTE_5 16 ++#define CVID 0 ++#define CVID_MASK 0xfff ++ ++#define MT7530_ATRD 0x8C ++#define AGE_TIMER 24 ++#define AGE_TIMER_MASK 0xff ++#define PORT_MAP 4 ++#define PORT_MAP_MASK 0xff ++#define ENT_STATUS 2 ++#define ENT_STATUS_MASK 0x3 ++ ++/* Register for vlan table control */ ++#define MT7530_VTCR 0x90 ++#define VTCR_BUSY BIT(31) ++#define VTCR_FUNC (((x) & 0xf) << 12) ++#define VTCR_FUNC_RD_VID 0x1 ++#define VTCR_FUNC_WR_VID 0x2 ++#define VTCR_FUNC_INV_VID 0x3 ++#define VTCR_FUNC_VAL_VID 0x4 ++#define VTCR_VID ((x) & 0xfff) ++ ++/* Register for setup vlan and acl write data */ ++#define MT7530_VAWD1 0x94 ++#define PORT_STAG BIT(31) ++#define IVL_MAC BIT(30) ++#define PORT_MEM(x) (((x) & 0xff) << 16) ++#define VALID BIT(1) ++ ++#define MT7530_VAWD2 0x98 ++ ++/* Register for port STP state control */ ++#define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100)) ++#define FID_PST(x) ((x) & 0x3) ++#define FID_PST_MASK FID_PST(0x3) ++ ++enum mt7530_stp_state { ++ MT7530_STP_DISABLED = 0, ++ MT7530_STP_BLOCKING = 1, ++ MT7530_STP_LISTENING = 1, ++ MT7530_STP_LEARNING = 2, ++ MT7530_STP_FORWARDING = 3 ++}; ++ ++/* Register for port control */ ++#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100)) ++#define PORT_VLAN(x) ((x) & 0x3) ++#define PCR_MATRIX(x) (((x) & 0xff) << 16) ++#define PORT_PRI(x) (((x) & 0x7) << 24) ++#define EG_TAG(x) (((x) & 0x3) << 28) ++#define PCR_MATRIX_MASK PCR_MATRIX(0xff) ++#define PCR_MATRIX_CLR PCR_MATRIX(0) ++ ++/* Register for port security control */ ++#define MT7530_PSC_P(x) (0x200c + ((x) * 0x100)) ++#define SA_DIS BIT(4) ++ ++/* Register for port vlan control */ ++#define MT7530_PVC_P(x) (0x2010 + ((x) * 0x100)) ++#define PORT_SPEC_TAG BIT(5) ++#define VLAN_ATTR(x) (((x) & 0x3) << 6) ++#define STAG_VPID (((x) & 0xffff) << 16) ++ ++/* Register for port port-and-protocol based vlan 1 control */ ++#define MT7530_PPBV1_P(x) (0x2014 + ((x) * 0x100)) ++ ++/* Register for port MAC control register */ ++#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100)) ++#define PMCR_IFG_XMIT(x) (((x) & 0x3) << 18) ++#define PMCR_MAC_MODE BIT(16) ++#define PMCR_FORCE_MODE BIT(15) ++#define PMCR_TX_EN BIT(14) ++#define PMCR_RX_EN BIT(13) ++#define PMCR_BACKOFF_EN BIT(9) ++#define PMCR_BACKPR_EN BIT(8) ++#define PMCR_TX_FC_EN BIT(5) ++#define PMCR_RX_FC_EN BIT(4) ++#define PMCR_FORCE_SPEED_1000 BIT(3) ++#define PMCR_FORCE_FDX BIT(1) ++#define PMCR_FORCE_LNK BIT(0) ++#define PMCR_COMMON_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ ++ PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ ++ PMCR_TX_EN | PMCR_RX_EN | \ ++ PMCR_TX_FC_EN | PMCR_RX_FC_EN) ++#define PMCR_CPUP_LINK (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \ ++ PMCR_FORCE_SPEED_1000 | \ ++ PMCR_FORCE_FDX | \ ++ PMCR_FORCE_LNK) ++#define PMCR_USERP_LINK PMCR_COMMON_LINK ++#define PMCR_FIXED_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ ++ PMCR_FORCE_MODE | PMCR_TX_EN | \ ++ PMCR_RX_EN | PMCR_BACKPR_EN | \ ++ PMCR_BACKOFF_EN | \ ++ PMCR_FORCE_SPEED_1000 | \ ++ PMCR_FORCE_FDX | \ ++ PMCR_FORCE_LNK) ++#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \ ++ PMCR_TX_FC_EN | PMCR_RX_FC_EN) ++ ++#define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100) ++ ++/* Register for MIB */ ++#define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100) ++#define MT7530_MIB_CCR 0x4fe0 ++#define CCR_MIB_ENABLE BIT(31) ++#define CCR_RX_OCT_CNT_GOOD BIT(7) ++#define CCR_RX_OCT_CNT_BAD BIT(6) ++#define CCR_TX_OCT_CNT_GOOD BIT(5) ++#define CCR_TX_OCT_CNT_BAD BIT(4) ++#define CCR_MIB_FLUSH (CCR_RX_OCT_CNT_GOOD | \ ++ CCR_RX_OCT_CNT_BAD | \ ++ CCR_TX_OCT_CNT_GOOD | \ ++ CCR_TX_OCT_CNT_BAD) ++#define CCR_MIB_ACTIVATE (CCR_MIB_ENABLE | \ ++ CCR_RX_OCT_CNT_GOOD | \ ++ CCR_RX_OCT_CNT_BAD | \ ++ CCR_TX_OCT_CNT_GOOD | \ ++ CCR_TX_OCT_CNT_BAD) ++/* Register for system reset */ ++#define MT7530_SYS_CTRL 0x7000 ++#define SYS_CTRL_PHY_RST BIT(2) ++#define SYS_CTRL_SW_RST BIT(1) ++#define SYS_CTRL_REG_RST BIT(0) ++ ++/* Register for hw trap status */ ++#define MT7530_HWTRAP 0x7800 ++ ++/* Register for hw trap modification */ ++#define MT7530_MHWTRAP 0x7804 ++#define MHWTRAP_MANUAL BIT(16) ++#define MHWTRAP_P5_MAC_SEL BIT(13) ++#define MHWTRAP_P6_DIS BIT(8) ++#define MHWTRAP_P5_RGMII_MODE BIT(7) ++#define MHWTRAP_P5_DIS BIT(6) ++#define MHWTRAP_PHY_ACCESS BIT(5) ++ ++/* Register for TOP signal control */ ++#define MT7530_TOP_SIG_CTRL 0x7808 ++#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) ++ ++#define MT7530_IO_DRV_CR 0x7810 ++#define P5_IO_CLK_DRV(x) ((x) & 0x3) ++#define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4) ++ ++#define MT7530_P6ECR 0x7830 ++#define P6_INTF_MODE_MASK 0x3 ++#define P6_INTF_MODE(x) ((x) & 0x3) ++ ++/* Registers for TRGMII on the both side */ ++#define MT7530_TRGMII_RCK_CTRL 0x7a00 ++#define GSW_TRGMII_RCK_CTRL 0x300 ++#define RX_RST BIT(31) ++#define RXC_DQSISEL BIT(30) ++#define DQSI1_TAP_MASK (0x7f << 8) ++#define DQSI0_TAP_MASK 0x7f ++#define DQSI1_TAP(x) (((x) & 0x7f) << 8) ++#define DQSI0_TAP(x) ((x) & 0x7f) ++ ++#define MT7530_TRGMII_RCK_RTT 0x7a04 ++#define GSW_TRGMII_RCK_RTT 0x304 ++#define DQS1_GATE BIT(31) ++#define DQS0_GATE BIT(30) ++ ++#define MT7530_TRGMII_RD(x) (0x7a10 + (x) * 8) ++#define GSW_TRGMII_RD(x) (0x310 + (x) * 8) ++#define BSLIP_EN BIT(31) ++#define EDGE_CHK BIT(30) ++#define RD_TAP_MASK 0x7f ++#define RD_TAP(x) ((x) & 0x7f) ++ ++#define GSW_TRGMII_TXCTRL 0x340 ++#define MT7530_TRGMII_TXCTRL 0x7a40 ++#define TRAIN_TXEN BIT(31) ++#define TXC_INV BIT(30) ++#define TX_RST BIT(28) ++ ++#define MT7530_TRGMII_TD_ODT(i) (0x7a54 + 8 * (i)) ++#define GSW_TRGMII_TD_ODT(i) (0x354 + 8 * (i)) ++#define TD_DM_DRVP(x) ((x) & 0xf) ++#define TD_DM_DRVN(x) (((x) & 0xf) << 4) ++ ++#define GSW_INTF_MODE 0x390 ++#define INTF_MODE_TRGMII BIT(1) ++ ++#define MT7530_TRGMII_TCK_CTRL 0x7a78 ++#define TCK_TAP(x) (((x) & 0xf) << 8) ++ ++#define MT7530_P5RGMIIRXCR 0x7b00 ++#define CSR_RGMII_EDGE_ALIGN BIT(8) ++#define CSR_RGMII_RXC_0DEG_CFG(x) ((x) & 0xf) ++ ++#define MT7530_P5RGMIITXCR 0x7b04 ++#define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f) ++ ++#define MT7530_CREV 0x7ffc ++#define CHIP_NAME_SHIFT 16 ++#define MT7530_ID 0x7530 ++ ++/* Registers for core PLL access through mmd indirect */ ++#define CORE_PLL_GROUP2 0x401 ++#define RG_SYSPLL_EN_NORMAL BIT(15) ++#define RG_SYSPLL_VODEN BIT(14) ++#define RG_SYSPLL_LF BIT(13) ++#define RG_SYSPLL_RST_DLY(x) (((x) & 0x3) << 12) ++#define RG_SYSPLL_LVROD_EN BIT(10) ++#define RG_SYSPLL_PREDIV(x) (((x) & 0x3) << 8) ++#define RG_SYSPLL_POSDIV(x) (((x) & 0x3) << 5) ++#define RG_SYSPLL_FBKSEL BIT(4) ++#define RT_SYSPLL_EN_AFE_OLT BIT(0) ++ ++#define CORE_PLL_GROUP4 0x403 ++#define RG_SYSPLL_DDSFBK_EN BIT(12) ++#define RG_SYSPLL_BIAS_EN BIT(11) ++#define RG_SYSPLL_BIAS_LPF_EN BIT(10) ++ ++#define CORE_PLL_GROUP5 0x404 ++#define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff) ++ ++#define CORE_PLL_GROUP6 0x405 ++#define RG_LCDDS_PCW_NCPO0(x) ((x) & 0xffff) ++ ++#define CORE_PLL_GROUP7 0x406 ++#define RG_LCDDS_PWDB BIT(15) ++#define RG_LCDDS_ISO_EN BIT(13) ++#define RG_LCCDS_C(x) (((x) & 0x7) << 4) ++#define RG_LCDDS_PCW_NCPO_CHG BIT(3) ++ ++#define CORE_PLL_GROUP10 0x409 ++#define RG_LCDDS_SSC_DELTA(x) ((x) & 0xfff) ++ ++#define CORE_PLL_GROUP11 0x40a ++#define RG_LCDDS_SSC_DELTA1(x) ((x) & 0xfff) ++ ++#define CORE_GSWPLL_GRP1 0x40d ++#define RG_GSWPLL_PREDIV(x) (((x) & 0x3) << 14) ++#define RG_GSWPLL_POSDIV_200M(x) (((x) & 0x3) << 12) ++#define RG_GSWPLL_EN_PRE BIT(11) ++#define RG_GSWPLL_FBKSEL BIT(10) ++#define RG_GSWPLL_BP BIT(9) ++#define RG_GSWPLL_BR BIT(8) ++#define RG_GSWPLL_FBKDIV_200M(x) ((x) & 0xff) ++ ++#define CORE_GSWPLL_GRP2 0x40e ++#define RG_GSWPLL_POSDIV_500M(x) (((x) & 0x3) << 8) ++#define RG_GSWPLL_FBKDIV_500M(x) ((x) & 0xff) ++ ++#define CORE_TRGMII_GSW_CLK_CG 0x410 ++#define REG_GSWCK_EN BIT(0) ++#define REG_TRGMIICK_EN BIT(1) ++ ++#define MIB_DESC(_s, _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++struct mt7530_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++}; ++ ++struct mt7530_fdb { ++ u16 vid; ++ u8 port_mask; ++ u8 aging; ++ u8 mac[6]; ++ bool noarp; ++}; ++ ++struct mt7530_port { ++ bool enable; ++ u32 pm; ++}; ++ ++/* struct mt7530_priv - This is the main data structure for holding the state ++ * of the driver ++ * @dev: The device pointer ++ * @ds: The pointer to the dsa core structure ++ * @bus: The bus used for the device and built-in PHY ++ * @rstc: The pointer to reset control used by MCM ++ * @ethernet: The regmap used for access TRGMII-based registers ++ * @core_pwr: The power supplied into the core ++ * @io_pwr: The power supplied into the I/O ++ * @reset: The descriptor for GPIO line tied to its reset pin ++ * @mcm: Flag for distinguishing if standalone IC or module ++ * coupling ++ * @ports: Holding the state among ports ++ * @reg_mutex: The lock for protecting among process accessing ++ * registers ++ */ ++struct mt7530_priv { ++ struct device *dev; ++ struct dsa_switch *ds; ++ struct mii_bus *bus; ++ struct reset_control *rstc; ++ struct regmap *ethernet; ++ struct regulator *core_pwr; ++ struct regulator *io_pwr; ++ struct gpio_desc *reset; ++ bool mcm; ++ ++ struct mt7530_port ports[MT7530_NUM_PORTS]; ++ /* protect among processes for registers access*/ ++ struct mutex reg_mutex; ++}; ++ ++struct mt7530_hw_stats { ++ const char *string; ++ u16 reg; ++ u8 sizeof_stat; ++}; ++ ++#endif /* __MT7530_H */ diff --git a/target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch b/target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch new file mode 100644 index 0000000000..9e52be845b --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0031-net-dsa-dsa-api-compat.patch @@ -0,0 +1,106 @@ +From a319687ac18dcc557a88054282508e061ad8495f Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:42:19 +0200 +Subject: [PATCH 31/57] net: dsa: dsa api compat + +make the latest driver work on the old API + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 14 ++++++++------ + drivers/net/dsa/mt7530.h | 2 ++ + net/dsa/tag_mtk.c | 2 +- + 3 files changed, 11 insertions(+), 7 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc + int i; + + mutex_lock(&priv->reg_mutex); ++ priv->bridge_dev[port] = bridge; + + for (i = 0; i < MT7530_NUM_PORTS; i++) { + /* Add this port to the port matrix of the other ports in the +@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc + * and not being setup until the port becomes enabled. + */ + if (ds->enabled_port_mask & BIT(i) && i != port) { +- if (ds->ports[i].bridge_dev != bridge) ++ if (priv->bridge_dev[i] != bridge) + continue; + if (priv->ports[i].enable) + mt7530_set(priv, MT7530_PCR_P(i), +@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc + } + + static void +-mt7530_port_bridge_leave(struct dsa_switch *ds, int port, +- struct net_device *bridge) ++mt7530_port_bridge_leave(struct dsa_switch *ds, int port) + { + struct mt7530_priv *priv = ds->priv; + int i; +@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit + * is kept and not being setup until the port becomes enabled. + */ + if (ds->enabled_port_mask & BIT(i) && i != port) { +- if (ds->ports[i].bridge_dev != bridge) ++ if (priv->bridge_dev[i] != priv->bridge_dev[port]) + continue; + if (priv->ports[i].enable) + mt7530_clear(priv, MT7530_PCR_P(i), +@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit + /* Set the cpu port to be the only one in the port matrix of + * this port. + */ ++ priv->bridge_dev[port] = NULL; + if (priv->ports[port].enable) + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, + PCR_MATRIX(BIT(MT7530_CPU_PORT))); +@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev + if (!priv) + return -ENOMEM; + +- priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); ++ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + +@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + priv->ds->priv = priv; ++ priv->ds->dev = &mdiodev->dev; + priv->ds->ops = &mt7530_switch_ops; + mutex_init(&priv->reg_mutex); + lpriv = priv; + dev_set_drvdata(&mdiodev->dev, priv); + +- return dsa_register_switch(priv->ds, &mdiodev->dev); ++ return dsa_register_switch(priv->ds, priv->ds->dev->of_node); + } + + static void +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -379,6 +379,8 @@ struct mt7530_priv { + struct mt7530_port ports[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ + struct mutex reg_mutex; ++ ++ struct net_device *bridge_dev[MT7530_NUM_PORTS]; + }; + + struct mt7530_hw_stats { +--- a/net/dsa/tag_mtk.c ++++ b/net/dsa/tag_mtk.c +@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru + /* Build the tag after the MAC Source Address */ + mtk_tag = skb->data + 2 * ETH_ALEN; + mtk_tag[0] = 0; +- mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; ++ mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK; + mtk_tag[2] = 0; + mtk_tag[3] = 0; + diff --git a/target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch b/target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch new file mode 100644 index 0000000000..6c96b067dc --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch @@ -0,0 +1,38 @@ +From 52e9ce30a2b3c414e0efb20632fefa7cfc5096e6 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:44:18 +0200 +Subject: [PATCH 32/57] net: dsa: mediatek: add support for GMAC2 wired to ext + phy + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 5 +++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++ + 2 files changed, 8 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -629,6 +629,11 @@ mt7530_setup(struct dsa_switch *ds) + val = mt7530_read(priv, MT7530_MHWTRAP); + val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; + val |= MHWTRAP_MANUAL; ++ if (!dsa_is_cpu_port(ds, 5)) { ++ val |= MHWTRAP_P5_DIS; ++ val |= MHWTRAP_P5_MAC_SEL; ++ val |= MHWTRAP_P5_RGMII_MODE; ++ } + mt7530_write(priv, MT7530_MHWTRAP, val); + + /* Enable and reset MIB counters */ +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -221,6 +221,9 @@ static void mtk_phy_link_adjust(struct n + netif_carrier_on(dev); + else + netif_carrier_off(dev); ++ ++ if (!of_phy_is_fixed_link(mac->of_node)) ++ phy_print_status(dev->phydev); + } + + static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, diff --git a/target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch b/target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch new file mode 100644 index 0000000000..8ff2bed8c1 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0033-net-dsa-add-multi-gmac-support.patch @@ -0,0 +1,272 @@ +From cce5dd6034ed1651ee25c910edee708e6b84a44a Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:45:08 +0200 +Subject: [PATCH 33/57] net: dsa: add multi gmac support + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 10 +--------- + include/net/dsa.h | 21 ++++++++++++++++++++- + net/dsa/dsa2.c | 40 +++++++++++++++++++++++++++++++++------- + net/dsa/dsa_priv.h | 1 + + net/dsa/slave.c | 26 ++++++++++++++++---------- + 5 files changed, 71 insertions(+), 27 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -996,15 +996,7 @@ err: + static enum dsa_tag_protocol + mtk_get_tag_protocol(struct dsa_switch *ds) + { +- struct mt7530_priv *priv = ds->priv; +- +- if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { +- dev_warn(priv->dev, +- "port not matched with tagging CPU port\n"); +- return DSA_TAG_PROTO_NONE; +- } else { +- return DSA_TAG_PROTO_MTK; +- } ++ return DSA_TAG_PROTO_MTK; + } + + static struct dsa_switch_ops mt7530_switch_ops = { +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -145,6 +145,8 @@ struct dsa_port { + struct device_node *dn; + unsigned int ageing_time; + u8 stp_state; ++ struct net_device *ethernet; ++ int upstream; + }; + + struct dsa_switch { +@@ -205,7 +207,7 @@ struct dsa_switch { + + static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) + { +- return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); ++ return !!(ds->cpu_port_mask & (1 << p)); + } + + static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p) +@@ -218,6 +220,11 @@ static inline bool dsa_is_port_initializ + return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; + } + ++static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p) ++{ ++ return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p); ++} ++ + static inline u8 dsa_upstream_port(struct dsa_switch *ds) + { + struct dsa_switch_tree *dst = ds->dst; +@@ -234,6 +241,18 @@ static inline u8 dsa_upstream_port(struc + return ds->rtable[dst->cpu_switch]; + } + ++static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port) ++{ ++ /* ++ * If this port has a specific upstream cpu port, use it, ++ * otherwise use the switch default. ++ */ ++ if (ds->ports[port].upstream) ++ return ds->ports[port].upstream; ++ else ++ return dsa_upstream_port(ds); ++} ++ + struct switchdev_trans; + struct switchdev_obj; + struct switchdev_obj_port_fdb; +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -248,8 +248,6 @@ static int dsa_cpu_port_apply(struct dev + return err; + } + +- ds->cpu_port_mask |= BIT(index); +- + return 0; + } + +@@ -259,6 +257,10 @@ static void dsa_cpu_port_unapply(struct + dsa_cpu_dsa_destroy(port); + ds->cpu_port_mask &= ~BIT(index); + ++ if (ds->ports[index].ethernet) { ++ dev_put(ds->ports[index].ethernet); ++ ds->ports[index].ethernet = NULL; ++ } + } + + static int dsa_user_port_apply(struct device_node *port, u32 index, +@@ -479,6 +481,29 @@ static int dsa_cpu_parse(struct device_n + + dst->rcv = dst->tag_ops->rcv; + ++ dev_hold(ethernet_dev); ++ ds->ports[index].ethernet = ethernet_dev; ++ ds->cpu_port_mask |= BIT(index); ++ ++ return 0; ++} ++ ++static int dsa_user_parse(struct device_node *port, u32 index, ++ struct dsa_switch *ds) ++{ ++ struct device_node *cpu_port; ++ const unsigned int *cpu_port_reg; ++ int cpu_port_index; ++ ++ cpu_port = of_parse_phandle(port, "cpu", 0); ++ if (cpu_port) { ++ cpu_port_reg = of_get_property(cpu_port, "reg", NULL); ++ if (!cpu_port_reg) ++ return -EINVAL; ++ cpu_port_index = be32_to_cpup(cpu_port_reg); ++ ds->ports[index].upstream = cpu_port_index; ++ } ++ + return 0; + } + +@@ -486,18 +511,19 @@ static int dsa_ds_parse(struct dsa_switc + { + struct device_node *port; + u32 index; +- int err; ++ int err = 0; + + for (index = 0; index < DSA_MAX_PORTS; index++) { + port = ds->ports[index].dn; + if (!port) + continue; + +- if (dsa_port_is_cpu(port)) { ++ if (dsa_port_is_cpu(port)) + err = dsa_cpu_parse(port, index, dst, ds); +- if (err) +- return err; +- } ++ else if (!dsa_port_is_dsa(port)) ++ err = dsa_user_parse(port, index, ds); ++ if (err) ++ return err; + } + + pr_info("DSA: switch %d %d parsed\n", dst->tree, ds->index); +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -43,6 +43,7 @@ struct dsa_slave_priv { + int old_duplex; + + struct net_device *bridge_dev; ++ struct net_device *master; + #ifdef CONFIG_NET_POLL_CONTROLLER + struct netpoll *netpoll; + #endif +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -61,7 +61,7 @@ static int dsa_slave_get_iflink(const st + { + struct dsa_slave_priv *p = netdev_priv(dev); + +- return p->parent->dst->master_netdev->ifindex; ++ return p->master->ifindex; + } + + static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) +@@ -96,7 +96,7 @@ static void dsa_port_set_stp_state(struc + static int dsa_slave_open(struct net_device *dev) + { + struct dsa_slave_priv *p = netdev_priv(dev); +- struct net_device *master = p->parent->dst->master_netdev; ++ struct net_device *master = p->master; + struct dsa_switch *ds = p->parent; + u8 stp_state = dsa_port_is_bridged(p) ? + BR_STATE_BLOCKING : BR_STATE_FORWARDING; +@@ -151,7 +151,7 @@ out: + static int dsa_slave_close(struct net_device *dev) + { + struct dsa_slave_priv *p = netdev_priv(dev); +- struct net_device *master = p->parent->dst->master_netdev; ++ struct net_device *master = p->master; + struct dsa_switch *ds = p->parent; + + if (p->phy) +@@ -178,7 +178,7 @@ static int dsa_slave_close(struct net_de + static void dsa_slave_change_rx_flags(struct net_device *dev, int change) + { + struct dsa_slave_priv *p = netdev_priv(dev); +- struct net_device *master = p->parent->dst->master_netdev; ++ struct net_device *master = p->master; + + if (change & IFF_ALLMULTI) + dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); +@@ -189,7 +189,7 @@ static void dsa_slave_change_rx_flags(st + static void dsa_slave_set_rx_mode(struct net_device *dev) + { + struct dsa_slave_priv *p = netdev_priv(dev); +- struct net_device *master = p->parent->dst->master_netdev; ++ struct net_device *master = p->master; + + dev_mc_sync(master, dev); + dev_uc_sync(master, dev); +@@ -198,7 +198,7 @@ static void dsa_slave_set_rx_mode(struct + static int dsa_slave_set_mac_address(struct net_device *dev, void *a) + { + struct dsa_slave_priv *p = netdev_priv(dev); +- struct net_device *master = p->parent->dst->master_netdev; ++ struct net_device *master = p->master; + struct sockaddr *addr = a; + int err; + +@@ -633,7 +633,7 @@ static netdev_tx_t dsa_slave_xmit(struct + /* Queue the SKB for transmission on the parent interface, but + * do not modify its EtherType + */ +- nskb->dev = p->parent->dst->master_netdev; ++ nskb->dev = p->master; + dev_queue_xmit(nskb); + + return NETDEV_TX_OK; +@@ -945,7 +945,7 @@ static int dsa_slave_netpoll_setup(struc + { + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; +- struct net_device *master = ds->dst->master_netdev; ++ struct net_device *master = p->master; + struct netpoll *netpoll; + int err = 0; + +@@ -1233,11 +1233,16 @@ int dsa_slave_create(struct dsa_switch * + struct net_device *master; + struct net_device *slave_dev; + struct dsa_slave_priv *p; ++ int port_cpu = ds->ports[port].upstream; + int ret; + +- master = ds->dst->master_netdev; +- if (ds->master_netdev) ++ if (port_cpu && ds->ports[port_cpu].ethernet) ++ master = ds->ports[port_cpu].ethernet; ++ else if (ds->master_netdev) + master = ds->master_netdev; ++ else ++ master = ds->dst->master_netdev; ++ master->dsa_ptr = (void *)ds->dst; + + slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, + NET_NAME_UNKNOWN, ether_setup); +@@ -1263,6 +1268,7 @@ int dsa_slave_create(struct dsa_switch * + p->parent = ds; + p->port = port; + p->xmit = dst->tag_ops->xmit; ++ p->master = master; + + p->old_pause = -1; + p->old_link = -1; diff --git a/target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch b/target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch new file mode 100644 index 0000000000..ae0614681f --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0034-net-dsa-mediatek-add-dual-gmac-support.patch @@ -0,0 +1,91 @@ +From dcb751a52b2ee69c16db2fef8f92a96ab13b6bb4 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 14:45:34 +0200 +Subject: [PATCH 34/57] net: dsa: mediatek: add dual gmac support + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -627,7 +627,7 @@ mt7530_setup(struct dsa_switch *ds) + + /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ + val = mt7530_read(priv, MT7530_MHWTRAP); +- val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; ++ val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; + val |= MHWTRAP_MANUAL; + if (!dsa_is_cpu_port(ds, 5)) { + val |= MHWTRAP_P5_DIS; +@@ -735,6 +735,9 @@ static int + mt7530_cpu_port_enable(struct mt7530_priv *priv, + int port) + { ++ u8 port_mask = 0; ++ int i; ++ + /* Enable Mediatek header mode on the cpu port */ + mt7530_write(priv, MT7530_PVC_P(port), + PORT_SPEC_TAG); +@@ -751,8 +754,12 @@ mt7530_cpu_port_enable(struct mt7530_pri + /* CPU port gets connected to all user ports of + * the switch + */ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ if ((priv->ds->enabled_port_mask & BIT(i)) && ++ (dsa_port_upstream_port(priv->ds, i) == port)) ++ port_mask |= BIT(i); + mt7530_write(priv, MT7530_PCR_P(port), +- PCR_MATRIX(priv->ds->enabled_port_mask)); ++ PCR_MATRIX(port_mask)); + + return 0; + } +@@ -762,6 +769,7 @@ mt7530_port_enable(struct dsa_switch *ds + struct phy_device *phy) + { + struct mt7530_priv *priv = ds->priv; ++ u8 upstream = dsa_port_upstream_port(ds, port); + + mutex_lock(&priv->reg_mutex); + +@@ -772,7 +780,7 @@ mt7530_port_enable(struct dsa_switch *ds + * restore the port matrix if the port is the member of a certain + * bridge. + */ +- priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ priv->ports[port].pm |= PCR_MATRIX(BIT(upstream)); + priv->ports[port].enable = true; + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, + priv->ports[port].pm); +@@ -835,7 +843,8 @@ mt7530_port_bridge_join(struct dsa_switc + struct net_device *bridge) + { + struct mt7530_priv *priv = ds->priv; +- u32 port_bitmap = BIT(MT7530_CPU_PORT); ++ u8 upstream = dsa_port_upstream_port(ds, port); ++ u32 port_bitmap = BIT(upstream); + int i; + + mutex_lock(&priv->reg_mutex); +@@ -873,6 +882,7 @@ static void + mt7530_port_bridge_leave(struct dsa_switch *ds, int port) + { + struct mt7530_priv *priv = ds->priv; ++ u8 upstream = dsa_port_upstream_port(ds, port); + int i; + + mutex_lock(&priv->reg_mutex); +@@ -898,8 +908,8 @@ mt7530_port_bridge_leave(struct dsa_swit + priv->bridge_dev[port] = NULL; + if (priv->ports[port].enable) + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, +- PCR_MATRIX(BIT(MT7530_CPU_PORT))); +- priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ PCR_MATRIX(BIT(upstream))); ++ priv->ports[port].pm = PCR_MATRIX(BIT(upstream)); + + mutex_unlock(&priv->reg_mutex); + } diff --git a/target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch b/target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch new file mode 100644 index 0000000000..36321c55cf --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0035-net-mediatek-disable-RX-VLan-offloading.patch @@ -0,0 +1,47 @@ +From 35b83b85e752a6660b92f08c0fb912308f25cf6d Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:56:40 +0200 +Subject: [PATCH 35/57] net: mediatek: disable RX VLan offloading + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 9 ++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 -- + 2 files changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -643,8 +643,8 @@ static int mtk_tx_map(struct sk_buff *sk + txd4 |= TX_DMA_CHKSUM; + + /* VLAN header offload */ +- if (skb_vlan_tag_present(skb)) +- txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); ++// if (skb_vlan_tag_present(skb)) ++// txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); + + mapped_addr = dma_map_single(eth->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); +@@ -1874,7 +1874,10 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); + + /* Enable RX VLan Offloading */ +- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); ++ if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX) ++ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); ++ else ++ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); + + /* disable delay and normal interrupt */ + mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -34,8 +34,6 @@ + NETIF_MSG_TX_ERR) + #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ + NETIF_F_RXCSUM | \ +- NETIF_F_HW_VLAN_CTAG_TX | \ +- NETIF_F_HW_VLAN_CTAG_RX | \ + NETIF_F_SG | NETIF_F_TSO | \ + NETIF_F_TSO6 | \ + NETIF_F_IPV6_CSUM) diff --git a/target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch b/target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch new file mode 100644 index 0000000000..e96374fdd1 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0036-net-next-mediatek-fix-typos-inside-the-header-file.patch @@ -0,0 +1,25 @@ +From bf25fbdc7dfb256f267725336e29e232aadd5123 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 21 Jul 2017 08:43:58 +0200 +Subject: [PATCH 36/57] net-next: mediatek: fix typos inside the header file + +Trivial patch fixing 2 typos. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -525,8 +525,8 @@ struct mtk_rx_ring { + * @pctl: The register map pointing at the range used to setup + * GMAC port drive/slew values + * @dma_refcnt: track how many netdevs are using the DMA engine +- * @tx_ring: Pointer to the memore holding info about the TX ring +- * @rx_ring: Pointer to the memore holding info about the RX ring ++ * @tx_ring: Pointer to the memory holding info about the TX ring ++ * @rx_ring: Pointer to the memory holding info about the RX ring + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct + * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring diff --git a/target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch b/target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch new file mode 100644 index 0000000000..9d6a089c5e --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0037-net-next-mediatek-bring-up-QDMA-RX-ring-0.patch @@ -0,0 +1,128 @@ +From 047a4e7b17322c1b32d8db32a0df9899cb4963a3 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 21 Jul 2017 08:48:38 +0200 +Subject: [PATCH 37/57] net-next: mediatek: bring up QDMA RX ring 0 + +This patch is in peparation for adding HW flow and QoS offloading. For +those features to work, the driver needs to bring up the first QDMA RX +ring. This ring is used by the PPE offloading HW. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 38 ++++++++++++++++++++--------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 +++ + 2 files changed, 30 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1224,11 +1224,21 @@ static void mtk_tx_clean(struct mtk_eth + + static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + { +- struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; ++ struct mtk_rx_ring *ring; + int rx_data_len, rx_dma_size; + int i; ++ u32 offset = 0; + +- if (rx_flag == MTK_RX_FLAGS_HWLRO) { ++ if (rx_flag & MTK_RX_FLAGS_QDMA) { ++ if (ring_no) ++ return -EINVAL; ++ ring = ð->rx_ring_qdma; ++ offset = 0x1000; ++ } else { ++ ring = ð->rx_ring[ring_no]; ++ } ++ ++ if (rx_flag & MTK_RX_FLAGS_HWLRO) { + rx_data_len = MTK_MAX_LRO_RX_LENGTH; + rx_dma_size = MTK_HW_LRO_DMA_SIZE; + } else { +@@ -1276,17 +1286,16 @@ static int mtk_rx_alloc(struct mtk_eth * + */ + wmb(); + +- mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no)); +- mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no)); +- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); +- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX); ++ mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); ++ mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); + + return 0; + } + +-static void mtk_rx_clean(struct mtk_eth *eth, int ring_no) ++static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) + { +- struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; + int i; + + if (ring->data && ring->dma) { +@@ -1612,6 +1621,10 @@ static int mtk_dma_init(struct mtk_eth * + if (err) + return err; + ++ err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA); ++ if (err) ++ return err; ++ + err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_NORMAL); + if (err) + return err; +@@ -1651,12 +1664,13 @@ static void mtk_dma_free(struct mtk_eth + eth->phy_scratch_ring = 0; + } + mtk_tx_clean(eth); +- mtk_rx_clean(eth, 0); ++ mtk_rx_clean(eth, ð->rx_ring[0]); ++ mtk_rx_clean(eth, ð->rx_ring_qdma); + + if (eth->hwlro) { + mtk_hwlro_rx_uninit(eth); + for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) +- mtk_rx_clean(eth, i); ++ mtk_rx_clean(eth, ð->rx_ring[i]); + } + + kfree(eth->scratch_head); +@@ -1723,7 +1737,9 @@ static int mtk_start_dma(struct mtk_eth + + mtk_w32(eth, + MTK_TX_WB_DDONE | MTK_TX_DMA_EN | +- MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO, ++ MTK_DMA_SIZE_16DWORDS | MTK_NDP_CO_PRO | ++ MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | ++ MTK_RX_BT_32DWORDS, + MTK_QDMA_GLO_CFG); + + mtk_w32(eth, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -484,6 +484,7 @@ struct mtk_tx_ring { + enum mtk_rx_flags { + MTK_RX_FLAGS_NORMAL = 0, + MTK_RX_FLAGS_HWLRO, ++ MTK_RX_FLAGS_QDMA, + }; + + /* struct mtk_rx_ring - This struct holds info describing a RX ring +@@ -527,6 +528,7 @@ struct mtk_rx_ring { + * @dma_refcnt: track how many netdevs are using the DMA engine + * @tx_ring: Pointer to the memory holding info about the TX ring + * @rx_ring: Pointer to the memory holding info about the RX ring ++ * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ring + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct + * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring +@@ -556,6 +558,7 @@ struct mtk_eth { + atomic_t dma_refcnt; + struct mtk_tx_ring tx_ring; + struct mtk_rx_ring rx_ring[MTK_MAX_RX_RING_NUM]; ++ struct mtk_rx_ring rx_ring_qdma; + struct napi_struct tx_napi; + struct napi_struct rx_napi; + struct mtk_tx_dma *scratch_ring; diff --git a/target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch b/target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch new file mode 100644 index 0000000000..cb1c1b9e97 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0038-net-next-dsa-move-struct-dsa_device_ops-to-the-globa.patch @@ -0,0 +1,46 @@ +From b58bf0220f666705e63fe8d361f37c913aee2d8f Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 21 Jul 2017 09:32:54 +0200 +Subject: [PATCH 38/57] net-next: dsa: move struct dsa_device_ops to the global + header file + +We need to access this struct from within the flow_dissector to fix +dissection for packets coming in on DSA devices. + +Signed-off-by: John Crispin +--- + include/net/dsa.h | 7 +++++++ + net/dsa/dsa_priv.h | 6 ------ + 2 files changed, 7 insertions(+), 6 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -88,6 +88,13 @@ struct dsa_platform_data { + + struct packet_type; + ++struct dsa_device_ops { ++ struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); ++ int sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, ++ struct packet_type *pt, ++ struct net_device *orig_dev); ++}; ++ + struct dsa_switch_tree { + struct list_head list; + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -15,12 +15,6 @@ + #include + #include + +-struct dsa_device_ops { +- struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); +- int (*rcv)(struct sk_buff *skb, struct net_device *dev, +- struct packet_type *pt, struct net_device *orig_dev); +-}; +- + struct dsa_slave_priv { + struct sk_buff * (*xmit)(struct sk_buff *skb, + struct net_device *dev); diff --git a/target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch b/target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch new file mode 100644 index 0000000000..ebc52c83fe --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0039-net-next-dsa-add-flow_dissect-callback-to-struct-dsa.patch @@ -0,0 +1,32 @@ +From 22e8b65ea4bf8a1fa757137bdcbdefe505fa4044 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 7 Aug 2017 16:35:43 +0200 +Subject: [PATCH 39/57] net-next: dsa: add flow_dissect callback to struct + dsa_device_ops + +When the flow dissector first sees packets coming in on a DSA devices the +802.3 header wont be located where the code expects it to be as the tag +is still present. Adding this new callback allows a DSA device to provide a +new function that the flow_disscetor can use to get the correct offsets +for the protocol field and network header offset. + +Signed-off-by: John Crispin +--- + include/net/dsa.h | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -90,9 +90,11 @@ struct packet_type; + + struct dsa_device_ops { + struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); +- int sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev, ++ int (*rcv)(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, + struct net_device *orig_dev); ++ int (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, ++ int *offset); + }; + + struct dsa_switch_tree { diff --git a/target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch b/target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch new file mode 100644 index 0000000000..da98a21380 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0040-net-next-tag_mtk-add-flow_dissect-callback-to-the-op.patch @@ -0,0 +1,39 @@ +From 9d6806e16e5ea68a49225da1ab065ef0b5d7704b Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 7 Aug 2017 16:55:56 +0200 +Subject: [PATCH 40/57] net-next: tag_mtk: add flow_dissect callback to the ops + struct + +The MT7530 inserts the 4 magic header in between the 802.3 address and +protocol field. The patch implements the callback that can be called by +the flow dissector to figure out the real protocol and offset of the +network header. With this patch applied we can properly parse the packet +and thus make hashing function properly. + +Signed-off-by: John Crispin +--- + net/dsa/tag_mtk.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/net/dsa/tag_mtk.c ++++ b/net/dsa/tag_mtk.c +@@ -111,7 +111,17 @@ out: + return 0; + } + ++static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto, ++ int *offset) ++{ ++ *offset = 4; ++ *proto = ((__be16 *)skb->data)[1]; ++ ++ return 0; ++} ++ + const struct dsa_device_ops mtk_netdev_ops = { +- .xmit = mtk_tag_xmit, +- .rcv = mtk_tag_rcv, ++ .xmit = mtk_tag_xmit, ++ .rcv = mtk_tag_rcv, ++ .flow_dissect = mtk_tag_flow_dissect, + }; diff --git a/target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch b/target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch new file mode 100644 index 0000000000..54359623e2 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0041-net-next-dsa-fix-flow-dissection.patch @@ -0,0 +1,65 @@ +From 04c825484d6ecdcc8ce09b350235c9077eaca6e3 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 9 Aug 2017 08:20:21 +0200 +Subject: [PATCH 41/57] net-next: dsa: fix flow dissection + +RPS and probably other kernel features are currently broken on some if not +all DSA devices. The root cause of this is that skb_hash will call the +flow_dissector. At this point the skb still contains the magic switch +header and the skb->protocol field is not set up to the correct 802.3 +value yet. By the time the tag specific code is called, removing the header +and =roperly setting the protocol an invalid hash is already set. In the +case of the mt7530 this will result in all flows always having the same +hash. + +This patch makes the flow dissector honour the nh and protocol offset +defined by the dsa tag driver thus fixing dissection, hashing and RPS. + +Signed-off-by: John Crispin +--- + net/core/flow_dissector.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -123,13 +124,23 @@ bool __skb_flow_dissect(const struct sk_ + bool skip_vlan = false; + u8 ip_proto = 0; + bool ret; +- + if (!data) { + data = skb->data; + proto = skb_vlan_tag_present(skb) ? + skb->vlan_proto : skb->protocol; + nhoff = skb_network_offset(skb); + hlen = skb_headlen(skb); ++ if (unlikely(netdev_uses_dsa(skb->dev))) { ++ const struct dsa_device_ops *ops; ++ int offset; ++ ++ ops = skb->dev->dsa_ptr->tag_ops; ++ if (ops->flow_dissect && ++ !ops->flow_dissect(skb, &proto, &offset)) { ++ hlen -= offset; ++ nhoff += offset; ++ } ++ } + } + + /* It is ensured by skb_flow_dissector_init() that control key will +@@ -162,6 +173,7 @@ again: + case htons(ETH_P_IP): { + const struct iphdr *iph; + struct iphdr _iph; ++ + ip: + iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); + if (!iph || iph->ihl < 5) diff --git a/target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch b/target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch new file mode 100644 index 0000000000..4f2c7b2e6e --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch @@ -0,0 +1,50 @@ +From a306af3b97c56b9e224a2f9ee04838a2d32ff60b Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 9 Aug 2017 14:44:07 +0200 +Subject: [PATCH 42/57] net-next: mediatek: honour special tag bit inside RX + DMA descriptor + +For HW NAT/QoS to work the DSA driver needs to turn the special tag bit +inside the ingress control register on. This has the side effect that +the code working out which ingress gmac we have breaks. Fix this by +honouring the special tag bit inside the RX free descriptor. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 14 ++++++++++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -933,10 +933,16 @@ static int mtk_poll_rx(struct napi_struc + if (!(trxd.rxd2 & RX_DMA_DONE)) + break; + +- /* find out which mac the packet come from. values start at 1 */ +- mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & +- RX_DMA_FPORT_MASK; +- mac--; ++ /* find out which mac the packet comes from. If the special tag is ++ * we can assume that the traffic is coming from the builtin mt7530 ++ * and the DSA driver has loaded. FPORT will be the physical switch ++ * port in this case rather than the FE forward port id. */ ++ if (!(trxd.rxd4 & RX_DMA_SP_TAG)) { ++ /* values start at 1 */ ++ mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & ++ RX_DMA_FPORT_MASK; ++ mac--; ++ } + + netdev = eth->netdev[mac]; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -284,6 +284,7 @@ + + /* QDMA descriptor rxd4 */ + #define RX_DMA_L4_VALID BIT(24) ++#define RX_DMA_SP_TAG BIT(22) + #define RX_DMA_FPORT_SHIFT 19 + #define RX_DMA_FPORT_MASK 0x7 + diff --git a/target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch b/target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch new file mode 100644 index 0000000000..2256325c9c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0043-net-next-mediatek-enable-special-tag-indication-for-.patch @@ -0,0 +1,41 @@ +From 53e3d9af39805a7e1ba81a047a9ab433be0e82f5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 9 Aug 2017 14:56:53 +0200 +Subject: [PATCH 43/57] net-next: mediatek: enable special tag indication for + PDMA + +The Ingress special tag indication was only enabled for QDMA and not PDMA. +Properly initialize the STAG bit. This broke HW NAT and Qos from working +for traffic coming in via a DSA device. The PPE failed to properly parse +the traffic as it was not expecting the special tag. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ + 2 files changed, 6 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1894,6 +1894,8 @@ static int mtk_hw_init(struct mtk_eth *e + */ + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ val = mtk_r32(eth, MTK_CDMP_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); + + /* Enable RX VLan Offloading */ + if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -76,6 +76,10 @@ + #define MTK_CDMQ_IG_CTRL 0x1400 + #define MTK_CDMQ_STAG_EN BIT(0) + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMP_IG_CTRL 0x400 ++#define MTK_CDMP_STAG_EN BIT(0) ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + diff --git a/target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch b/target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch new file mode 100644 index 0000000000..51204d4001 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch @@ -0,0 +1,43 @@ +From 6a5932028a4f3217ed7c9d602f269611d95dd8ca Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 9 Aug 2017 15:13:19 +0200 +Subject: [PATCH 44/57] net-next: dsa: mediatek: tell GDMA when we are turning + on the special tag + +Enabling this bit will make the RX DMA descriptor enable the SP bit for all +ingress traffic inside the return descriptor. The PPE needs this to know +that a SP is present. + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 5 +++++ + drivers/net/dsa/mt7530.h | 4 ++++ + 2 files changed, 9 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -742,6 +742,11 @@ mt7530_cpu_port_enable(struct mt7530_pri + mt7530_write(priv, MT7530_PVC_P(port), + PORT_SPEC_TAG); + ++ /* Enable Mediatek header mode on the GMAC that the cpu port ++ * connects to */ ++ regmap_write_bits(priv->ethernet, MTK_GDMA_FWD_CFG(port), ++ GDMA_SPEC_TAG, GDMA_SPEC_TAG); ++ + /* Setup the MAC by default for the cpu port */ + mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); + +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -22,6 +22,10 @@ + + #define TRGMII_BASE(x) (0x10000 + (x)) + ++/* Registers for GDMA configuration access */ ++#define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000)) ++#define GDMA_SPEC_TAG BIT(24) ++ + /* Registers to ethsys access */ + #define ETHSYS_CLKCFG0 0x2c + #define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) diff --git a/target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch b/target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch new file mode 100644 index 0000000000..c263b07952 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0045-net-dsa-mediatek-turn-into-platform-driver.patch @@ -0,0 +1,79 @@ +From 1e33784f665cb95c2af5481d3e776d2d3099921b Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:57:17 +0200 +Subject: [PATCH 45/57] net: dsa: mediatek: turn into platform driver + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1035,10 +1035,10 @@ static struct dsa_switch_ops mt7530_swit + }; + + static int +-mt7530_probe(struct mdio_device *mdiodev) ++mt7530_probe(struct platform_device *mdiodev) + { + struct mt7530_priv *priv; +- struct device_node *dn; ++ struct device_node *dn, *mdio; + + dn = mdiodev->dev.of_node; + +@@ -1086,7 +1086,12 @@ mt7530_probe(struct mdio_device *mdiodev + } + } + +- priv->bus = mdiodev->bus; ++ mdio = of_parse_phandle(dn, "dsa,mii-bus", 0); ++ if (!mdio) ++ return -EINVAL; ++ priv->bus = of_mdio_find_bus(mdio); ++ if (!priv->bus) ++ return -EPROBE_DEFER; + priv->dev = &mdiodev->dev; + priv->ds->priv = priv; + priv->ds->dev = &mdiodev->dev; +@@ -1098,8 +1103,8 @@ mt7530_probe(struct mdio_device *mdiodev + return dsa_register_switch(priv->ds, priv->ds->dev->of_node); + } + +-static void +-mt7530_remove(struct mdio_device *mdiodev) ++static int ++mt7530_remove(struct platform_device *mdiodev) + { + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); + int ret = 0; +@@ -1116,6 +1121,8 @@ mt7530_remove(struct mdio_device *mdiode + + dsa_unregister_switch(priv->ds); + mutex_destroy(&priv->reg_mutex); ++ ++ return 0; + } + + static const struct of_device_id mt7530_of_match[] = { +@@ -1123,16 +1130,16 @@ static const struct of_device_id mt7530_ + { /* sentinel */ }, + }; + +-static struct mdio_driver mt7530_mdio_driver = { ++static struct platform_driver mtk_mt7530_driver = { + .probe = mt7530_probe, + .remove = mt7530_remove, +- .mdiodrv.driver = { ++ .driver = { + .name = "mt7530", + .of_match_table = mt7530_of_match, + }, + }; ++module_platform_driver(mtk_mt7530_driver); + +-mdio_module_driver(mt7530_mdio_driver); + + MODULE_AUTHOR("Sean Wang "); + MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); diff --git a/target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch b/target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch new file mode 100644 index 0000000000..47c3980a6c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0046-net-mediatek-add-irq-delay.patch @@ -0,0 +1,56 @@ +From 6e081074df96bf3762c2e6438c383f11a56b0a7e Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:58:04 +0200 +Subject: [PATCH 46/57] net: mediatek: add irq delay + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 ++++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 +++++++- + 2 files changed, 13 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1904,8 +1904,13 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); + + /* disable delay and normal interrupt */ +- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); ++#ifdef MTK_IRQ_DLY ++ mtk_w32(eth, 0x84048404, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, 0x84048404, MTK_QDMA_DELAY_INT); ++#else + mtk_w32(eth, 0, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); ++#endif + mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); + mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); + mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -12,6 +12,8 @@ + * Copyright (C) 2013-2016 Michael Lee + */ + ++#define MTK_IRQ_DLY ++ + #ifndef MTK_ETH_H + #define MTK_ETH_H + +@@ -220,11 +222,15 @@ + #define MTK_TX_DONE_INT2 BIT(2) + #define MTK_TX_DONE_INT1 BIT(1) + #define MTK_TX_DONE_INT0 BIT(0) ++#ifdef MTK_IRQ_DLY ++#define MTK_RX_DONE_INT BIT(30) ++#define MTK_TX_DONE_INT BIT(28) ++#else + #define MTK_RX_DONE_INT (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1 | \ + MTK_RX_DONE_INT2 | MTK_RX_DONE_INT3) + #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ + MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) +- ++#endif + /* QDMA Interrupt grouping registers */ + #define MTK_QDMA_INT_GRP1 0x1a20 + #define MTK_QDMA_INT_GRP2 0x1a24 diff --git a/target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch b/target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch new file mode 100644 index 0000000000..27a78a63b0 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0047-net-next-mediatek-split-IRQ-register-locking-into-TX.patch @@ -0,0 +1,208 @@ +From 5afceece38fa30e3c71e7ed9ac62aa70ba8cfbb1 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 16 Jun 2017 10:00:30 +0200 +Subject: [PATCH 47/57] net-next: mediatek: split IRQ register locking into TX + and RX + +Originally the driver only utilized the new QDMA engine. The current code +still assumes this is the case when locking the IRQ mask register. Since +RX now runs on the old style PDMA engine we can add a second lock. This +patch reduces the IRQ latency as the TX and RX path no longer need to wait +on each other under heavy load. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 79 ++++++++++++++++++----------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +- + 2 files changed, 54 insertions(+), 30 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -372,28 +372,48 @@ static void mtk_mdio_cleanup(struct mtk_ + mdiobus_unregister(eth->mii_bus); + } + +-static inline void mtk_irq_disable(struct mtk_eth *eth, +- unsigned reg, u32 mask) ++static inline void mtk_tx_irq_disable(struct mtk_eth *eth, u32 mask) + { + unsigned long flags; + u32 val; + +- spin_lock_irqsave(ð->irq_lock, flags); +- val = mtk_r32(eth, reg); +- mtk_w32(eth, val & ~mask, reg); +- spin_unlock_irqrestore(ð->irq_lock, flags); ++ spin_lock_irqsave(ð->tx_irq_lock, flags); ++ val = mtk_r32(eth, MTK_QDMA_INT_MASK); ++ mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK); ++ spin_unlock_irqrestore(ð->tx_irq_lock, flags); + } + +-static inline void mtk_irq_enable(struct mtk_eth *eth, +- unsigned reg, u32 mask) ++static inline void mtk_tx_irq_enable(struct mtk_eth *eth, u32 mask) + { + unsigned long flags; + u32 val; + +- spin_lock_irqsave(ð->irq_lock, flags); +- val = mtk_r32(eth, reg); +- mtk_w32(eth, val | mask, reg); +- spin_unlock_irqrestore(ð->irq_lock, flags); ++ spin_lock_irqsave(ð->tx_irq_lock, flags); ++ val = mtk_r32(eth, MTK_QDMA_INT_MASK); ++ mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK); ++ spin_unlock_irqrestore(ð->tx_irq_lock, flags); ++} ++ ++static inline void mtk_rx_irq_disable(struct mtk_eth *eth, u32 mask) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(ð->rx_irq_lock, flags); ++ val = mtk_r32(eth, MTK_PDMA_INT_MASK); ++ mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK); ++ spin_unlock_irqrestore(ð->rx_irq_lock, flags); ++} ++ ++static inline void mtk_rx_irq_enable(struct mtk_eth *eth, u32 mask) ++{ ++ unsigned long flags; ++ u32 val; ++ ++ spin_lock_irqsave(ð->rx_irq_lock, flags); ++ val = mtk_r32(eth, MTK_PDMA_INT_MASK); ++ mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK); ++ spin_unlock_irqrestore(ð->rx_irq_lock, flags); + } + + static int mtk_set_mac_address(struct net_device *dev, void *p) +@@ -1116,7 +1136,7 @@ static int mtk_napi_tx(struct napi_struc + return budget; + + napi_complete(napi); +- mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); ++ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); + + return tx_done; + } +@@ -1150,7 +1170,7 @@ poll_again: + goto poll_again; + } + napi_complete(napi); +- mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); + + return rx_done + budget - remain_budget; + } +@@ -1699,7 +1719,7 @@ static irqreturn_t mtk_handle_irq_rx(int + + if (likely(napi_schedule_prep(ð->rx_napi))) { + __napi_schedule(ð->rx_napi); +- mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); + } + + return IRQ_HANDLED; +@@ -1711,7 +1731,7 @@ static irqreturn_t mtk_handle_irq_tx(int + + if (likely(napi_schedule_prep(ð->tx_napi))) { + __napi_schedule(ð->tx_napi); +- mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); ++ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); + } + + return IRQ_HANDLED; +@@ -1723,11 +1743,11 @@ static void mtk_poll_controller(struct n + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + +- mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); +- mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); ++ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); + mtk_handle_irq_rx(eth->irq[2], dev); +- mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); +- mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); ++ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); + } + #endif + +@@ -1770,8 +1790,8 @@ static int mtk_open(struct net_device *d + + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); +- mtk_irq_enable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); +- mtk_irq_enable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); ++ mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); + } + atomic_inc(ð->dma_refcnt); + +@@ -1816,8 +1836,8 @@ static int mtk_stop(struct net_device *d + if (!atomic_dec_and_test(ð->dma_refcnt)) + return 0; + +- mtk_irq_disable(eth, MTK_QDMA_INT_MASK, MTK_TX_DONE_INT); +- mtk_irq_disable(eth, MTK_PDMA_INT_MASK, MTK_RX_DONE_INT); ++ mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); ++ mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); + napi_disable(ð->tx_napi); + napi_disable(ð->rx_napi); + +@@ -1911,8 +1931,8 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, 0, MTK_PDMA_DELAY_INT); + mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + #endif +- mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); +- mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); ++ mtk_tx_irq_disable(eth, ~0); ++ mtk_rx_irq_disable(eth, ~0); + mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); + mtk_w32(eth, 0, MTK_RST_GL); + +@@ -1983,8 +2003,8 @@ static void mtk_uninit(struct net_device + phy_disconnect(dev->phydev); + if (of_phy_is_fixed_link(mac->of_node)) + of_phy_deregister_fixed_link(mac->of_node); +- mtk_irq_disable(eth, MTK_QDMA_INT_MASK, ~0); +- mtk_irq_disable(eth, MTK_PDMA_INT_MASK, ~0); ++ mtk_tx_irq_disable(eth, ~0); ++ mtk_rx_irq_disable(eth, ~0); + } + + static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +@@ -2442,7 +2462,8 @@ static int mtk_probe(struct platform_dev + return PTR_ERR(eth->base); + + spin_lock_init(ð->page_lock); +- spin_lock_init(ð->irq_lock); ++ spin_lock_init(ð->tx_irq_lock); ++ spin_lock_init(ð->rx_irq_lock); + + eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "mediatek,ethsys"); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -526,6 +526,8 @@ struct mtk_rx_ring { + * @dev: The device pointer + * @base: The mapped register i/o base + * @page_lock: Make sure that register operations are atomic ++ * @tx_irq__lock: Make sure that IRQ register operations are atomic ++ * @rx_irq__lock: Make sure that IRQ register operations are atomic + * @dummy_dev: we run 2 netdevs on 1 physical DMA ring and need a + * dummy for NAPI to work + * @netdev: The netdev instances +@@ -555,7 +557,8 @@ struct mtk_eth { + struct device *dev; + void __iomem *base; + spinlock_t page_lock; +- spinlock_t irq_lock; ++ spinlock_t tx_irq_lock; ++ spinlock_t rx_irq_lock; + struct net_device dummy_dev; + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; diff --git a/target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch b/target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch new file mode 100644 index 0000000000..20d0e43b38 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0048-net-core-add-RPS-balancer.patch @@ -0,0 +1,90 @@ +From 3e969c9695b45e1a052d43b367096ec99f2f0aac Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:58:29 +0200 +Subject: [PATCH 48/57] net: core: add RPS balancer + +Signed-off-by: John Crispin +--- + net/core/dev.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 56 insertions(+), 1 deletion(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3547,6 +3547,58 @@ set_rps_cpu(struct net_device *dev, stru + return rflow; + } + ++#define RPS_TBL_SIZE_SHIFT 10 ++#define RPS_TBL_SIZE (1 << RPS_TBL_SIZE_SHIFT) ++struct rps_table { ++ int core; ++ struct timer_list expire; ++}; ++static struct rps_table rps_table[RPS_TBL_SIZE]; ++static int rps_table_last_core; ++ ++static void rps_table_expire(unsigned long data) ++{ ++ struct rps_table *entry = (struct rps_table *) data; ++ ++ entry->core = -1; ++} ++ ++static int rps_table_core(struct rps_map *map) ++{ ++ int i; ++ ++ for (i = 0; i < map->len; i++) { ++ int cpu = map->cpus[(rps_table_last_core + i + 1) % map->len]; ++ if (cpu_online(cpu)) { ++ rps_table_last_core = cpu; ++ return cpu; ++ } ++ } ++ return map->cpus[0]; ++} ++ ++static int rps_table_lookup(struct rps_map *map, u32 hash) ++{ ++ int bucket = hash & 0x3ff; ++ ++ if (rps_table[bucket].core < 0) ++ rps_table[bucket].core = rps_table_core(map); ++ mod_timer(&rps_table[bucket].expire, jiffies + HZ); ++ ++ return rps_table[bucket].core; ++} ++ ++static void rps_table_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < RPS_TBL_SIZE; i++) { ++ rps_table[i].core = -1; ++ setup_timer(&rps_table[i].expire, rps_table_expire, ++ (unsigned long) &rps_table[i]); ++ } ++} ++ + /* + * get_rps_cpu is called from netif_receive_skb and returns the target + * CPU from the RPS map of the receiving queue for a given skb. +@@ -3636,7 +3688,7 @@ static int get_rps_cpu(struct net_device + try_rps: + + if (map) { +- tcpu = map->cpus[reciprocal_scale(hash, map->len)]; ++ tcpu = rps_table_lookup(map, hash); + if (cpu_online(tcpu)) { + cpu = tcpu; + goto done; +@@ -8426,6 +8478,9 @@ static int __init net_dev_init(void) + sd->backlog.weight = weight_p; + } + ++ if (IS_ENABLED(CONFIG_RPS)) ++ rps_table_init(); ++ + dev_boot_phase = 0; + + /* The loopback device is special if any other network devices diff --git a/target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch b/target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch new file mode 100644 index 0000000000..0146a9dd5c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0049-net-mediatek-add-rx-queue.patch @@ -0,0 +1,20 @@ +From 066b30a76a0d13cbd2c0d463f9a1e87efc352679 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:58:46 +0200 +Subject: [PATCH 49/57] net: mediatek: add rx queue + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1009,6 +1009,7 @@ static int mtk_poll_rx(struct napi_struc + RX_DMA_VID(trxd.rxd3)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); ++ skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + + ring->data[idx] = new_data; diff --git a/target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch b/target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch new file mode 100644 index 0000000000..3d7df70bb3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0050-net-mediatek-add-trgmii-clock.patch @@ -0,0 +1,21 @@ +From 67c4af99af02d86b627a8cde2e99cc4c9699d2ce Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:59:08 +0200 +Subject: [PATCH 50/57] net: mediatek: add trgmii clock + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1873,6 +1873,8 @@ static int mtk_hw_init(struct mtk_eth *e + pm_runtime_enable(eth->dev); + pm_runtime_get_sync(eth->dev); + ++ clk_set_rate(eth->clks[MTK_CLK_TRGPLL], 250000000); ++ + clk_prepare_enable(eth->clks[MTK_CLK_ETHIF]); + clk_prepare_enable(eth->clks[MTK_CLK_ESW]); + clk_prepare_enable(eth->clks[MTK_CLK_GP1]); diff --git a/target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch b/target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch new file mode 100644 index 0000000000..3de3e7343b --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0051-net-mediatek-increase-tx_timeout.patch @@ -0,0 +1,21 @@ +From 5cbf53c7e5eac5bacc409461888789accdaf8eec Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:00:06 +0200 +Subject: [PATCH 51/57] net: mediatek: increase tx_timeout + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2384,7 +2384,7 @@ static int mtk_add_mac(struct mtk_eth *e + mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; + + SET_NETDEV_DEV(eth->netdev[id], eth->dev); +- eth->netdev[id]->watchdog_timeo = 5 * HZ; ++ eth->netdev[id]->watchdog_timeo = 30 * HZ; + eth->netdev[id]->netdev_ops = &mtk_netdev_ops; + eth->netdev[id]->base_addr = (unsigned long)eth->base; + diff --git a/target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch deleted file mode 100644 index 7c786be738..0000000000 --- a/target/linux/mediatek/patches-4.9/0052-clk-dont-disable-unused-clocks.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 5238c5d1d38661955ed3b52f45c46e00bfc9eb6e Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 7 Apr 2016 07:18:35 +0200 -Subject: [PATCH 052/102] clk: dont disable unused clocks - -Signed-off-by: John Crispin ---- - drivers/clk/clk.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -796,7 +796,7 @@ unlock_out: - clk_core_disable_unprepare(core->parent); - } - --static bool clk_ignore_unused; -+static bool clk_ignore_unused = true; - static int __init clk_ignore_unused_setup(char *__unused) - { - clk_ignore_unused = true; diff --git a/target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch b/target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch new file mode 100644 index 0000000000..89f730b3a3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0052-net-phy-add-FC.patch @@ -0,0 +1,21 @@ +From 18b2169d84b47a3414164e5e40f23fb7e875707c Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:00:28 +0200 +Subject: [PATCH 52/57] net: phy: add FC + +Signed-off-by: John Crispin +--- + drivers/net/phy/phy_device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1799,7 +1799,7 @@ static struct phy_driver genphy_driver[] + .config_init = genphy_config_init, + .features = PHY_GBIT_FEATURES | SUPPORTED_MII | + SUPPORTED_AUI | SUPPORTED_FIBRE | +- SUPPORTED_BNC, ++ SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .config_aneg = genphy_config_aneg, + .aneg_done = genphy_aneg_done, + .read_status = genphy_read_status, diff --git a/target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch deleted file mode 100644 index 39939001f1..0000000000 --- a/target/linux/mediatek/patches-4.9/0053-clk-mediatek-enable-critical-clocks.patch +++ /dev/null @@ -1,69 +0,0 @@ -From c8fd103d6c07af5db47f061b70759b7c69169656 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 31 Mar 2016 06:46:51 +0200 -Subject: [PATCH 053/102] clk: mediatek: enable critical clocks - -Signed-off-by: John Crispin ---- - drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++-- - 1 file changed, 20 insertions(+), 2 deletions(-) - ---- a/drivers/clk/mediatek/clk-mt2701.c -+++ b/drivers/clk/mediatek/clk-mt2701.c -@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[] - GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28), - }; - -+static struct clk_onecell_data *mt7623_top_clk_data __initdata; -+static struct clk_onecell_data *mt7623_pll_clk_data __initdata; -+ -+static void __init mtk_clk_enable_critical(void) -+{ -+ if (!mt7623_top_clk_data || !mt7623_pll_clk_data) -+ return; -+ -+ clk_prepare_enable(mt7623_pll_clk_data->clks[CLK_APMIXED_ARMPLL]); -+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_MEM_SEL]); -+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]); -+ clk_prepare_enable(mt7623_top_clk_data->clks[CLK_TOP_RTC_SEL]); -+} -+ - static void __init mtk_topckgen_init(struct device_node *node) - { - struct clk_onecell_data *clk_data; -@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str - return; - } - -- clk_data = mtk_alloc_clk_data(CLK_TOP_NR); -+ mt7623_top_clk_data = clk_data = mtk_alloc_clk_data(CLK_TOP_NR); - - mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), - clk_data); -@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_clk_enable_critical(); - } - CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init); - -@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s - struct clk_onecell_data *clk_data; - int r; - -- clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); -+ mt7623_pll_clk_data = clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls)); - if (!clk_data) - return; - -@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s - if (r) - pr_err("%s(): could not register clock provider: %d\n", - __func__, r); -+ -+ mtk_clk_enable_critical(); - } - CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys", - mtk_apmixedsys_init); diff --git a/target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch b/target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch new file mode 100644 index 0000000000..a41bcb0262 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0053-net-dsa-mediatek-add-software-phy-polling.patch @@ -0,0 +1,68 @@ +From 53eec2c3580e63fdebfc25ae324f30cd8aa4403b Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:00:46 +0200 +Subject: [PATCH 53/57] net: dsa: mediatek: add software phy polling + +Signed-off-by: John Crispin +--- + drivers/net/dsa/mt7530.c | 38 ++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.h | 1 + + 2 files changed, 39 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -728,6 +728,44 @@ static void mt7530_adjust_link(struct ds + * all finished. + */ + mt7623_pad_clk_setup(ds); ++ } else { ++ u16 lcl_adv = 0, rmt_adv = 0; ++ u8 flowctrl; ++ u32 mcr = PMCR_USERP_LINK | PMCR_FORCE_MODE; ++ ++ switch (phydev->speed) { ++ case SPEED_1000: ++ mcr |= PMCR_FORCE_SPEED_1000; ++ break; ++ case SPEED_100: ++ mcr |= PMCR_FORCE_SPEED_100; ++ break; ++ }; ++ ++ if (phydev->link) ++ mcr |= PMCR_FORCE_LNK; ++ ++ if (phydev->duplex) { ++ mcr |= PMCR_FORCE_FDX; ++ ++ if (phydev->pause) ++ rmt_adv = LPA_PAUSE_CAP; ++ if (phydev->asym_pause) ++ rmt_adv |= LPA_PAUSE_ASYM; ++ ++ if (phydev->advertising & ADVERTISED_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_CAP; ++ if (phydev->advertising & ADVERTISED_Asym_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_ASYM; ++ ++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); ++ ++ if (flowctrl & FLOW_CTRL_TX) ++ mcr |= PMCR_TX_FC_EN; ++ if (flowctrl & FLOW_CTRL_RX) ++ mcr |= PMCR_RX_FC_EN; ++ } ++ mt7530_write(priv, MT7530_PMCR_P(port), mcr); + } + } + +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -155,6 +155,7 @@ enum mt7530_stp_state { + #define PMCR_TX_FC_EN BIT(5) + #define PMCR_RX_FC_EN BIT(4) + #define PMCR_FORCE_SPEED_1000 BIT(3) ++#define PMCR_FORCE_SPEED_100 BIT(2) + #define PMCR_FORCE_FDX BIT(1) + #define PMCR_FORCE_LNK BIT(0) + #define PMCR_COMMON_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ diff --git a/target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch deleted file mode 100644 index a22cb9941f..0000000000 --- a/target/linux/mediatek/patches-4.9/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 1387d4f0ebf4b48c09f2ea0d27a02936c3fa0010 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Thu, 31 Mar 2016 02:26:37 +0200 -Subject: [PATCH 054/102] clk: mediatek: Export CPU mux clocks for CPU - frequency control - -This patch adds CPU mux clocks which are used by Mediatek cpufreq driver -for intermediate clock source switching. - -Signed-off-by: Pi-Cheng Chen ---- - drivers/clk/mediatek/Makefile | 2 +- - drivers/clk/mediatek/clk-cpumux.c | 127 ++++++++++++++++++++++++++++++++ - drivers/clk/mediatek/clk-cpumux.h | 22 ++++++ - drivers/clk/mediatek/clk-mt2701.c | 8 ++ - drivers/clk/mediatek/clk-mt8173.c | 23 ++++++ - include/dt-bindings/clock/mt2701-clk.h | 3 +- - include/dt-bindings/clock/mt8173-clk.h | 4 +- - 7 files changed, 186 insertions(+), 3 deletions(-) - create mode 100644 drivers/clk/mediatek/clk-cpumux.c - create mode 100644 drivers/clk/mediatek/clk-cpumux.h - ---- a/drivers/clk/mediatek/Makefile -+++ b/drivers/clk/mediatek/Makefile -@@ -1,4 +1,4 @@ --obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o -+obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o - obj-$(CONFIG_RESET_CONTROLLER) += reset.o - obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o - obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o ---- /dev/null -+++ b/drivers/clk/mediatek/clk-cpumux.c -@@ -0,0 +1,127 @@ -+/* -+ * Copyright (c) 2015 Linaro Ltd. -+ * Author: Pi-Cheng Chen -+ * -+ * 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 -+#include -+#include -+ -+#include "clk-mtk.h" -+#include "clk-cpumux.h" -+ -+struct mtk_clk_cpumux { -+ struct clk_hw hw; -+ struct regmap *regmap; -+ u32 reg; -+ u32 mask; -+ u8 shift; -+}; -+ -+static inline struct mtk_clk_cpumux *to_mtk_clk_mux(struct clk_hw *_hw) -+{ -+ return container_of(_hw, struct mtk_clk_cpumux, hw); -+} -+ -+static u8 clk_cpumux_get_parent(struct clk_hw *hw) -+{ -+ struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw); -+ int num_parents = clk_hw_get_num_parents(hw); -+ unsigned int val; -+ -+ regmap_read(mux->regmap, mux->reg, &val); -+ -+ val >>= mux->shift; -+ val &= mux->mask; -+ -+ if (val >= num_parents) -+ return -EINVAL; -+ -+ return val; -+} -+ -+static int clk_cpumux_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct mtk_clk_cpumux *mux = to_mtk_clk_mux(hw); -+ u32 mask, val; -+ -+ val = index << mux->shift; -+ mask = mux->mask << mux->shift; -+ -+ return regmap_update_bits(mux->regmap, mux->reg, mask, val); -+} -+ -+static const struct clk_ops clk_cpumux_ops = { -+ .get_parent = clk_cpumux_get_parent, -+ .set_parent = clk_cpumux_set_parent, -+}; -+ -+static struct clk __init *mtk_clk_register_cpumux(const struct mtk_composite *mux, -+ struct regmap *regmap) -+{ -+ struct mtk_clk_cpumux *cpumux; -+ struct clk *clk; -+ struct clk_init_data init; -+ -+ cpumux = kzalloc(sizeof(*cpumux), GFP_KERNEL); -+ if (!cpumux) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = mux->name; -+ init.ops = &clk_cpumux_ops; -+ init.parent_names = mux->parent_names; -+ init.num_parents = mux->num_parents; -+ init.flags = mux->flags; -+ -+ cpumux->reg = mux->mux_reg; -+ cpumux->shift = mux->mux_shift; -+ cpumux->mask = BIT(mux->mux_width) - 1; -+ cpumux->regmap = regmap; -+ cpumux->hw.init = &init; -+ -+ clk = clk_register(NULL, &cpumux->hw); -+ if (IS_ERR(clk)) -+ kfree(cpumux); -+ -+ return clk; -+} -+ -+int __init mtk_clk_register_cpumuxes(struct device_node *node, -+ const struct mtk_composite *clks, int num, -+ struct clk_onecell_data *clk_data) -+{ -+ int i; -+ struct clk *clk; -+ struct regmap *regmap; -+ -+ regmap = syscon_node_to_regmap(node); -+ if (IS_ERR(regmap)) { -+ pr_err("Cannot find regmap for %s: %ld\n", node->full_name, -+ PTR_ERR(regmap)); -+ return PTR_ERR(regmap); -+ } -+ -+ for (i = 0; i < num; i++) { -+ const struct mtk_composite *mux = &clks[i]; -+ -+ clk = mtk_clk_register_cpumux(mux, regmap); -+ if (IS_ERR(clk)) { -+ pr_err("Failed to register clk %s: %ld\n", -+ mux->name, PTR_ERR(clk)); -+ continue; -+ } -+ -+ clk_data->clks[mux->id] = clk; -+ } -+ -+ return 0; -+} ---- /dev/null -+++ b/drivers/clk/mediatek/clk-cpumux.h -@@ -0,0 +1,22 @@ -+/* -+ * Copyright (c) 2015 Linaro Ltd. -+ * Author: Pi-Cheng Chen -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __DRV_CLK_CPUMUX_H -+#define __DRV_CLK_CPUMUX_H -+ -+int mtk_clk_register_cpumuxes(struct device_node *node, -+ const struct mtk_composite *clks, int num, -+ struct clk_onecell_data *clk_data); -+ -+#endif /* __DRV_CLK_CPUMUX_H */ ---- a/drivers/clk/mediatek/clk-mt2701.c -+++ b/drivers/clk/mediatek/clk-mt2701.c -@@ -18,6 +18,7 @@ - - #include "clk-mtk.h" - #include "clk-gate.h" -+#include "clk-cpumux.h" - - #include - -@@ -465,6 +466,10 @@ static const char * const cpu_parents[] - "mmpll" - }; - -+static const struct mtk_composite cpu_muxes[] __initconst = { -+ MUX(CLK_INFRA_CPUSEL, "infra_cpu_sel", cpu_parents, 0x0000, 2, 2), -+}; -+ - static const struct mtk_composite top_muxes[] __initconst = { - MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, - 0x0040, 0, 3, INVALID_MUX_GATE_BIT), -@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str - mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), - clk_data); - -+ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), -+ clk_data); -+ - r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", ---- a/drivers/clk/mediatek/clk-mt8173.c -+++ b/drivers/clk/mediatek/clk-mt8173.c -@@ -18,6 +18,7 @@ - - #include "clk-mtk.h" - #include "clk-gate.h" -+#include "clk-cpumux.h" - - #include - -@@ -525,6 +526,25 @@ static const char * const i2s3_b_ck_pare - "apll2_div5" - }; - -+static const char * const ca53_parents[] __initconst = { -+ "clk26m", -+ "armca7pll", -+ "mainpll", -+ "univpll" -+}; -+ -+static const char * const ca57_parents[] __initconst = { -+ "clk26m", -+ "armca15pll", -+ "mainpll", -+ "univpll" -+}; -+ -+static const struct mtk_composite cpu_muxes[] __initconst = { -+ MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2), -+ MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2), -+}; -+ - static const struct mtk_composite top_muxes[] __initconst = { - /* CLK_CFG_0 */ - MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3), -@@ -948,6 +968,9 @@ static void __init mtk_infrasys_init(str - clk_data); - mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data); - -+ mtk_clk_register_cpumuxes(node, cpu_muxes, ARRAY_SIZE(cpu_muxes), -+ clk_data); -+ - r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); - if (r) - pr_err("%s(): could not register clock provider: %d\n", ---- a/include/dt-bindings/clock/mt2701-clk.h -+++ b/include/dt-bindings/clock/mt2701-clk.h -@@ -221,7 +221,8 @@ - #define CLK_INFRA_PMICWRAP 17 - #define CLK_INFRA_DDCCI 18 - #define CLK_INFRA_CLK_13M 19 --#define CLK_INFRA_NR 20 -+#define CLK_INFRA_CPUSEL 20 -+#define CLK_INFRA_NR 21 - - /* PERICFG */ - ---- a/include/dt-bindings/clock/mt8173-clk.h -+++ b/include/dt-bindings/clock/mt8173-clk.h -@@ -193,7 +193,9 @@ - #define CLK_INFRA_PMICSPI 10 - #define CLK_INFRA_PMICWRAP 11 - #define CLK_INFRA_CLK_13M 12 --#define CLK_INFRA_NR_CLK 13 -+#define CLK_INFRA_CA53SEL 13 -+#define CLK_INFRA_CA57SEL 14 -+#define CLK_INFRA_NR_CLK 15 - - /* PERI_SYS */ - diff --git a/target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch b/target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch new file mode 100644 index 0000000000..29005316ee --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0054-net-ethernet-mediatek-fixed-deadlock-captured-by-loc.patch @@ -0,0 +1,105 @@ +From 746bf1c3e561aba396cd40e6540245646461117d Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Tue, 4 Jul 2017 11:17:36 +0800 +Subject: [PATCH 54/57] net: ethernet: mediatek: fixed deadlock captured by + lockdep + +Lockdep found an inconsistent lock state when mtk_get_stats64 is called +in user context while NAPI updates MAC statistics in softirq. + +Use spin_trylock_bh/spin_unlock_bh fix following lockdep warning. + +[ 81.321030] WARNING: inconsistent lock state +[ 81.325266] 4.12.0-rc1-00035-gd9dda65 #32 Not tainted +[ 81.330273] -------------------------------- +[ 81.334505] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +[ 81.340464] ksoftirqd/0/7 [HC0[0]:SC1[1]:HE1:SE0] takes: +[ 81.345731] (&syncp->seq#2){+.?...}, at: [] mtk_handle_status_irq.part.6+0x70/0x84 +[ 81.354219] {SOFTIRQ-ON-W} state was registered at: +[ 81.359062] lock_acquire+0xfc/0x2b0 +[ 81.362696] mtk_stats_update_mac+0x60/0x2c0 +[ 81.367017] mtk_get_stats64+0x17c/0x18c +[ 81.370995] dev_get_stats+0x48/0xbc +[ 81.374628] rtnl_fill_stats+0x48/0x128 +[ 81.378520] rtnl_fill_ifinfo+0x4ac/0xd1c +[ 81.382584] rtmsg_ifinfo_build_skb+0x7c/0xe0 +[ 81.386991] rtmsg_ifinfo.part.5+0x24/0x54 +[ 81.391139] rtmsg_ifinfo+0x24/0x28 +[ 81.394685] __dev_notify_flags+0xa4/0xac +[ 81.398749] dev_change_flags+0x50/0x58 +[ 81.402640] devinet_ioctl+0x768/0x85c +[ 81.406444] inet_ioctl+0x1a4/0x1d0 +[ 81.409990] sock_ioctl+0x16c/0x33c +[ 81.413538] do_vfs_ioctl+0xb4/0xa34 +[ 81.417169] SyS_ioctl+0x44/0x6c +[ 81.420458] ret_fast_syscall+0x0/0x1c +[ 81.424260] irq event stamp: 3354692 +[ 81.427806] hardirqs last enabled at (3354692): [] net_rx_action+0xc0/0x504 +[ 81.435660] hardirqs last disabled at (3354691): [] net_rx_action+0x8c/0x504 +[ 81.443515] softirqs last enabled at (3354106): [] __do_softirq+0x4b4/0x614 +[ 81.451370] softirqs last disabled at (3354109): [] run_ksoftirqd+0x44/0x80 +[ 81.459134] +[ 81.459134] other info that might help us debug this: +[ 81.465608] Possible unsafe locking scenario: +[ 81.465608] +[ 81.471478] CPU0 +[ 81.473900] ---- +[ 81.476321] lock(&syncp->seq#2); +[ 81.479701] +[ 81.482294] lock(&syncp->seq#2); +[ 81.485847] +[ 81.485847] *** DEADLOCK *** +[ 81.485847] +[ 81.491720] 1 lock held by ksoftirqd/0/7: +[ 81.495693] #0: (&(&mac->hw_stats->stats_lock)->rlock){+.+...}, at: [] mtk_handle_status_irq.part.6+0x48/0x84 +[ 81.506579] +[ 81.506579] stack backtrace: +[ 81.510904] CPU: 0 PID: 7 Comm: ksoftirqd/0 Not tainted 4.12.0-rc1-00035-gd9dda65 #32 +[ 81.518668] Hardware name: Mediatek Cortex-A7 (Device Tree) +[ 81.524208] [] (unwind_backtrace) from [] (show_stack+0x20/0x24) +[ 81.531899] [] (show_stack) from [] (dump_stack+0xb4/0xe0) +[ 81.539072] [] (dump_stack) from [] (print_usage_bug+0x234/0x2e0) +[ 81.546846] [] (print_usage_bug) from [] (mark_lock+0x63c/0x7bc) +[ 81.554532] [] (mark_lock) from [] (__lock_acquire+0x654/0x1bfc) +[ 81.562217] [] (__lock_acquire) from [] (lock_acquire+0xfc/0x2b0) +[ 81.569990] [] (lock_acquire) from [] (mtk_stats_update_mac+0x60/0x2c0) +[ 81.578283] [] (mtk_stats_update_mac) from [] (mtk_handle_status_irq.part.6+0x70/0x84) +[ 81.587865] [] (mtk_handle_status_irq.part.6) from [] (mtk_napi_tx+0x358/0x37c) +[ 81.596845] [] (mtk_napi_tx) from [] (net_rx_action+0x244/0x504) +[ 81.604533] [] (net_rx_action) from [] (__do_softirq+0x134/0x614) +[ 81.612306] [] (__do_softirq) from [] (run_ksoftirqd+0x44/0x80) +[ 81.619907] [] (run_ksoftirqd) from [] (smpboot_thread_fn+0x14c/0x25c) +[ 81.628110] [] (smpboot_thread_fn) from [] (kthread+0x150/0x180) +[ 81.635798] [] (kthread) from [] (ret_from_fork+0x14/0x24) + +Signed-off-by: Sean Wang +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -493,9 +493,9 @@ static struct rtnl_link_stats64 * mtk_ge + unsigned int start; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock(&hw_stats->stats_lock)) { ++ if (spin_trylock_bh(&hw_stats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock(&hw_stats->stats_lock); ++ spin_unlock_bh(&hw_stats->stats_lock); + } + } + +@@ -2229,9 +2229,9 @@ static void mtk_get_ethtool_stats(struct + return; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock(&hwstats->stats_lock)) { ++ if (spin_trylock_bh(&hwstats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock(&hwstats->stats_lock); ++ spin_unlock_bh(&hwstats->stats_lock); + } + } + diff --git a/target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch deleted file mode 100644 index 4e7c05965d..0000000000 --- a/target/linux/mediatek/patches-4.9/0055-cpufreq-mediatek-add-driver.patch +++ /dev/null @@ -1,433 +0,0 @@ -From 60f4e41b367bdb29530468c91c1e613b17a37755 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Wed, 30 Mar 2016 23:48:53 +0200 -Subject: [PATCH 055/102] cpufreq: mediatek: add driver - -Signed-off-by: John Crispin ---- - drivers/cpufreq/Kconfig.arm | 9 + - drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/mt7623-cpufreq.c | 389 ++++++++++++++++++++++++++++++++++++++ - 3 files changed, 399 insertions(+) - create mode 100644 drivers/cpufreq/mt7623-cpufreq.c - ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -74,6 +74,15 @@ config ARM_KIRKWOOD_CPUFREQ - This adds the CPUFreq driver for Marvell Kirkwood - SoCs. - -+config ARM_MT7623_CPUFREQ -+ bool "Mediatek MT7623 CPUFreq support" -+ depends on ARCH_MEDIATEK && REGULATOR -+ depends on ARM || (ARM_CPU_TOPOLOGY && COMPILE_TEST) -+ depends on !CPU_THERMAL || THERMAL=y -+ select PM_OPP -+ help -+ This adds the CPUFreq driver support for Mediatek MT7623 SoC. -+ - config ARM_MT8173_CPUFREQ - tristate "Mediatek MT8173 CPUFreq support" - depends on ARCH_MEDIATEK && REGULATOR ---- a/drivers/cpufreq/Makefile -+++ b/drivers/cpufreq/Makefile -@@ -58,6 +58,7 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += hi - obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o - obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o - obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o -+obj-$(CONFIG_ARM_MT7623_CPUFREQ) += mt7623-cpufreq.o - obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o - obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o - obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o ---- /dev/null -+++ b/drivers/cpufreq/mt7623-cpufreq.c -@@ -0,0 +1,389 @@ -+/* -+ * Copyright (c) 2015 Linaro Ltd. -+ * Author: Pi-Cheng Chen -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define VOLT_TOL (10000) -+ -+/* -+ * When scaling the clock frequency of a CPU clock domain, the clock source -+ * needs to be switched to another stable PLL clock temporarily until -+ * the original PLL becomes stable at target frequency. -+ */ -+struct mtk_cpu_dvfs_info { -+ struct device *cpu_dev; -+ struct regulator *proc_reg; -+ struct clk *cpu_clk; -+ struct clk *inter_clk; -+ struct thermal_cooling_device *cdev; -+ int intermediate_voltage; -+}; -+ -+static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc) -+{ -+ return regulator_set_voltage(info->proc_reg, vproc, -+ vproc + VOLT_TOL); -+} -+ -+static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, -+ unsigned int index) -+{ -+ struct cpufreq_frequency_table *freq_table = policy->freq_table; -+ struct clk *cpu_clk = policy->clk; -+ struct clk *armpll = clk_get_parent(cpu_clk); -+ struct mtk_cpu_dvfs_info *info = policy->driver_data; -+ struct device *cpu_dev = info->cpu_dev; -+ struct dev_pm_opp *opp; -+ long freq_hz, old_freq_hz; -+ int vproc, old_vproc, inter_vproc, target_vproc, ret; -+ -+ inter_vproc = info->intermediate_voltage; -+ -+ old_freq_hz = clk_get_rate(cpu_clk); -+ old_vproc = regulator_get_voltage(info->proc_reg); -+ -+ freq_hz = freq_table[index].frequency * 1000; -+ -+ rcu_read_lock(); -+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); -+ if (IS_ERR(opp)) { -+ rcu_read_unlock(); -+ pr_err("cpu%d: failed to find OPP for %ld\n", -+ policy->cpu, freq_hz); -+ return PTR_ERR(opp); -+ } -+ vproc = dev_pm_opp_get_voltage(opp); -+ rcu_read_unlock(); -+ -+ /* -+ * If the new voltage or the intermediate voltage is higher than the -+ * current voltage, scale up voltage first. -+ */ -+ target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; -+ if (old_vproc < target_vproc) { -+ ret = mtk_cpufreq_set_voltage(info, target_vproc); -+ if (ret) { -+ pr_err("cpu%d: failed to scale up voltage!\n", -+ policy->cpu); -+ mtk_cpufreq_set_voltage(info, old_vproc); -+ return ret; -+ } -+ } -+ -+ /* Reparent the CPU clock to intermediate clock. */ -+ ret = clk_set_parent(cpu_clk, info->inter_clk); -+ if (ret) { -+ pr_err("cpu%d: failed to re-parent cpu clock!\n", -+ policy->cpu); -+ mtk_cpufreq_set_voltage(info, old_vproc); -+ WARN_ON(1); -+ return ret; -+ } -+ -+ /* Set the original PLL to target rate. */ -+ ret = clk_set_rate(armpll, freq_hz); -+ if (ret) { -+ pr_err("cpu%d: failed to scale cpu clock rate!\n", -+ policy->cpu); -+ clk_set_parent(cpu_clk, armpll); -+ mtk_cpufreq_set_voltage(info, old_vproc); -+ return ret; -+ } -+ -+ /* Set parent of CPU clock back to the original PLL. */ -+ ret = clk_set_parent(cpu_clk, armpll); -+ if (ret) { -+ pr_err("cpu%d: failed to re-parent cpu clock!\n", -+ policy->cpu); -+ mtk_cpufreq_set_voltage(info, inter_vproc); -+ WARN_ON(1); -+ return ret; -+ } -+ -+ /* -+ * If the new voltage is lower than the intermediate voltage or the -+ * original voltage, scale down to the new voltage. -+ */ -+ if (vproc < inter_vproc || vproc < old_vproc) { -+ ret = mtk_cpufreq_set_voltage(info, vproc); -+ if (ret) { -+ pr_err("cpu%d: failed to scale down voltage!\n", -+ policy->cpu); -+ clk_set_parent(cpu_clk, info->inter_clk); -+ clk_set_rate(armpll, old_freq_hz); -+ clk_set_parent(cpu_clk, armpll); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static void mtk_cpufreq_ready(struct cpufreq_policy *policy) -+{ -+ struct mtk_cpu_dvfs_info *info = policy->driver_data; -+ struct device_node *np = of_node_get(info->cpu_dev->of_node); -+ -+ if (WARN_ON(!np)) -+ return; -+ -+ if (of_find_property(np, "#cooling-cells", NULL)) { -+ info->cdev = of_cpufreq_cooling_register(np, -+ policy->related_cpus); -+ -+ if (IS_ERR(info->cdev)) { -+ dev_err(info->cpu_dev, -+ "running cpufreq without cooling device: %ld\n", -+ PTR_ERR(info->cdev)); -+ -+ info->cdev = NULL; -+ } -+ } -+ -+ of_node_put(np); -+} -+ -+static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) -+{ -+ struct device *cpu_dev; -+ struct regulator *proc_reg = ERR_PTR(-ENODEV); -+ struct clk *cpu_clk = ERR_PTR(-ENODEV); -+ struct clk *inter_clk = ERR_PTR(-ENODEV); -+ struct dev_pm_opp *opp; -+ unsigned long rate; -+ int ret; -+ -+ cpu_dev = get_cpu_device(cpu); -+ if (!cpu_dev) { -+ pr_err("failed to get cpu%d device\n", cpu); -+ return -ENODEV; -+ } -+ -+ cpu_clk = clk_get(cpu_dev, "cpu"); -+ if (IS_ERR(cpu_clk)) { -+ if (PTR_ERR(cpu_clk) == -EPROBE_DEFER) -+ pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu); -+ else -+ pr_err("failed to get cpu clk for cpu%d\n", cpu); -+ -+ ret = PTR_ERR(cpu_clk); -+ return ret; -+ } -+ -+ inter_clk = clk_get(cpu_dev, "intermediate"); -+ if (IS_ERR(inter_clk)) { -+ if (PTR_ERR(inter_clk) == -EPROBE_DEFER) -+ pr_warn("intermediate clk for cpu%d not ready, retry.\n", -+ cpu); -+ else -+ pr_err("failed to get intermediate clk for cpu%d\n", -+ cpu); -+ -+ ret = PTR_ERR(inter_clk); -+ goto out_free_resources; -+ } -+ -+ proc_reg = regulator_get_exclusive(cpu_dev, "proc"); -+ if (IS_ERR(proc_reg)) { -+ if (PTR_ERR(proc_reg) == -EPROBE_DEFER) -+ pr_warn("proc regulator for cpu%d not ready, retry.\n", -+ cpu); -+ else -+ pr_err("failed to get proc regulator for cpu%d\n", -+ cpu); -+ -+ ret = PTR_ERR(proc_reg); -+ goto out_free_resources; -+ } -+ -+ ret = dev_pm_opp_of_add_table(cpu_dev); -+ if (ret) { -+ pr_warn("no OPP table for cpu%d\n", cpu); -+ goto out_free_resources; -+ } -+ -+ /* Search a safe voltage for intermediate frequency. */ -+ rate = clk_get_rate(inter_clk); -+ rcu_read_lock(); -+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); -+ if (IS_ERR(opp)) { -+ rcu_read_unlock(); -+ pr_err("failed to get intermediate opp for cpu%d\n", cpu); -+ ret = PTR_ERR(opp); -+ goto out_free_opp_table; -+ } -+ info->intermediate_voltage = dev_pm_opp_get_voltage(opp); -+ rcu_read_unlock(); -+ -+ info->cpu_dev = cpu_dev; -+ info->proc_reg = proc_reg; -+ info->cpu_clk = cpu_clk; -+ info->inter_clk = inter_clk; -+ -+ return 0; -+ -+out_free_opp_table: -+ dev_pm_opp_of_remove_table(cpu_dev); -+ -+out_free_resources: -+ if (!IS_ERR(proc_reg)) -+ regulator_put(proc_reg); -+ if (!IS_ERR(cpu_clk)) -+ clk_put(cpu_clk); -+ if (!IS_ERR(inter_clk)) -+ clk_put(inter_clk); -+ -+ return ret; -+} -+ -+static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) -+{ -+ if (!IS_ERR(info->proc_reg)) -+ regulator_put(info->proc_reg); -+ if (!IS_ERR(info->cpu_clk)) -+ clk_put(info->cpu_clk); -+ if (!IS_ERR(info->inter_clk)) -+ clk_put(info->inter_clk); -+ -+ dev_pm_opp_of_remove_table(info->cpu_dev); -+} -+ -+static int mtk_cpufreq_init(struct cpufreq_policy *policy) -+{ -+ struct mtk_cpu_dvfs_info *info; -+ struct cpufreq_frequency_table *freq_table; -+ int ret; -+ -+ info = kzalloc(sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return -ENOMEM; -+ -+ ret = mtk_cpu_dvfs_info_init(info, policy->cpu); -+ if (ret) { -+ pr_err("%s failed to initialize dvfs info for cpu%d\n", -+ __func__, policy->cpu); -+ goto out_free_dvfs_info; -+ } -+ -+ ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); -+ if (ret) { -+ pr_err("failed to init cpufreq table for cpu%d: %d\n", -+ policy->cpu, ret); -+ goto out_release_dvfs_info; -+ } -+ -+ ret = cpufreq_table_validate_and_show(policy, freq_table); -+ if (ret) { -+ pr_err("%s: invalid frequency table: %d\n", __func__, ret); -+ goto out_free_cpufreq_table; -+ } -+ -+ /* CPUs in the same cluster share a clock and power domain. */ -+ cpumask_setall(policy->cpus); -+ policy->driver_data = info; -+ policy->clk = info->cpu_clk; -+ -+ return 0; -+ -+out_free_cpufreq_table: -+ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); -+ -+out_release_dvfs_info: -+ mtk_cpu_dvfs_info_release(info); -+ -+out_free_dvfs_info: -+ kfree(info); -+ -+ return ret; -+} -+ -+static int mtk_cpufreq_exit(struct cpufreq_policy *policy) -+{ -+ struct mtk_cpu_dvfs_info *info = policy->driver_data; -+ -+ cpufreq_cooling_unregister(info->cdev); -+ dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); -+ mtk_cpu_dvfs_info_release(info); -+ kfree(info); -+ -+ return 0; -+} -+ -+static struct cpufreq_driver mt7623_cpufreq_driver = { -+ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, -+ .verify = cpufreq_generic_frequency_table_verify, -+ .target_index = mtk_cpufreq_set_target, -+ .get = cpufreq_generic_get, -+ .init = mtk_cpufreq_init, -+ .exit = mtk_cpufreq_exit, -+ .ready = mtk_cpufreq_ready, -+ .name = "mtk-cpufreq", -+ .attr = cpufreq_generic_attr, -+}; -+ -+static int mt7623_cpufreq_probe(struct platform_device *pdev) -+{ -+ int ret; -+ -+ ret = cpufreq_register_driver(&mt7623_cpufreq_driver); -+ if (ret) -+ pr_err("failed to register mtk cpufreq driver\n"); -+ -+ return ret; -+} -+ -+static struct platform_driver mt7623_cpufreq_platdrv = { -+ .driver = { -+ .name = "mt7623-cpufreq", -+ }, -+ .probe = mt7623_cpufreq_probe, -+}; -+ -+static int mt7623_cpufreq_driver_init(void) -+{ -+ struct platform_device *pdev; -+ int err; -+ -+ if (!of_machine_is_compatible("mediatek,mt7623")) -+ return -ENODEV; -+ -+ err = platform_driver_register(&mt7623_cpufreq_platdrv); -+ if (err) -+ return err; -+ -+ /* -+ * Since there's no place to hold device registration code and no -+ * device tree based way to match cpufreq driver yet, both the driver -+ * and the device registration codes are put here to handle defer -+ * probing. -+ */ -+ pdev = platform_device_register_simple("mt7623-cpufreq", -1, NULL, 0); -+ if (IS_ERR(pdev)) { -+ pr_err("failed to register mtk-cpufreq platform device\n"); -+ return PTR_ERR(pdev); -+ } -+ -+ return 0; -+} -+device_initcall(mt7623_cpufreq_driver_init); diff --git a/target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch b/target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch new file mode 100644 index 0000000000..6598e8208c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0055-net-ethernet-mediatek-avoid-potential-invalid-memory.patch @@ -0,0 +1,31 @@ +From a3360b3543b9fb833ba691019e396e72293a313f Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:31:45 +0200 +Subject: [PATCH 55/57] net: ethernet: mediatek: avoid potential invalid memory + access + +Potential dangerous invalid memory might be accessed if invalid mac value +reflected from the forward port field in rxd4 caused by possible potential +hardware defects. So added a simple sanity checker to avoid the kind of +situation happening. + +Signed-off-by: Sean Wang +Acked-by: John Crispin +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -964,6 +964,10 @@ static int mtk_poll_rx(struct napi_struc + mac--; + } + ++ if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || ++ !eth->netdev[mac])) ++ goto release_desc; ++ + netdev = eth->netdev[mac]; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) diff --git a/target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch b/target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch new file mode 100644 index 0000000000..d1d6ed473b --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0056-net-mediatek-add-hw-nat-support.patch @@ -0,0 +1,119 @@ +From 043efc0e619e04661be2b1889382db2fdd378145 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:34:36 +0200 +Subject: [PATCH 56/57] net: mediatek: add hw nat support + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/Kconfig | 7 +++++++ + drivers/net/ethernet/mediatek/Makefile | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 13 +++++++++++++ + net/netfilter/nf_conntrack_proto_tcp.c | 19 +++++++++++++++++++ + 4 files changed, 40 insertions(+) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -14,4 +14,11 @@ config NET_MEDIATEK_SOC + This driver supports the gigabit ethernet MACs in the + MediaTek MT2701/MT7623 chipset family. + ++config NET_MEDIATEK_HNAT ++ tristate "MediaTek MT7623 hardware NAT support" ++ depends on NET_MEDIATEK_SOC && NF_CONNTRACK && NF_CONNTRACK_IPV4 && IP_NF_NAT && IP_NF_TARGET_MASQUERADE ++ ---help--- ++ This driver supports the hardwaer NAT in the ++ MediaTek MT2701/MT7623 chipset family. ++ + endif #NET_VENDOR_MEDIATEK +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -3,3 +3,4 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o ++obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtk_hnat/ +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -23,6 +23,10 @@ + #include + #include + ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++#include "mtk_hnat/nf_hnat_mtk.h" ++#endif ++ + #include "mtk_eth_soc.h" + + static int mtk_msg_level = -1; +@@ -649,6 +653,11 @@ static int mtk_tx_map(struct sk_buff *sk + return -ENOMEM; + + /* set the forward port */ ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++ if (HNAT_SKB_CB2(skb)->magic == 0x78681415) ++ fport |= 0x4 << TX_DMA_FPORT_SHIFT; ++ else ++#endif + fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; + txd4 |= fport; + +@@ -1013,6 +1022,10 @@ static int mtk_poll_rx(struct napi_struc + RX_DMA_VID(trxd.rxd3)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); ++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) ++ *(u32 *)(skb->head) = trxd.rxd4; ++ skb_hnat_alg(skb) = 0; ++#endif + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -19,6 +20,7 @@ + #include + #include + ++#include + #include + + #include +@@ -53,6 +55,11 @@ static int nf_ct_tcp_max_retrans __read_ + /* FIXME: Examine ipfilter's timeouts and conntrack transitions more + closely. They're more complex. --RR */ + ++#ifndef IPV4_DEVCONF_DFLT ++ #define IPV4_DEVCONF_DFLT(net, attr) \ ++ IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr) ++#endif ++ + static const char *const tcp_conntrack_names[] = { + "NONE", + "SYN_SENT", +@@ -519,6 +526,18 @@ static bool tcp_in_window(const struct n + if (nf_ct_tcp_no_window_check) + return true; + ++ if (net) { ++ if ((net->ipv4.devconf_all && net->ipv4.devconf_dflt && net->ipv6.devconf_all) && ++ net->ipv6.devconf_dflt) { ++ if ((IPV4_DEVCONF_DFLT(net, FORWARDING) || ++ IPV4_DEVCONF_ALL(net, FORWARDING)) || ++ (net->ipv6.devconf_all->forwarding || ++ net->ipv6.devconf_dflt->forwarding)) { ++ return true; ++ } ++ } ++ } ++ + /* + * Get the required data from the packet. + */ diff --git a/target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch b/target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch new file mode 100644 index 0000000000..f6284583a4 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0057-net-mediatek-add-HW-QoS-support.patch @@ -0,0 +1,121 @@ +From 660c13dfbacbf37f090a66a2b14f0c5ce7cbec81 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 16:38:27 +0200 +Subject: [PATCH 57/57] net: mediatek: add HW QoS support + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/Kconfig | 7 ++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 60 ++++++++++++++++++++++++++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + 3 files changed, 66 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -21,4 +21,11 @@ config NET_MEDIATEK_HNAT + This driver supports the hardwaer NAT in the + MediaTek MT2701/MT7623 chipset family. + ++config NET_MEDIATEK_HW_QOS ++ tristate "MediaTek MT7623 hardware QoS support" ++ depends on NET_MEDIATEK_SOC ++ ---help--- ++ This driver supports the hardware QoS in the ++ MediaTek MT2701/MT7623 chipset family. ++ + endif #NET_VENDOR_MEDIATEK +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -23,6 +23,17 @@ + #include + #include + ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++struct mtk_ioctl_reg { ++ unsigned int off; ++ unsigned int val; ++}; ++ ++#define REG_HQOS_MAX 0x3FFF ++#define RAETH_QDMA_REG_READ 0x89F8 ++#define RAETH_QDMA_REG_WRITE 0x89F9 ++#endif ++ + #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) + #include "mtk_hnat/nf_hnat_mtk.h" + #endif +@@ -646,7 +657,7 @@ static int mtk_tx_map(struct sk_buff *sk + dma_addr_t mapped_addr; + unsigned int nr_frags; + int i, n_desc = 1; +- u32 txd4 = 0, fport; ++ u32 txd3 = 0, txd4 = 0, fport; + + itxd = ring->next_free; + if (itxd == ring->last_free) +@@ -675,6 +686,12 @@ static int mtk_tx_map(struct sk_buff *sk + // if (skb_vlan_tag_present(skb)) + // txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); + ++#ifdef CONFIG_NET_MEDIATEK_HW_QOS ++ txd3 |= skb->mark & 0x7; ++ if (mac->id) ++ txd3 += 8; ++#endif ++ + mapped_addr = dma_map_single(eth->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) +@@ -718,7 +735,8 @@ static int mtk_tx_map(struct sk_buff *sk + WRITE_ONCE(txd->txd1, mapped_addr); + WRITE_ONCE(txd->txd3, (TX_DMA_SWC | + TX_DMA_PLEN0(frag_map_size) | +- last_frag * TX_DMA_LS0)); ++ last_frag * TX_DMA_LS0 | ++ txd3)); + WRITE_ONCE(txd->txd4, fport); + + tx_buf = mtk_desc_to_tx_buf(ring, txd); +@@ -2029,7 +2047,31 @@ static void mtk_uninit(struct net_device + + static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ struct mtk_ioctl_reg reg; ++#endif ++ + switch (cmd) { ++#if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ case RAETH_QDMA_REG_READ: ++ copy_from_user(®, ifr->ifr_data, sizeof(reg)); ++ if (reg.off > REG_HQOS_MAX) ++ return -EINVAL; ++ reg.val = mtk_r32(eth, 0x1800 + reg.off); ++// printk("read reg off:%x val:%x\n", reg.off, reg.val); ++ copy_to_user(ifr->ifr_data, ®, sizeof(reg)); ++ return 0; ++ ++ case RAETH_QDMA_REG_WRITE: ++ copy_from_user(®, ifr->ifr_data, sizeof(reg)); ++ if (reg.off > REG_HQOS_MAX) ++ return -EINVAL; ++ mtk_w32(eth, reg.val, 0x1800 + reg.off); ++// printk("write reg off:%x val:%x\n", reg.off, reg.val); ++ return 0; ++#endif + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -20,7 +20,7 @@ + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 + #define MTK_TX_DMA_BUF_LEN 0x3fff +-#define MTK_DMA_SIZE 256 ++#define MTK_DMA_SIZE 2048 + #define MTK_NAPI_WEIGHT 64 + #define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) diff --git a/target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch b/target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch new file mode 100644 index 0000000000..3174b805e2 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0058-pinctrl-update.patch @@ -0,0 +1,470 @@ +--- a/drivers/pinctrl/mediatek/Kconfig ++++ b/drivers/pinctrl/mediatek/Kconfig +@@ -15,12 +15,6 @@ config PINCTRL_MT2701 + default MACH_MT2701 + select PINCTRL_MTK + +-config PINCTRL_MT7623 +- bool "Mediatek MT7623 pin control" if COMPILE_TEST && !MACH_MT7623 +- depends on OF +- default MACH_MT7623 +- select PINCTRL_MTK_COMMON +- + config PINCTRL_MT8135 + bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135 + depends on OF +--- a/drivers/pinctrl/mediatek/Makefile ++++ b/drivers/pinctrl/mediatek/Makefile +@@ -3,7 +3,6 @@ obj-y += pinctrl-mtk-common.o + + # SoC Drivers + obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o +-obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o + obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o + obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o + obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o +--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c +@@ -565,6 +565,7 @@ static int mt2701_pinctrl_probe(struct p + + static const struct of_device_id mt2701_pctrl_match[] = { + { .compatible = "mediatek,mt2701-pinctrl", }, ++ { .compatible = "mediatek,mt7623-pinctrl", }, + {} + }; + MODULE_DEVICE_TABLE(of, mt2701_pctrl_match); +--- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c ++++ /dev/null +@@ -1,379 +0,0 @@ +-/* +- * Copyright (c) 2016 John Crispin +- * +- * 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 +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "pinctrl-mtk-common.h" +-#include "pinctrl-mtk-mt7623.h" +- +-static const struct mtk_drv_group_desc mt7623_drv_grp[] = { +- /* 0E4E8SR 4/8/12/16 */ +- MTK_DRV_GRP(4, 16, 1, 2, 4), +- /* 0E2E4SR 2/4/6/8 */ +- MTK_DRV_GRP(2, 8, 1, 2, 2), +- /* E8E4E2 2/4/6/8/10/12/14/16 */ +- MTK_DRV_GRP(2, 16, 0, 2, 2) +-}; +- +-#define DRV_SEL0 0xf50 +-#define DRV_SEL1 0xf60 +-#define DRV_SEL2 0xf70 +-#define DRV_SEL3 0xf80 +-#define DRV_SEL4 0xf90 +-#define DRV_SEL5 0xfa0 +-#define DRV_SEL6 0xfb0 +-#define DRV_SEL7 0xfe0 +-#define DRV_SEL8 0xfd0 +-#define DRV_SEL9 0xff0 +-#define DRV_SEL10 0xf00 +- +-#define MSDC0_CTRL0 0xcc0 +-#define MSDC0_CTRL1 0xcd0 +-#define MSDC0_CTRL2 0xce0 +-#define MSDC0_CTRL3 0xcf0 +-#define MSDC0_CTRL4 0xd00 +-#define MSDC0_CTRL5 0xd10 +-#define MSDC0_CTRL6 0xd20 +-#define MSDC1_CTRL0 0xd30 +-#define MSDC1_CTRL1 0xd40 +-#define MSDC1_CTRL2 0xd50 +-#define MSDC1_CTRL3 0xd60 +-#define MSDC1_CTRL4 0xd70 +-#define MSDC1_CTRL5 0xd80 +-#define MSDC1_CTRL6 0xd90 +- +-#define IES_EN0 0xb20 +-#define IES_EN1 0xb30 +-#define IES_EN2 0xb40 +- +-#define SMT_EN0 0xb50 +-#define SMT_EN1 0xb60 +-#define SMT_EN2 0xb70 +- +-static const struct mtk_pin_drv_grp mt7623_pin_drv[] = { +- MTK_PIN_DRV_GRP(0, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(1, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(2, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(3, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(4, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(5, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(6, DRV_SEL0, 0, 1), +- MTK_PIN_DRV_GRP(7, DRV_SEL0, 4, 1), +- MTK_PIN_DRV_GRP(8, DRV_SEL0, 4, 1), +- MTK_PIN_DRV_GRP(9, DRV_SEL0, 4, 1), +- MTK_PIN_DRV_GRP(10, DRV_SEL0, 8, 1), +- MTK_PIN_DRV_GRP(11, DRV_SEL0, 8, 1), +- MTK_PIN_DRV_GRP(12, DRV_SEL0, 8, 1), +- MTK_PIN_DRV_GRP(13, DRV_SEL0, 8, 1), +- MTK_PIN_DRV_GRP(14, DRV_SEL0, 12, 0), +- MTK_PIN_DRV_GRP(15, DRV_SEL0, 12, 0), +- MTK_PIN_DRV_GRP(18, DRV_SEL1, 4, 0), +- MTK_PIN_DRV_GRP(19, DRV_SEL1, 4, 0), +- MTK_PIN_DRV_GRP(20, DRV_SEL1, 4, 0), +- MTK_PIN_DRV_GRP(21, DRV_SEL1, 4, 0), +- MTK_PIN_DRV_GRP(22, DRV_SEL1, 8, 0), +- MTK_PIN_DRV_GRP(23, DRV_SEL1, 8, 0), +- MTK_PIN_DRV_GRP(24, DRV_SEL1, 8, 0), +- MTK_PIN_DRV_GRP(25, DRV_SEL1, 8, 0), +- MTK_PIN_DRV_GRP(26, DRV_SEL1, 8, 0), +- MTK_PIN_DRV_GRP(27, DRV_SEL1, 12, 0), +- MTK_PIN_DRV_GRP(28, DRV_SEL1, 12, 0), +- MTK_PIN_DRV_GRP(29, DRV_SEL1, 12, 0), +- MTK_PIN_DRV_GRP(33, DRV_SEL2, 0, 0), +- MTK_PIN_DRV_GRP(34, DRV_SEL2, 0, 0), +- MTK_PIN_DRV_GRP(35, DRV_SEL2, 0, 0), +- MTK_PIN_DRV_GRP(36, DRV_SEL2, 0, 0), +- MTK_PIN_DRV_GRP(37, DRV_SEL2, 0, 0), +- MTK_PIN_DRV_GRP(39, DRV_SEL2, 8, 1), +- MTK_PIN_DRV_GRP(40, DRV_SEL2, 8, 1), +- MTK_PIN_DRV_GRP(41, DRV_SEL2, 8, 1), +- MTK_PIN_DRV_GRP(42, DRV_SEL2, 8, 1), +- MTK_PIN_DRV_GRP(43, DRV_SEL2, 12, 0), +- MTK_PIN_DRV_GRP(44, DRV_SEL2, 12, 0), +- MTK_PIN_DRV_GRP(45, DRV_SEL2, 12, 0), +- MTK_PIN_DRV_GRP(47, DRV_SEL3, 0, 0), +- MTK_PIN_DRV_GRP(48, DRV_SEL3, 0, 0), +- MTK_PIN_DRV_GRP(49, DRV_SEL3, 4, 0), +- MTK_PIN_DRV_GRP(53, DRV_SEL3, 12, 0), +- MTK_PIN_DRV_GRP(54, DRV_SEL3, 12, 0), +- MTK_PIN_DRV_GRP(55, DRV_SEL3, 12, 0), +- MTK_PIN_DRV_GRP(56, DRV_SEL3, 12, 0), +- MTK_PIN_DRV_GRP(60, DRV_SEL4, 8, 1), +- MTK_PIN_DRV_GRP(61, DRV_SEL4, 8, 1), +- MTK_PIN_DRV_GRP(62, DRV_SEL4, 8, 1), +- MTK_PIN_DRV_GRP(63, DRV_SEL4, 12, 1), +- MTK_PIN_DRV_GRP(64, DRV_SEL4, 12, 1), +- MTK_PIN_DRV_GRP(65, DRV_SEL4, 12, 1), +- MTK_PIN_DRV_GRP(66, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(67, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(68, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(69, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(70, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(71, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(72, DRV_SEL3, 4, 0), +- MTK_PIN_DRV_GRP(73, DRV_SEL3, 4, 0), +- MTK_PIN_DRV_GRP(74, DRV_SEL3, 4, 0), +- MTK_PIN_DRV_GRP(83, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(84, DRV_SEL5, 0, 1), +- MTK_PIN_DRV_GRP(105, MSDC1_CTRL1, 0, 1), +- MTK_PIN_DRV_GRP(106, MSDC1_CTRL0, 0, 1), +- MTK_PIN_DRV_GRP(107, MSDC1_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(108, MSDC1_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(109, MSDC1_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(110, MSDC1_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(111, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(112, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(113, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(114, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(115, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(116, MSDC0_CTRL1, 0, 1), +- MTK_PIN_DRV_GRP(117, MSDC0_CTRL0, 0, 1), +- MTK_PIN_DRV_GRP(118, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(119, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(120, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(121, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(126, DRV_SEL3, 4, 0), +- MTK_PIN_DRV_GRP(199, DRV_SEL0, 4, 1), +- MTK_PIN_DRV_GRP(200, DRV_SEL8, 0, 0), +- MTK_PIN_DRV_GRP(201, DRV_SEL8, 0, 0), +- MTK_PIN_DRV_GRP(203, DRV_SEL8, 4, 0), +- MTK_PIN_DRV_GRP(204, DRV_SEL8, 4, 0), +- MTK_PIN_DRV_GRP(205, DRV_SEL8, 4, 0), +- MTK_PIN_DRV_GRP(206, DRV_SEL8, 4, 0), +- MTK_PIN_DRV_GRP(207, DRV_SEL8, 4, 0), +- MTK_PIN_DRV_GRP(208, DRV_SEL8, 8, 0), +- MTK_PIN_DRV_GRP(209, DRV_SEL8, 8, 0), +- MTK_PIN_DRV_GRP(236, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(237, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(238, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(239, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(240, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(241, DRV_SEL9, 4, 0), +- MTK_PIN_DRV_GRP(242, DRV_SEL9, 8, 0), +- MTK_PIN_DRV_GRP(243, DRV_SEL9, 8, 0), +- MTK_PIN_DRV_GRP(257, MSDC0_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(261, MSDC1_CTRL2, 0, 1), +- MTK_PIN_DRV_GRP(262, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(263, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(264, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(265, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(266, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(267, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(268, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(269, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(270, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(271, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(272, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(274, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(275, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(276, DRV_SEL10, 8, 0), +- MTK_PIN_DRV_GRP(278, DRV_SEL2, 8, 1), +-}; +- +-static const struct mtk_pin_spec_pupd_set_samereg mt7623_spec_pupd[] = { +- MTK_PIN_PUPD_SPEC_SR(105, MSDC1_CTRL1, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(106, MSDC1_CTRL0, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(107, MSDC1_CTRL3, 0, 1, 2), +- MTK_PIN_PUPD_SPEC_SR(108, MSDC1_CTRL3, 4, 5, 6), +- MTK_PIN_PUPD_SPEC_SR(109, MSDC1_CTRL3, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(110, MSDC1_CTRL3, 12, 13, 14), +- MTK_PIN_PUPD_SPEC_SR(111, MSDC0_CTRL4, 12, 13, 14), +- MTK_PIN_PUPD_SPEC_SR(112, MSDC0_CTRL4, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(113, MSDC0_CTRL4, 4, 5, 6), +- MTK_PIN_PUPD_SPEC_SR(114, MSDC0_CTRL4, 0, 1, 2), +- MTK_PIN_PUPD_SPEC_SR(115, MSDC0_CTRL5, 0, 1, 2), +- MTK_PIN_PUPD_SPEC_SR(116, MSDC0_CTRL1, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(117, MSDC0_CTRL0, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(118, MSDC0_CTRL3, 12, 13, 14), +- MTK_PIN_PUPD_SPEC_SR(119, MSDC0_CTRL3, 8, 9, 10), +- MTK_PIN_PUPD_SPEC_SR(120, MSDC0_CTRL3, 4, 5, 6), +- MTK_PIN_PUPD_SPEC_SR(121, MSDC0_CTRL3, 0, 1, 2), +-}; +- +-static int mt7623_spec_pull_set(struct regmap *regmap, unsigned int pin, +- unsigned char align, bool isup, unsigned int r1r0) +-{ +- return mtk_pctrl_spec_pull_set_samereg(regmap, mt7623_spec_pupd, +- ARRAY_SIZE(mt7623_spec_pupd), pin, align, isup, r1r0); +-} +- +-static const struct mtk_pin_ies_smt_set mt7623_ies_set[] = { +- MTK_PIN_IES_SMT_SPEC(0, 6, IES_EN0, 0), +- MTK_PIN_IES_SMT_SPEC(7, 9, IES_EN0, 1), +- MTK_PIN_IES_SMT_SPEC(10, 13, IES_EN0, 2), +- MTK_PIN_IES_SMT_SPEC(14, 15, IES_EN0, 3), +- MTK_PIN_IES_SMT_SPEC(18, 21, IES_EN0, 5), +- MTK_PIN_IES_SMT_SPEC(22, 26, IES_EN0, 6), +- MTK_PIN_IES_SMT_SPEC(27, 29, IES_EN0, 7), +- MTK_PIN_IES_SMT_SPEC(33, 37, IES_EN0, 8), +- MTK_PIN_IES_SMT_SPEC(39, 42, IES_EN0, 9), +- MTK_PIN_IES_SMT_SPEC(43, 45, IES_EN0, 10), +- MTK_PIN_IES_SMT_SPEC(47, 48, IES_EN0, 11), +- MTK_PIN_IES_SMT_SPEC(49, 49, IES_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(53, 56, IES_EN0, 14), +- MTK_PIN_IES_SMT_SPEC(60, 62, IES_EN1, 0), +- MTK_PIN_IES_SMT_SPEC(63, 65, IES_EN1, 1), +- MTK_PIN_IES_SMT_SPEC(66, 71, IES_EN1, 2), +- MTK_PIN_IES_SMT_SPEC(72, 74, IES_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(75, 76, IES_EN1, 3), +- MTK_PIN_IES_SMT_SPEC(83, 84, IES_EN1, 2), +- MTK_PIN_IES_SMT_SPEC(105, 121, MSDC1_CTRL1, 4), +- MTK_PIN_IES_SMT_SPEC(122, 125, IES_EN1, 7), +- MTK_PIN_IES_SMT_SPEC(126, 126, IES_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(199, 201, IES_EN0, 1), +- MTK_PIN_IES_SMT_SPEC(203, 207, IES_EN2, 2), +- MTK_PIN_IES_SMT_SPEC(208, 209, IES_EN2, 3), +- MTK_PIN_IES_SMT_SPEC(236, 241, IES_EN2, 6), +- MTK_PIN_IES_SMT_SPEC(242, 243, IES_EN2, 7), +- MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL2, 4), +- MTK_PIN_IES_SMT_SPEC(262, 272, IES_EN2, 12), +- MTK_PIN_IES_SMT_SPEC(274, 276, IES_EN2, 12), +- MTK_PIN_IES_SMT_SPEC(278, 278, IES_EN2, 13), +-}; +- +-static const struct mtk_pin_ies_smt_set mt7623_smt_set[] = { +- MTK_PIN_IES_SMT_SPEC(0, 6, SMT_EN0, 0), +- MTK_PIN_IES_SMT_SPEC(7, 9, SMT_EN0, 1), +- MTK_PIN_IES_SMT_SPEC(10, 13, SMT_EN0, 2), +- MTK_PIN_IES_SMT_SPEC(14, 15, SMT_EN0, 3), +- MTK_PIN_IES_SMT_SPEC(18, 21, SMT_EN0, 5), +- MTK_PIN_IES_SMT_SPEC(22, 26, SMT_EN0, 6), +- MTK_PIN_IES_SMT_SPEC(27, 29, SMT_EN0, 7), +- MTK_PIN_IES_SMT_SPEC(33, 37, SMT_EN0, 8), +- MTK_PIN_IES_SMT_SPEC(39, 42, SMT_EN0, 9), +- MTK_PIN_IES_SMT_SPEC(43, 45, SMT_EN0, 10), +- MTK_PIN_IES_SMT_SPEC(47, 48, SMT_EN0, 11), +- MTK_PIN_IES_SMT_SPEC(49, 49, SMT_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(53, 56, SMT_EN0, 14), +- MTK_PIN_IES_SMT_SPEC(60, 62, SMT_EN1, 0), +- MTK_PIN_IES_SMT_SPEC(63, 65, SMT_EN1, 1), +- MTK_PIN_IES_SMT_SPEC(66, 71, SMT_EN1, 2), +- MTK_PIN_IES_SMT_SPEC(72, 74, SMT_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(75, 76, SMT_EN1, 3), +- MTK_PIN_IES_SMT_SPEC(83, 84, SMT_EN1, 2), +- MTK_PIN_IES_SMT_SPEC(105, 106, MSDC1_CTRL1, 11), +- MTK_PIN_IES_SMT_SPEC(107, 107, MSDC1_CTRL3, 3), +- MTK_PIN_IES_SMT_SPEC(108, 108, MSDC1_CTRL3, 7), +- MTK_PIN_IES_SMT_SPEC(109, 109, MSDC1_CTRL3, 11), +- MTK_PIN_IES_SMT_SPEC(110, 111, MSDC1_CTRL3, 15), +- MTK_PIN_IES_SMT_SPEC(112, 112, MSDC0_CTRL4, 11), +- MTK_PIN_IES_SMT_SPEC(113, 113, MSDC0_CTRL4, 7), +- MTK_PIN_IES_SMT_SPEC(114, 115, MSDC0_CTRL4, 3), +- MTK_PIN_IES_SMT_SPEC(116, 117, MSDC0_CTRL1, 11), +- MTK_PIN_IES_SMT_SPEC(118, 118, MSDC0_CTRL3, 15), +- MTK_PIN_IES_SMT_SPEC(119, 119, MSDC0_CTRL3, 11), +- MTK_PIN_IES_SMT_SPEC(120, 120, MSDC0_CTRL3, 7), +- MTK_PIN_IES_SMT_SPEC(121, 121, MSDC0_CTRL3, 3), +- MTK_PIN_IES_SMT_SPEC(122, 125, SMT_EN1, 7), +- MTK_PIN_IES_SMT_SPEC(126, 126, SMT_EN0, 12), +- MTK_PIN_IES_SMT_SPEC(199, 201, SMT_EN0, 1), +- MTK_PIN_IES_SMT_SPEC(203, 207, SMT_EN2, 2), +- MTK_PIN_IES_SMT_SPEC(208, 209, SMT_EN2, 3), +- MTK_PIN_IES_SMT_SPEC(236, 241, SMT_EN2, 6), +- MTK_PIN_IES_SMT_SPEC(242, 243, SMT_EN2, 7), +- MTK_PIN_IES_SMT_SPEC(261, 261, MSDC1_CTRL6, 3), +- MTK_PIN_IES_SMT_SPEC(262, 272, SMT_EN2, 12), +- MTK_PIN_IES_SMT_SPEC(274, 276, SMT_EN2, 12), +- MTK_PIN_IES_SMT_SPEC(278, 278, SMT_EN2, 13), +-}; +- +-static int mt7623_ies_smt_set(struct regmap *regmap, unsigned int pin, +- unsigned char align, int value, enum pin_config_param arg) +-{ +- if (arg == PIN_CONFIG_INPUT_ENABLE) +- return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_ies_set, +- ARRAY_SIZE(mt7623_ies_set), pin, align, value); +- else if (arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE) +- return mtk_pconf_spec_set_ies_smt_range(regmap, mt7623_smt_set, +- ARRAY_SIZE(mt7623_smt_set), pin, align, value); +- return -EINVAL; +-} +- +-static const struct mtk_pinctrl_devdata mt7623_pinctrl_data = { +- .pins = mtk_pins_mt7623, +- .npins = ARRAY_SIZE(mtk_pins_mt7623), +- .grp_desc = mt7623_drv_grp, +- .n_grp_cls = ARRAY_SIZE(mt7623_drv_grp), +- .pin_drv_grp = mt7623_pin_drv, +- .n_pin_drv_grps = ARRAY_SIZE(mt7623_pin_drv), +- .spec_pull_set = mt7623_spec_pull_set, +- .spec_ies_smt_set = mt7623_ies_smt_set, +- .dir_offset = 0x0000, +- .pullen_offset = 0x0150, +- .pullsel_offset = 0x0280, +- .dout_offset = 0x0500, +- .din_offset = 0x0630, +- .pinmux_offset = 0x0760, +- .type1_start = 280, +- .type1_end = 280, +- .port_shf = 4, +- .port_mask = 0x1f, +- .port_align = 4, +- .eint_offsets = { +- .name = "mt7623_eint", +- .stat = 0x000, +- .ack = 0x040, +- .mask = 0x080, +- .mask_set = 0x0c0, +- .mask_clr = 0x100, +- .sens = 0x140, +- .sens_set = 0x180, +- .sens_clr = 0x1c0, +- .soft = 0x200, +- .soft_set = 0x240, +- .soft_clr = 0x280, +- .pol = 0x300, +- .pol_set = 0x340, +- .pol_clr = 0x380, +- .dom_en = 0x400, +- .dbnc_ctrl = 0x500, +- .dbnc_set = 0x600, +- .dbnc_clr = 0x700, +- .port_mask = 6, +- .ports = 6, +- }, +- .ap_num = 169, +- .db_cnt = 16, +-}; +- +-static int mt7623_pinctrl_probe(struct platform_device *pdev) +-{ +- return mtk_pctrl_init(pdev, &mt7623_pinctrl_data, NULL); +-} +- +-static const struct of_device_id mt7623_pctrl_match[] = { +- { .compatible = "mediatek,mt7623-pinctrl", }, +- {} +-}; +-MODULE_DEVICE_TABLE(of, mt7623_pctrl_match); +- +-static struct platform_driver mtk_pinctrl_driver = { +- .probe = mt7623_pinctrl_probe, +- .driver = { +- .name = "mediatek-mt7623-pinctrl", +- .of_match_table = mt7623_pctrl_match, +- }, +-}; +- +-static int __init mtk_pinctrl_init(void) +-{ +- return platform_driver_register(&mtk_pinctrl_driver); +-} +- +-arch_initcall(mtk_pinctrl_init); +--- a/include/dt-bindings/pinctrl/mt7623-pinfunc.h ++++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h +@@ -185,6 +185,12 @@ + #define MT7623_PIN_56_SPI0_MO_FUNC_SPI0_MO (MTK_PIN_NO(56) | 1) + #define MT7623_PIN_56_SPI0_MO_FUNC_SPI0_MI (MTK_PIN_NO(56) | 2) + ++#define MT7623_PIN_57_SDA1_FUNC_GPIO57 (MTK_PIN_NO(57) | 0) ++#define MT7623_PIN_57_SDA1_FUNC_SDA1 (MTK_PIN_NO(57) | 1) ++ ++#define MT7623_PIN_58_SCL1_FUNC_GPIO58 (MTK_PIN_NO(58) | 0) ++#define MT7623_PIN_58_SCL1_FUNC_SCL1 (MTK_PIN_NO(58) | 1) ++ + #define MT7623_PIN_60_WB_RSTB_FUNC_GPIO60 (MTK_PIN_NO(60) | 0) + #define MT7623_PIN_60_WB_RSTB_FUNC_WB_RSTB (MTK_PIN_NO(60) | 1) + +@@ -244,6 +250,22 @@ + #define MT7623_PIN_76_SCL0_FUNC_GPIO76 (MTK_PIN_NO(76) | 0) + #define MT7623_PIN_76_SCL0_FUNC_SCL0 (MTK_PIN_NO(76) | 1) + ++#define MT7623_PIN_79_URXD0_FUNC_GPIO79 (MTK_PIN_NO(79) | 0) ++#define MT7623_PIN_79_URXD0_FUNC_URXD0 (MTK_PIN_NO(79) | 1) ++#define MT7623_PIN_79_URXD0_FUNC_UTXD0 (MTK_PIN_NO(79) | 2) ++ ++#define MT7623_PIN_80_UTXD0_FUNC_GPIO80 (MTK_PIN_NO(80) | 0) ++#define MT7623_PIN_80_UTXD0_FUNC_UTXD0 (MTK_PIN_NO(80) | 1) ++#define MT7623_PIN_80_UTXD0_FUNC_URXD0 (MTK_PIN_NO(80) | 2) ++ ++#define MT7623_PIN_81_URXD1_FUNC_GPIO81 (MTK_PIN_NO(81) | 0) ++#define MT7623_PIN_81_URXD1_FUNC_URXD1 (MTK_PIN_NO(81) | 1) ++#define MT7623_PIN_81_URXD1_FUNC_UTXD1 (MTK_PIN_NO(81) | 2) ++ ++#define MT7623_PIN_82_UTXD1_FUNC_GPIO82 (MTK_PIN_NO(82) | 0) ++#define MT7623_PIN_82_UTXD1_FUNC_UTXD1 (MTK_PIN_NO(82) | 1) ++#define MT7623_PIN_82_UTXD1_FUNC_URXD1 (MTK_PIN_NO(82) | 2) ++ + #define MT7623_PIN_83_LCM_RST_FUNC_GPIO83 (MTK_PIN_NO(83) | 0) + #define MT7623_PIN_83_LCM_RST_FUNC_LCM_RST (MTK_PIN_NO(83) | 1) + +@@ -351,10 +373,10 @@ + #define MT7623_PIN_122_GPIO122_FUNC_SDA2 (MTK_PIN_NO(122) | 4) + #define MT7623_PIN_122_GPIO122_FUNC_URXD0 (MTK_PIN_NO(122) | 5) + +-#define MT7623_PIN_123_GPIO123_FUNC_GPIO123 (MTK_PIN_NO(123) | 0) +-#define MT7623_PIN_123_GPIO123_FUNC_TEST (MTK_PIN_NO(123) | 1) +-#define MT7623_PIN_123_GPIO123_FUNC_SCL2 (MTK_PIN_NO(123) | 4) +-#define MT7623_PIN_123_GPIO123_FUNC_UTXD0 (MTK_PIN_NO(123) | 5) ++#define MT7623_PIN_123_HTPLG_FUNC_GPIO123 (MTK_PIN_NO(123) | 0) ++#define MT7623_PIN_123_HTPLG_FUNC_HTPLG (MTK_PIN_NO(123) | 1) ++#define MT7623_PIN_123_HTPLG_FUNC_SCL2 (MTK_PIN_NO(123) | 4) ++#define MT7623_PIN_123_HTPLG_FUNC_UTXD0 (MTK_PIN_NO(123) | 5) + + #define MT7623_PIN_124_GPIO124_FUNC_GPIO124 (MTK_PIN_NO(124) | 0) + #define MT7623_PIN_124_GPIO124_FUNC_TEST (MTK_PIN_NO(124) | 1) diff --git a/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch b/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch new file mode 100644 index 0000000000..61b4b2615c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0059-eth-fixes.patch @@ -0,0 +1,531 @@ +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,7 @@ + #include + + #if defined(CONFIG_NET_MEDIATEK_HW_QOS) ++ + struct mtk_ioctl_reg { + unsigned int off; + unsigned int val; +@@ -32,6 +33,13 @@ struct mtk_ioctl_reg { + #define REG_HQOS_MAX 0x3FFF + #define RAETH_QDMA_REG_READ 0x89F8 + #define RAETH_QDMA_REG_WRITE 0x89F9 ++#define RAETH_QDMA_QUEUE_MAPPING 0x89FA ++ ++unsigned int M2Q_table[16] = {0}; ++unsigned int lan_wan_separate = 0; ++ ++EXPORT_SYMBOL_GPL(M2Q_table); ++ + #endif + + #if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE) +@@ -225,7 +233,7 @@ static void mtk_phy_link_adjust(struct n + if (flowctrl & FLOW_CTRL_RX) + mcr |= MAC_MCR_FORCE_RX_FC; + +- netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n", ++ netif_info(mac->hw, link, dev, "rx pause %s, tx pause %s\n", + flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", + flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); + } +@@ -508,9 +516,9 @@ static struct rtnl_link_stats64 * mtk_ge + unsigned int start; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock_bh(&hw_stats->stats_lock)) { ++ if (spin_trylock(&hw_stats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock_bh(&hw_stats->stats_lock); ++ spin_unlock(&hw_stats->stats_lock); + } + } + +@@ -690,6 +698,7 @@ static int mtk_tx_map(struct sk_buff *sk + txd3 |= skb->mark & 0x7; + if (mac->id) + txd3 += 8; ++ txd3 = 0; + #endif + + mapped_addr = dma_map_single(eth->dev, skb->data, +@@ -760,16 +769,7 @@ static int mtk_tx_map(struct sk_buff *sk + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- /* we have a single DMA ring so BQL needs to be updated for all devices +- * sitting on this ring +- */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i]) +- continue; +- +- netdev_sent_queue(eth->netdev[i], skb->len); +- } +- ++ netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -980,20 +980,9 @@ static int mtk_poll_rx(struct napi_struc + if (!(trxd.rxd2 & RX_DMA_DONE)) + break; + +- /* find out which mac the packet comes from. If the special tag is +- * we can assume that the traffic is coming from the builtin mt7530 +- * and the DSA driver has loaded. FPORT will be the physical switch +- * port in this case rather than the FE forward port id. */ +- if (!(trxd.rxd4 & RX_DMA_SP_TAG)) { +- /* values start at 1 */ +- mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & +- RX_DMA_FPORT_MASK; +- mac--; +- } +- +- if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || +- !eth->netdev[mac])) +- goto release_desc; ++ /* find out which mac the packet come from. values start at 1 */ ++ mac = (trxd.rxd4 >> 22) & 0x1; ++ mac = (mac + 1) % 2; + + netdev = eth->netdev[mac]; + +@@ -1017,6 +1006,9 @@ static int mtk_poll_rx(struct napi_struc + } + + /* receive data */ ++ if (mac < 0 || mac > 2) ++ mac = 0; ++ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { + skb_free_frag(new_data); +@@ -1076,18 +1068,21 @@ static int mtk_poll_tx(struct mtk_eth *e + struct mtk_tx_dma *desc; + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; +- int total = 0, done = 0; +- unsigned int bytes = 0; ++ unsigned int done[MTK_MAX_DEVS]; ++ unsigned int bytes[MTK_MAX_DEVS]; + u32 cpu, dma; + static int condition; +- int i; ++ int total = 0, i; ++ ++ memset(done, 0, sizeof(done)); ++ memset(bytes, 0, sizeof(bytes)); + + cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); + dma = mtk_r32(eth, MTK_QTX_DRX_PTR); + + desc = mtk_qdma_phys_to_virt(ring, cpu); + +- while ((cpu != dma) && done < budget) { ++ while ((cpu != dma) && budget) { + u32 next_cpu = desc->txd2; + int mac = 0; + +@@ -1106,8 +1101,9 @@ static int mtk_poll_tx(struct mtk_eth *e + } + + if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { +- bytes += skb->len; +- done++; ++ bytes[mac] += skb->len; ++ done[mac]++; ++ budget--; + } + mtk_tx_unmap(eth, tx_buf); + +@@ -1119,13 +1115,11 @@ static int mtk_poll_tx(struct mtk_eth *e + + mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + +- /* we have a single DMA ring so BQL needs to be updated for all devices +- * sitting on this ring +- */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i]) ++ if (!eth->netdev[i] || !done[i]) + continue; +- netdev_completed_queue(eth->netdev[i], done, bytes); ++ netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); ++ total += done[i]; + } + + if (mtk_queue_stopped(eth) && +@@ -1286,21 +1280,11 @@ static void mtk_tx_clean(struct mtk_eth + + static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + { +- struct mtk_rx_ring *ring; ++ struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; + int rx_data_len, rx_dma_size; + int i; +- u32 offset = 0; +- +- if (rx_flag & MTK_RX_FLAGS_QDMA) { +- if (ring_no) +- return -EINVAL; +- ring = ð->rx_ring_qdma; +- offset = 0x1000; +- } else { +- ring = ð->rx_ring[ring_no]; +- } + +- if (rx_flag & MTK_RX_FLAGS_HWLRO) { ++ if (rx_flag == MTK_RX_FLAGS_HWLRO) { + rx_data_len = MTK_MAX_LRO_RX_LENGTH; + rx_dma_size = MTK_HW_LRO_DMA_SIZE; + } else { +@@ -1348,16 +1332,104 @@ static int mtk_rx_alloc(struct mtk_eth * + */ + wmb(); + +- mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); +- mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); +- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); +- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); ++ mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no)); ++ mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no)); ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX); + + return 0; + } + +-static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring) ++static int mtk_rx_alloc_qdma(struct mtk_eth *eth, int rx_flag) + { ++ struct mtk_rx_ring *ring = ð->rx_ring_qdma; ++ int rx_data_len, rx_dma_size; ++ int i; ++ ++ rx_data_len = ETH_DATA_LEN; ++ rx_dma_size = MTK_DMA_SIZE; ++ ++ ring->frag_size = mtk_max_frag_size(rx_data_len); ++ ring->buf_size = mtk_max_buf_size(ring->frag_size); ++ ring->data = kcalloc(rx_dma_size, sizeof(*ring->data), ++ GFP_KERNEL); ++ if (!ring->data) ++ return -ENOMEM; ++ ++ for (i = 0; i < rx_dma_size; i++) { ++ ring->data[i] = netdev_alloc_frag(ring->frag_size); ++ if (!ring->data[i]) ++ return -ENOMEM; ++ } ++ ++ ring->dma = dma_alloc_coherent(eth->dev, ++ rx_dma_size * sizeof(*ring->dma), ++ &ring->phys, ++ GFP_ATOMIC | __GFP_ZERO); ++ if (!ring->dma) ++ return -ENOMEM; ++ ++ for (i = 0; i < rx_dma_size; i++) { ++ dma_addr_t dma_addr = dma_map_single(eth->dev, ++ ring->data[i] + NET_SKB_PAD, ++ ring->buf_size, ++ DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dev, dma_addr))) ++ return -ENOMEM; ++ ring->dma[i].rxd1 = (unsigned int)dma_addr; ++ ++ ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ } ++ ring->dma_size = rx_dma_size; ++ ring->calc_idx_update = false; ++ ring->calc_idx = rx_dma_size - 1; ++ ring->crx_idx_reg = MTK_QRX_CRX_IDX_CFG(0); ++ /* make sure that all changes to the dma ring are flushed before we ++ * continue ++ */ ++ wmb(); ++ ++ mtk_w32(eth, ring->phys, MTK_QRX_BASE_PTR_CFG(0)); ++ mtk_w32(eth, rx_dma_size, MTK_QRX_MAX_CNT_CFG(0)); ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(0), MTK_QDMA_RST_IDX); ++ ++ return 0; ++} ++ ++static void mtk_rx_clean(struct mtk_eth *eth, int ring_no) ++{ ++ struct mtk_rx_ring *ring = ð->rx_ring[ring_no]; ++ int i; ++ ++ if (ring->data && ring->dma) { ++ for (i = 0; i < ring->dma_size; i++) { ++ if (!ring->data[i]) ++ continue; ++ if (!ring->dma[i].rxd1) ++ continue; ++ dma_unmap_single(eth->dev, ++ ring->dma[i].rxd1, ++ ring->buf_size, ++ DMA_FROM_DEVICE); ++ skb_free_frag(ring->data[i]); ++ } ++ kfree(ring->data); ++ ring->data = NULL; ++ } ++ ++ if (ring->dma) { ++ dma_free_coherent(eth->dev, ++ ring->dma_size * sizeof(*ring->dma), ++ ring->dma, ++ ring->phys); ++ ring->dma = NULL; ++ } ++} ++ ++static void mtk_rx_clean_qdma(struct mtk_eth *eth) ++{ ++ struct mtk_rx_ring *ring = ð->rx_ring_qdma; + int i; + + if (ring->data && ring->dma) { +@@ -1683,7 +1755,7 @@ static int mtk_dma_init(struct mtk_eth * + if (err) + return err; + +- err = mtk_rx_alloc(eth, 0, MTK_RX_FLAGS_QDMA); ++ err = mtk_rx_alloc_qdma(eth, MTK_RX_FLAGS_NORMAL); + if (err) + return err; + +@@ -1702,6 +1774,7 @@ static int mtk_dma_init(struct mtk_eth * + return err; + } + ++ + /* Enable random early drop and set drop threshold automatically */ + mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | FC_THRES_MIN, + MTK_QDMA_FC_THRES); +@@ -1726,13 +1799,13 @@ static void mtk_dma_free(struct mtk_eth + eth->phy_scratch_ring = 0; + } + mtk_tx_clean(eth); +- mtk_rx_clean(eth, ð->rx_ring[0]); +- mtk_rx_clean(eth, ð->rx_ring_qdma); ++ mtk_rx_clean(eth, 0); ++ mtk_rx_clean_qdma(eth); + + if (eth->hwlro) { + mtk_hwlro_rx_uninit(eth); + for (i = 1; i < MTK_MAX_RX_RING_NUM; i++) +- mtk_rx_clean(eth, ð->rx_ring[i]); ++ mtk_rx_clean(eth, i); + } + + kfree(eth->scratch_head); +@@ -1947,20 +2020,14 @@ static int mtk_hw_init(struct mtk_eth *e + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); + +- /* Indicates CDM to parse the MTK special tag from CPU +- * which also is working out for untag packets. +- */ +- val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); +- mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); +- val = mtk_r32(eth, MTK_CDMP_IG_CTRL); +- mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); +- + /* Enable RX VLan Offloading */ + if (MTK_HW_FEATURES & NETIF_F_HW_VLAN_CTAG_RX) + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + else + mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); + ++ mtk_w32(eth, 0x81000001, MTK_CDMP_IG_CTRL); ++ + /* disable delay and normal interrupt */ + #ifdef MTK_IRQ_DLY + mtk_w32(eth, 0x84048404, MTK_PDMA_DELAY_INT); +@@ -1990,6 +2057,9 @@ static int mtk_hw_init(struct mtk_eth *e + /* Enable RX checksum */ + val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; + ++ if (!i) ++ val |= BIT(24); ++ + /* setup the mac dma */ + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } +@@ -2069,7 +2139,18 @@ static int mtk_do_ioctl(struct net_devic + if (reg.off > REG_HQOS_MAX) + return -EINVAL; + mtk_w32(eth, reg.val, 0x1800 + reg.off); +-// printk("write reg off:%x val:%x\n", reg.off, reg.val); ++ printk("write reg off:%x val:%x\n", reg.off, reg.val); ++ return 0; ++ ++ case RAETH_QDMA_QUEUE_MAPPING: ++ copy_from_user(®, ifr->ifr_data, sizeof(reg)); ++ if ((reg.off & 0x100) == 0x100) { ++ lan_wan_separate = 1; ++ reg.off &= 0xff; ++ } else { ++ lan_wan_separate = 0; ++ } ++ M2Q_table[reg.off] = reg.val; + return 0; + #endif + case SIOCGMIIPHY: +@@ -2288,9 +2369,9 @@ static void mtk_get_ethtool_stats(struct + return; + + if (netif_running(dev) && netif_device_present(dev)) { +- if (spin_trylock_bh(&hwstats->stats_lock)) { ++ if (spin_trylock(&hwstats->stats_lock)) { + mtk_stats_update_mac(mac); +- spin_unlock_bh(&hwstats->stats_lock); ++ spin_unlock(&hwstats->stats_lock); + } + } + +@@ -2443,7 +2524,7 @@ static int mtk_add_mac(struct mtk_eth *e + mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; + + SET_NETDEV_DEV(eth->netdev[id], eth->dev); +- eth->netdev[id]->watchdog_timeo = 30 * HZ; ++ eth->netdev[id]->watchdog_timeo = 15 * HZ; + eth->netdev[id]->netdev_ops = &mtk_netdev_ops; + eth->netdev[id]->base_addr = (unsigned long)eth->base; + +@@ -2584,15 +2665,19 @@ static int mtk_probe(struct platform_dev + goto err_deinit_hw; + } + ++ cpumask_set_cpu(1, ð->affinity_mask[1]); ++ cpumask_set_cpu(0, ð->affinity_mask[2]); + err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; ++ irq_set_affinity_hint(eth->irq[1], ð->affinity_mask[1]); + + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; ++ irq_set_affinity_hint(eth->irq[2], ð->affinity_mask[2]); + + err = mtk_mdio_init(eth); + if (err) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -80,7 +80,6 @@ + + /* CDMP Ingress Control Register */ + #define MTK_CDMP_IG_CTRL 0x400 +-#define MTK_CDMP_STAG_EN BIT(0) + + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 +@@ -91,12 +90,27 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + ++/* GDMA Ingress Control Register */ ++#define MTK_GDMA1_IG_CTRL(x) (0x500 + (x * 0x1000)) ++ + /* Unicast Filter MAC Address Register - Low */ + #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) + + /* Unicast Filter MAC Address Register - High */ + #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) + ++/* QDMA RX Base Pointer Register */ ++#define MTK_QRX_BASE_PTR0 0x1900 ++#define MTK_QRX_BASE_PTR_CFG(x) (MTK_QRX_BASE_PTR0 + (x * 0x10)) ++ ++/* QDMA RX Maximum Count Register */ ++#define MTK_QRX_MAX_CNT0 0x1904 ++#define MTK_QRX_MAX_CNT_CFG(x) (MTK_QRX_MAX_CNT0 + (x * 0x10)) ++ ++/* QDMA RX CPU Pointer Register */ ++#define MTK_QRX_CRX_IDX0 0x1908 ++#define MTK_QRX_CRX_IDX_CFG(x) (MTK_QRX_CRX_IDX0 + (x * 0x10)) ++ + /* PDMA RX Base Pointer Register */ + #define MTK_PRX_BASE_PTR0 0x900 + #define MTK_PRX_BASE_PTR_CFG(x) (MTK_PRX_BASE_PTR0 + (x * 0x10)) +@@ -240,7 +254,10 @@ + #define MTK_QDMA_INT_MASK 0x1A1C + + /* QDMA Interrupt Mask Register */ ++#define MTK_QDMA_HRED1 0x1A40 + #define MTK_QDMA_HRED2 0x1A44 ++#define MTK_QDMA_SRED1 0x1A48 ++#define MTK_QDMA_SRED2 0x1A4c + + /* QDMA TX Forward CPU Pointer Register */ + #define MTK_QTX_CTX_PTR 0x1B00 +@@ -275,6 +292,7 @@ + #define TX_DMA_TSO BIT(28) + #define TX_DMA_FPORT_SHIFT 25 + #define TX_DMA_FPORT_MASK 0x7 ++#define TX_DMA_VQID0 BIT(17) + #define TX_DMA_INS_VLAN BIT(16) + + /* QDMA descriptor txd3 */ +@@ -294,7 +312,6 @@ + + /* QDMA descriptor rxd4 */ + #define RX_DMA_L4_VALID BIT(24) +-#define RX_DMA_SP_TAG BIT(22) + #define RX_DMA_FPORT_SHIFT 19 + #define RX_DMA_FPORT_MASK 0x7 + +@@ -310,6 +327,7 @@ + + /* Mac control registers */ + #define MTK_MAC_MCR(x) (0x10100 + (x * 0x100)) ++#define MTK_MAC_MSR(x) (0x10108 + (x * 0x100)) + #define MAC_MCR_MAX_RX_1536 BIT(24) + #define MAC_MCR_IPG_CFG (BIT(18) | BIT(16)) + #define MAC_MCR_FORCE_MODE BIT(15) +@@ -495,7 +513,6 @@ struct mtk_tx_ring { + enum mtk_rx_flags { + MTK_RX_FLAGS_NORMAL = 0, + MTK_RX_FLAGS_HWLRO, +- MTK_RX_FLAGS_QDMA, + }; + + /* struct mtk_rx_ring - This struct holds info describing a RX ring +@@ -539,9 +556,9 @@ struct mtk_rx_ring { + * @pctl: The register map pointing at the range used to setup + * GMAC port drive/slew values + * @dma_refcnt: track how many netdevs are using the DMA engine +- * @tx_ring: Pointer to the memory holding info about the TX ring +- * @rx_ring: Pointer to the memory holding info about the RX ring +- * @rx_ring_qdma: Pointer to the memory holding info about the QDMA RX ring ++ * @tx_ring: Pointer to the memore holding info about the TX ring ++ * @rx_ring: Pointer to the memore holding info about the RX ring ++ * @rx_ring_qdma: Pointer to the memore holding info about the RX ring (QDMA) + * @tx_napi: The TX NAPI struct + * @rx_napi: The RX NAPI struct + * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring +@@ -563,6 +580,7 @@ struct mtk_eth { + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; + int irq[3]; ++ cpumask_t affinity_mask[3]; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +@@ -615,4 +633,6 @@ void mtk_stats_update_mac(struct mtk_mac + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + ++extern unsigned int M2Q_table[16]; ++ + #endif /* MTK_ETH_H */ diff --git a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch deleted file mode 100644 index 19be772a14..0000000000 --- a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch +++ /dev/null @@ -1,276 +0,0 @@ -From 6f5941c93bdf7649f392f1263b9068d360ceab4d Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Fri, 6 May 2016 02:55:48 +0200 -Subject: [PATCH 071/102] pwm: add pwm-mediatek - -Signed-off-by: John Crispin ---- - arch/arm/boot/dts/mt7623-evb.dts | 17 +++ - arch/arm/boot/dts/mt7623.dtsi | 22 ++++ - drivers/pwm/Kconfig | 9 ++ - drivers/pwm/Makefile | 1 + - drivers/pwm/pwm-mediatek.c | 230 ++++++++++++++++++++++++++++++++++++++ - 5 files changed, 279 insertions(+) - create mode 100644 drivers/pwm/pwm-mediatek.c - ---- a/drivers/pwm/Kconfig -+++ b/drivers/pwm/Kconfig -@@ -282,6 +282,15 @@ config PWM_MTK_DISP - To compile this driver as a module, choose M here: the module - will be called pwm-mtk-disp. - -+config PWM_MEDIATEK -+ tristate "MediaTek PWM support" -+ depends on ARCH_MEDIATEK || COMPILE_TEST -+ help -+ Generic PWM framework driver for Mediatek ARM SoC. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called pwm-mxs. -+ - config PWM_MXS - tristate "Freescale MXS PWM support" - depends on ARCH_MXS && OF ---- a/drivers/pwm/Makefile -+++ b/drivers/pwm/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o - obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o - obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o - obj-$(CONFIG_PWM_MESON) += pwm-meson.o -+obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o - obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o - obj-$(CONFIG_PWM_MXS) += pwm-mxs.o - obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o ---- /dev/null -+++ b/drivers/pwm/pwm-mediatek.c -@@ -0,0 +1,230 @@ -+/* -+ * Mediatek Pulse Width Modulator driver -+ * -+ * Copyright (C) 2015 John Crispin -+ * -+ * This file is licensed under the terms of the GNU General Public -+ * License version 2. This program is licensed "as is" without any -+ * warranty of any kind, whether express or implied. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define NUM_PWM 5 -+ -+/* PWM registers and bits definitions */ -+#define PWMCON 0x00 -+#define PWMHDUR 0x04 -+#define PWMLDUR 0x08 -+#define PWMGDUR 0x0c -+#define PWMWAVENUM 0x28 -+#define PWMDWIDTH 0x2c -+#define PWMTHRES 0x30 -+ -+/** -+ * struct mtk_pwm_chip - struct representing pwm chip -+ * -+ * @mmio_base: base address of pwm chip -+ * @chip: linux pwm chip representation -+ */ -+struct mtk_pwm_chip { -+ void __iomem *mmio_base; -+ struct pwm_chip chip; -+ struct clk *clk_top; -+ struct clk *clk_main; -+ struct clk *clk_pwm[NUM_PWM]; -+}; -+ -+static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) -+{ -+ return container_of(chip, struct mtk_pwm_chip, chip); -+} -+ -+static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, -+ unsigned long offset) -+{ -+ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset); -+} -+ -+static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, -+ unsigned int num, unsigned long offset, -+ unsigned long val) -+{ -+ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset); -+} -+ -+static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, -+ int duty_ns, int period_ns) -+{ -+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); -+ u32 resolution = 100 / 4; -+ u32 clkdiv = 0; -+ -+ resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm])); -+ -+ while (period_ns / resolution > 8191) { -+ clkdiv++; -+ resolution *= 2; -+ } -+ -+ if (clkdiv > 7) -+ return -1; -+ -+ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv); -+ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); -+ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); -+ return 0; -+} -+ -+static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); -+ u32 val; -+ int ret; -+ -+ ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]); -+ if (ret < 0) -+ return ret; -+ -+ val = ioread32(pc->mmio_base); -+ val |= BIT(pwm->hwpwm); -+ iowrite32(val, pc->mmio_base); -+ -+ return 0; -+} -+ -+static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); -+ u32 val; -+ -+ val = ioread32(pc->mmio_base); -+ val &= ~BIT(pwm->hwpwm); -+ iowrite32(val, pc->mmio_base); -+ clk_unprepare(pc->clk_pwm[pwm->hwpwm]); -+} -+ -+static const struct pwm_ops mtk_pwm_ops = { -+ .config = mtk_pwm_config, -+ .enable = mtk_pwm_enable, -+ .disable = mtk_pwm_disable, -+ .owner = THIS_MODULE, -+}; -+ -+static int mtk_pwm_probe(struct platform_device *pdev) -+{ -+ struct mtk_pwm_chip *pc; -+ struct resource *r; -+ int ret; -+ -+ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); -+ if (!pc) -+ return -ENOMEM; -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); -+ if (IS_ERR(pc->mmio_base)) -+ return PTR_ERR(pc->mmio_base); -+ -+ pc->clk_main = devm_clk_get(&pdev->dev, "main"); -+ if (IS_ERR(pc->clk_main)) -+ return PTR_ERR(pc->clk_main); -+ -+ pc->clk_top = devm_clk_get(&pdev->dev, "top"); -+ if (IS_ERR(pc->clk_top)) -+ return PTR_ERR(pc->clk_top); -+ -+ pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1"); -+ if (IS_ERR(pc->clk_pwm[0])) -+ return PTR_ERR(pc->clk_pwm[0]); -+ -+ pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2"); -+ if (IS_ERR(pc->clk_pwm[1])) -+ return PTR_ERR(pc->clk_pwm[1]); -+ -+ pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3"); -+ if (IS_ERR(pc->clk_pwm[2])) -+ return PTR_ERR(pc->clk_pwm[2]); -+ -+ pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4"); -+ if (IS_ERR(pc->clk_pwm[3])) -+ return PTR_ERR(pc->clk_pwm[3]); -+ -+ pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5"); -+ if (IS_ERR(pc->clk_pwm[4])) -+ return PTR_ERR(pc->clk_pwm[4]); -+ -+ ret = clk_prepare(pc->clk_top); -+ if (ret < 0) -+ return ret; -+ -+ ret = clk_prepare(pc->clk_main); -+ if (ret < 0) -+ goto disable_clk_top; -+ -+ platform_set_drvdata(pdev, pc); -+ -+ pc->chip.dev = &pdev->dev; -+ pc->chip.ops = &mtk_pwm_ops; -+ pc->chip.base = -1; -+ pc->chip.npwm = NUM_PWM; -+ -+ ret = pwmchip_add(&pc->chip); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); -+ goto disable_clk_main; -+ } -+ -+ return 0; -+ -+disable_clk_main: -+ clk_unprepare(pc->clk_main); -+disable_clk_top: -+ clk_unprepare(pc->clk_top); -+ -+ return ret; -+} -+ -+static int mtk_pwm_remove(struct platform_device *pdev) -+{ -+ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); -+ int i; -+ -+ for (i = 0; i < NUM_PWM; i++) -+ pwm_disable(&pc->chip.pwms[i]); -+ -+ return pwmchip_remove(&pc->chip); -+} -+ -+static const struct of_device_id mtk_pwm_of_match[] = { -+ { .compatible = "mediatek,mt7623-pwm" }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); -+ -+static struct platform_driver mtk_pwm_driver = { -+ .driver = { -+ .name = "mtk-pwm", -+ .owner = THIS_MODULE, -+ .of_match_table = mtk_pwm_of_match, -+ }, -+ .probe = mtk_pwm_probe, -+ .remove = mtk_pwm_remove, -+}; -+ -+module_platform_driver(mtk_pwm_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin "); -+MODULE_ALIAS("platform:mtk-pwm"); diff --git a/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch deleted file mode 100644 index f743e10243..0000000000 --- a/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch +++ /dev/null @@ -1,41 +0,0 @@ -From patchwork Fri Feb 24 18:47:21 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v4,4/4] mfd: mt6397: Add MT6323 LED support into MT6397 driver -From: sean.wang@mediatek.com -X-Patchwork-Id: 9591021 -Message-Id: <1487962041-6548-5-git-send-email-sean.wang@mediatek.com> -To: , , , - , , , - -Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, - Sean Wang , linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, - linux-arm-kernel@lists.infradead.org -Date: Sat, 25 Feb 2017 02:47:21 +0800 - -From: Sean Wang - -Add compatible string as "mt6323-led" that will make -the OF core spawn child devices for the LED subnode -of that MT6323 MFD device. - -Signed-off-by: Sean Wang ---- - drivers/mfd/mt6397-core.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/mfd/mt6397-core.c -+++ b/drivers/mfd/mt6397-core.c -@@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs - .name = "mt6323-regulator", - .of_compatible = "mediatek,mt6323-regulator" - }, -+ { -+ .name = "mt6323-led", -+ .of_compatible = "mediatek,mt6323-led" -+ }, - }; - - static const struct mfd_cell mt6397_devs[] = { diff --git a/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch deleted file mode 100644 index dee31cdc8b..0000000000 --- a/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch +++ /dev/null @@ -1,91 +0,0 @@ -From patchwork Mon Mar 20 06:47:24 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6,1/4] dt-bindings: leds: Add document bindings for leds-mt6323 -From: sean.wang@mediatek.com -X-Patchwork-Id: 9633073 -Message-Id: <1489992447-13007-2-git-send-email-sean.wang@mediatek.com> -To: , , , - , , , - -Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, - Sean Wang , linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, - linux-arm-kernel@lists.infradead.org -Date: Mon, 20 Mar 2017 14:47:24 +0800 - -From: Sean Wang - -This patch adds documentation for devicetree bindings for LED support on -MT6323 PMIC. - -Signed-off-by: Sean Wang ---- - .../devicetree/bindings/leds/leds-mt6323.txt | 60 ++++++++++++++++++++++ - 1 file changed, 60 insertions(+) - create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt -@@ -0,0 +1,60 @@ -+Device Tree Bindings for LED support on MT6323 PMIC -+ -+MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED -+controllers are defined as the subnode of the function node provided by MT6323 -+PMIC controller that is being defined as one kind of Muti-Function Device (MFD) -+using shared bus called PMIC wrapper for each subfunction to access remote -+MT6323 PMIC hardware. -+ -+For MT6323 MFD bindings see: -+Documentation/devicetree/bindings/mfd/mt6397.txt -+For MediaTek PMIC wrapper bindings see: -+Documentation/devicetree/bindings/soc/mediatek/pwrap.txt -+ -+Required properties: -+- compatible : Must be "mediatek,mt6323-led" -+- address-cells : Must be 1 -+- size-cells : Must be 0 -+ -+Each led is represented as a child node of the mediatek,mt6323-led that -+describes the initial behavior for each LED physically and currently only four -+LED child nodes can be supported. -+ -+Required properties for the LED child node: -+- reg : LED channel number (0..3) -+ -+Optional properties for the LED child node: -+- label : See Documentation/devicetree/bindings/leds/common.txt -+- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt -+- default-state: See Documentation/devicetree/bindings/leds/common.txt -+ -+Example: -+ -+ mt6323: pmic { -+ compatible = "mediatek,mt6323"; -+ -+ ... -+ -+ mt6323led: leds { -+ compatible = "mediatek,mt6323-led"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ led@0 { -+ reg = <0>; -+ label = "LED0"; -+ linux,default-trigger = "timer"; -+ default-state = "on"; -+ }; -+ led@1 { -+ reg = <1>; -+ label = "LED1"; -+ default-state = "off"; -+ }; -+ led@2 { -+ reg = <2>; -+ label = "LED2"; -+ default-state = "on"; -+ }; -+ }; -+ }; diff --git a/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch deleted file mode 100644 index 2edb4ba23d..0000000000 --- a/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch +++ /dev/null @@ -1,38 +0,0 @@ -From patchwork Mon Mar 20 06:47:25 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6, - 2/4] dt-bindings: mfd: Add the description for LED as the sub module -From: sean.wang@mediatek.com -X-Patchwork-Id: 9633089 -Message-Id: <1489992447-13007-3-git-send-email-sean.wang@mediatek.com> -To: , , , - , , , - -Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, - Sean Wang , linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, - linux-arm-kernel@lists.infradead.org -Date: Mon, 20 Mar 2017 14:47:25 +0800 - -From: Sean Wang - -This patch adds description for LED as the sub-module on MT6397/MT6323 -multifunction device. - -Signed-off-by: Sean Wang ---- - Documentation/devicetree/bindings/mfd/mt6397.txt | 1 + - 1 file changed, 1 insertion(+) - ---- a/Documentation/devicetree/bindings/mfd/mt6397.txt -+++ b/Documentation/devicetree/bindings/mfd/mt6397.txt -@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device - - Audio codec - - GPIO - - Clock -+- LED - - It is interfaced to host controller using SPI interface by a proprietary hardware - called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap. diff --git a/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch deleted file mode 100644 index f0d706cd44..0000000000 --- a/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch +++ /dev/null @@ -1,554 +0,0 @@ -From patchwork Mon Mar 20 06:47:26 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6,3/4] leds: Add LED support for MT6323 PMIC -From: sean.wang@mediatek.com -X-Patchwork-Id: 9633081 -Message-Id: <1489992447-13007-4-git-send-email-sean.wang@mediatek.com> -To: , , , - , , , - -Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, - Sean Wang , linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, - linux-arm-kernel@lists.infradead.org -Date: Mon, 20 Mar 2017 14:47:26 +0800 - -From: Sean Wang - -MT6323 PMIC is a multi-function device that includes LED function. -It allows attaching up to 4 LEDs which can either be on, off or dimmed -and/or blinked with the controller. - -Signed-off-by: Sean Wang -Reviewed-by: Jacek Anaszewski ---- - drivers/leds/Kconfig | 8 + - drivers/leds/Makefile | 1 + - drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 511 insertions(+) - create mode 100644 drivers/leds/leds-mt6323.c - ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532 - This option enables support for the so called "User LED" of - Mikrotik's Routerboard 532. - -+config LEDS_MT6323 -+ tristate "LED Support for Mediatek MT6323 PMIC" -+ depends on LEDS_CLASS -+ depends on MFD_MT6397 -+ help -+ This option enables support for on-chip LED drivers found on -+ Mediatek MT6323 PMIC. -+ - config LEDS_S3C24XX - tristate "LED Support for Samsung S3C24XX GPIO LEDs" - depends on LEDS_CLASS ---- /dev/null -+++ b/drivers/leds/leds-mt6323.c -@@ -0,0 +1,502 @@ -+/* -+ * LED driver for Mediatek MT6323 PMIC -+ * -+ * Copyright (C) 2017 Sean Wang -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation; either version 2 of -+ * the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * Register field for MT6323_TOP_CKPDN0 to enable -+ * 32K clock common for LED device. -+ */ -+#define MT6323_RG_DRV_32K_CK_PDN BIT(11) -+#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11) -+ -+/* -+ * Register field for MT6323_TOP_CKPDN2 to enable -+ * individual clock for LED device. -+ */ -+#define MT6323_RG_ISINK_CK_PDN(i) BIT(i) -+#define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i) -+ -+/* -+ * Register field for MT6323_TOP_CKCON1 to select -+ * clock source. -+ */ -+#define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) -+ -+/* -+ * Register for MT6323_ISINK_CON0 to setup the -+ * duty cycle of the blink. -+ */ -+#define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i)) -+#define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8) -+#define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \ -+ MT6323_ISINK_DIM_DUTY_MASK) -+ -+/* Register to setup the period of the blink. */ -+#define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i)) -+#define MT6323_ISINK_DIM_FSEL_MASK (0xffff) -+#define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK) -+ -+/* Register to control the brightness. */ -+#define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i)) -+#define MT6323_ISINK_CH_STEP_SHIFT 12 -+#define MT6323_ISINK_CH_STEP_MASK (0x7 << 12) -+#define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \ -+ MT6323_ISINK_CH_STEP_MASK) -+#define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1) -+#define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \ -+ MT6323_ISINK_SFSTR0_TC_MASK) -+#define MT6323_ISINK_SFSTR0_EN_MASK BIT(0) -+#define MT6323_ISINK_SFSTR0_EN BIT(0) -+ -+/* Register to LED channel enablement. */ -+#define MT6323_ISINK_CH_EN_MASK(i) BIT(i) -+#define MT6323_ISINK_CH_EN(i) BIT(i) -+ -+#define MT6323_MAX_PERIOD 10000 -+#define MT6323_MAX_LEDS 4 -+#define MT6323_MAX_BRIGHTNESS 6 -+#define MT6323_UNIT_DUTY 3125 -+#define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\ -+ (p) * MT6323_UNIT_DUTY) -+ -+struct mt6323_leds; -+ -+/** -+ * struct mt6323_led - state container for the LED device -+ * @id: the identifier in MT6323 LED device -+ * @parent: the pointer to MT6323 LED controller -+ * @cdev: LED class device for this LED device -+ * @current_brightness: current state of the LED device -+ */ -+struct mt6323_led { -+ int id; -+ struct mt6323_leds *parent; -+ struct led_classdev cdev; -+ enum led_brightness current_brightness; -+}; -+ -+/** -+ * struct mt6323_leds - state container for holding LED controller -+ * of the driver -+ * @dev: the device pointer -+ * @hw: the underlying hardware providing shared -+ * bus for the register operations -+ * @lock: the lock among process context -+ * @led: the array that contains the state of individual -+ * LED device -+ */ -+struct mt6323_leds { -+ struct device *dev; -+ struct mt6397_chip *hw; -+ /* protect among process context */ -+ struct mutex lock; -+ struct mt6323_led *led[MT6323_MAX_LEDS]; -+}; -+ -+static int mt6323_led_hw_brightness(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ struct regmap *regmap = leds->hw->regmap; -+ u32 con2_mask = 0, con2_val = 0; -+ int ret; -+ -+ /* -+ * Setup current output for the corresponding -+ * brightness level. -+ */ -+ con2_mask |= MT6323_ISINK_CH_STEP_MASK | -+ MT6323_ISINK_SFSTR0_TC_MASK | -+ MT6323_ISINK_SFSTR0_EN_MASK; -+ con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) | -+ MT6323_ISINK_SFSTR0_TC(2) | -+ MT6323_ISINK_SFSTR0_EN; -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id), -+ con2_mask, con2_val); -+ return ret; -+} -+ -+static int mt6323_led_hw_off(struct led_classdev *cdev) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ struct regmap *regmap = leds->hw->regmap; -+ unsigned int status; -+ int ret; -+ -+ status = MT6323_ISINK_CH_EN(led->id); -+ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, -+ MT6323_ISINK_CH_EN_MASK(led->id), ~status); -+ if (ret < 0) -+ return ret; -+ -+ usleep_range(100, 300); -+ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, -+ MT6323_RG_ISINK_CK_PDN_MASK(led->id), -+ MT6323_RG_ISINK_CK_PDN(led->id)); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static enum led_brightness -+mt6323_get_led_hw_brightness(struct led_classdev *cdev) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ struct regmap *regmap = leds->hw->regmap; -+ unsigned int status; -+ int ret; -+ -+ ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status); -+ if (ret < 0) -+ return ret; -+ -+ if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id)) -+ return 0; -+ -+ ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status); -+ if (ret < 0) -+ return ret; -+ -+ if (!(status & MT6323_ISINK_CH_EN(led->id))) -+ return 0; -+ -+ ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status); -+ if (ret < 0) -+ return ret; -+ -+ return ((status & MT6323_ISINK_CH_STEP_MASK) -+ >> MT6323_ISINK_CH_STEP_SHIFT) + 1; -+} -+ -+static int mt6323_led_hw_on(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ struct regmap *regmap = leds->hw->regmap; -+ unsigned int status; -+ int ret; -+ -+ /* -+ * Setup required clock source, enable the corresponding -+ * clock and channel and let work with continuous blink as -+ * the default. -+ */ -+ ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1, -+ MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0); -+ if (ret < 0) -+ return ret; -+ -+ status = MT6323_RG_ISINK_CK_PDN(led->id); -+ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, -+ MT6323_RG_ISINK_CK_PDN_MASK(led->id), -+ ~status); -+ if (ret < 0) -+ return ret; -+ -+ usleep_range(100, 300); -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, -+ MT6323_ISINK_CH_EN_MASK(led->id), -+ MT6323_ISINK_CH_EN(led->id)); -+ if (ret < 0) -+ return ret; -+ -+ ret = mt6323_led_hw_brightness(cdev, brightness); -+ if (ret < 0) -+ return ret; -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), -+ MT6323_ISINK_DIM_DUTY_MASK, -+ MT6323_ISINK_DIM_DUTY(31)); -+ if (ret < 0) -+ return ret; -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), -+ MT6323_ISINK_DIM_FSEL_MASK, -+ MT6323_ISINK_DIM_FSEL(1000)); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static int mt6323_led_set_blink(struct led_classdev *cdev, -+ unsigned long *delay_on, -+ unsigned long *delay_off) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ struct regmap *regmap = leds->hw->regmap; -+ unsigned long period; -+ u8 duty_hw; -+ int ret; -+ -+ /* -+ * Units are in ms, if over the hardware able -+ * to support, fallback into software blink -+ */ -+ period = *delay_on + *delay_off; -+ -+ if (period > MT6323_MAX_PERIOD) -+ return -EINVAL; -+ -+ /* -+ * LED subsystem requires a default user -+ * friendly blink pattern for the LED so using -+ * 1Hz duty cycle 50% here if without specific -+ * value delay_on and delay off being assigned. -+ */ -+ if (!*delay_on && !*delay_off) { -+ *delay_on = 500; -+ *delay_off = 500; -+ } -+ -+ /* -+ * Calculate duty_hw based on the percentage of period during -+ * which the led is ON. -+ */ -+ duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); -+ -+ /* hardware doesn't support zero duty cycle. */ -+ if (!duty_hw) -+ return -EINVAL; -+ -+ mutex_lock(&leds->lock); -+ /* -+ * Set max_brightness as the software blink behavior -+ * when no blink brightness. -+ */ -+ if (!led->current_brightness) { -+ ret = mt6323_led_hw_on(cdev, cdev->max_brightness); -+ if (ret < 0) -+ goto out; -+ led->current_brightness = cdev->max_brightness; -+ } -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), -+ MT6323_ISINK_DIM_DUTY_MASK, -+ MT6323_ISINK_DIM_DUTY(duty_hw - 1)); -+ if (ret < 0) -+ goto out; -+ -+ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), -+ MT6323_ISINK_DIM_FSEL_MASK, -+ MT6323_ISINK_DIM_FSEL(period - 1)); -+out: -+ mutex_unlock(&leds->lock); -+ -+ return ret; -+} -+ -+static int mt6323_led_set_brightness(struct led_classdev *cdev, -+ enum led_brightness brightness) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ struct mt6323_leds *leds = led->parent; -+ int ret; -+ -+ mutex_lock(&leds->lock); -+ -+ if (!led->current_brightness && brightness) { -+ ret = mt6323_led_hw_on(cdev, brightness); -+ if (ret < 0) -+ goto out; -+ } else if (brightness) { -+ ret = mt6323_led_hw_brightness(cdev, brightness); -+ if (ret < 0) -+ goto out; -+ } else { -+ ret = mt6323_led_hw_off(cdev); -+ if (ret < 0) -+ goto out; -+ } -+ -+ led->current_brightness = brightness; -+out: -+ mutex_unlock(&leds->lock); -+ -+ return ret; -+} -+ -+static int mt6323_led_set_dt_default(struct led_classdev *cdev, -+ struct device_node *np) -+{ -+ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); -+ const char *state; -+ int ret = 0; -+ -+ led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; -+ led->cdev.default_trigger = of_get_property(np, -+ "linux,default-trigger", -+ NULL); -+ -+ state = of_get_property(np, "default-state", NULL); -+ if (state) { -+ if (!strcmp(state, "keep")) { -+ ret = mt6323_get_led_hw_brightness(cdev); -+ if (ret < 0) -+ return ret; -+ led->current_brightness = ret; -+ ret = 0; -+ } else if (!strcmp(state, "on")) { -+ ret = -+ mt6323_led_set_brightness(cdev, cdev->max_brightness); -+ } else { -+ ret = mt6323_led_set_brightness(cdev, LED_OFF); -+ } -+ } -+ -+ return ret; -+} -+ -+static int mt6323_led_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *child; -+ struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); -+ struct mt6323_leds *leds; -+ struct mt6323_led *led; -+ int ret; -+ unsigned int status; -+ u32 reg; -+ -+ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); -+ if (!leds) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, leds); -+ leds->dev = dev; -+ -+ /* -+ * leds->hw points to the underlying bus for the register -+ * controlled. -+ */ -+ leds->hw = hw; -+ mutex_init(&leds->lock); -+ -+ status = MT6323_RG_DRV_32K_CK_PDN; -+ ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, -+ MT6323_RG_DRV_32K_CK_PDN_MASK, ~status); -+ if (ret < 0) { -+ dev_err(leds->dev, -+ "Failed to update MT6323_TOP_CKPDN0 Register\n"); -+ return ret; -+ } -+ -+ for_each_available_child_of_node(np, child) { -+ ret = of_property_read_u32(child, "reg", ®); -+ if (ret) { -+ dev_err(dev, "Failed to read led 'reg' property\n"); -+ goto put_child_node; -+ } -+ -+ if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) { -+ dev_err(dev, "Invalid led reg %u\n", reg); -+ ret = -EINVAL; -+ goto put_child_node; -+ } -+ -+ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); -+ if (!led) { -+ ret = -ENOMEM; -+ goto put_child_node; -+ } -+ -+ leds->led[reg] = led; -+ leds->led[reg]->id = reg; -+ leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS; -+ leds->led[reg]->cdev.brightness_set_blocking = -+ mt6323_led_set_brightness; -+ leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; -+ leds->led[reg]->cdev.brightness_get = -+ mt6323_get_led_hw_brightness; -+ leds->led[reg]->parent = leds; -+ -+ ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child); -+ if (ret < 0) { -+ dev_err(leds->dev, -+ "Failed to LED set default from devicetree\n"); -+ goto put_child_node; -+ } -+ -+ ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to register LED: %d\n", -+ ret); -+ goto put_child_node; -+ } -+ leds->led[reg]->cdev.dev->of_node = child; -+ } -+ -+ return 0; -+ -+put_child_node: -+ of_node_put(child); -+ return ret; -+} -+ -+static int mt6323_led_remove(struct platform_device *pdev) -+{ -+ struct mt6323_leds *leds = platform_get_drvdata(pdev); -+ int i; -+ -+ /* Turn the LEDs off on driver removal. */ -+ for (i = 0 ; leds->led[i] ; i++) -+ mt6323_led_hw_off(&leds->led[i]->cdev); -+ -+ regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, -+ MT6323_RG_DRV_32K_CK_PDN_MASK, -+ MT6323_RG_DRV_32K_CK_PDN); -+ -+ mutex_destroy(&leds->lock); -+ -+ return 0; -+} -+ -+static const struct of_device_id mt6323_led_dt_match[] = { -+ { .compatible = "mediatek,mt6323-led" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mt6323_led_dt_match); -+ -+static struct platform_driver mt6323_led_driver = { -+ .probe = mt6323_led_probe, -+ .remove = mt6323_led_remove, -+ .driver = { -+ .name = "mt6323-led", -+ .of_match_table = mt6323_led_dt_match, -+ }, -+}; -+ -+module_platform_driver(mt6323_led_driver); -+ -+MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC"); -+MODULE_AUTHOR("Sean Wang "); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch deleted file mode 100644 index 888218bbdc..0000000000 --- a/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch +++ /dev/null @@ -1,42 +0,0 @@ -From patchwork Mon Mar 20 06:47:27 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [v6, - 4/4] mfd: mt6397: Align the placement at which the mfd_cell of LED is - defined -From: sean.wang@mediatek.com -X-Patchwork-Id: 9633079 -Message-Id: <1489992447-13007-5-git-send-email-sean.wang@mediatek.com> -To: , , , - , , , - -Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, - Sean Wang , linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, - linux-arm-kernel@lists.infradead.org -Date: Mon, 20 Mar 2017 14:47:27 +0800 - -From: Sean Wang - -Align the placement as which the mfd_cell of LED is defined as the other -members done on the structure. - -Signed-off-by: Sean Wang -Acked-by: Lee Jones ---- - drivers/mfd/mt6397-core.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/mfd/mt6397-core.c -+++ b/drivers/mfd/mt6397-core.c -@@ -47,8 +47,7 @@ static const struct mfd_cell mt6323_devs - { - .name = "mt6323-regulator", - .of_compatible = "mediatek,mt6323-regulator" -- }, -- { -+ }, { - .name = "mt6323-led", - .of_compatible = "mediatek,mt6323-led" - }, diff --git a/target/linux/mediatek/patches-4.9/0091-dsa1.patch b/target/linux/mediatek/patches-4.9/0091-dsa1.patch deleted file mode 100644 index ffc63dcc7c..0000000000 --- a/target/linux/mediatek/patches-4.9/0091-dsa1.patch +++ /dev/null @@ -1,124 +0,0 @@ -From patchwork Wed Mar 29 09:38:19 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [net-next,v3,1/5] dt-bindings: net: dsa: add Mediatek MT7530 binding -From: sean.wang@mediatek.com -X-Patchwork-Id: 9651093 -Message-Id: <1490780303-18598-2-git-send-email-sean.wang@mediatek.com> -To: , , - , , - , -Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, - netdev@vger.kernel.org, sean.wang@mediatek.com, - linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net -Date: Wed, 29 Mar 2017 17:38:19 +0800 - -From: Sean Wang - -Add device-tree binding for Mediatek MT7530 switch. - -Cc: devicetree@vger.kernel.org -Signed-off-by: Sean Wang -Acked-by: Rob Herring ---- - .../devicetree/bindings/net/dsa/mt7530.txt | 92 ++++++++++++++++++++++ - 1 file changed, 92 insertions(+) - create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt -@@ -0,0 +1,92 @@ -+Mediatek MT7530 Ethernet switch -+================================ -+ -+Required properties: -+ -+- compatible: Must be compatible = "mediatek,mt7530"; -+- #address-cells: Must be 1. -+- #size-cells: Must be 0. -+- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part -+ on multi-chip module belong to MT7623A has or the remotely standalone -+ chip as the function MT7623N reference board provided for. -+- core-supply: Phandle to the regulator node necessary for the core power. -+- io-supply: Phandle to the regulator node necessary for the I/O power. -+ See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt -+ for details for the regulator setup on these boards. -+ -+If the property mediatek,mcm isn't defined, following property is required -+ -+- reset-gpios: Should be a gpio specifier for a reset line. -+ -+Else, following properties are required -+ -+- resets : Phandle pointing to the system reset controller with -+ line index for the ethsys. -+- reset-names : Should be set to "mcm". -+ -+Required properties for the child nodes within ports container: -+ -+- reg: Port address described must be 6 for CPU port and from 0 to 5 for -+ user ports. -+- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled -+ "cpu". -+ -+See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional -+required, optional properties and how the integrated switch subnodes must -+be specified. -+ -+Example: -+ -+ &mdio0 { -+ switch@0 { -+ compatible = "mediatek,mt7530"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0>; -+ -+ core-supply = <&mt6323_vpa_reg>; -+ io-supply = <&mt6323_vemc3v3_reg>; -+ reset-gpios = <&pio 33 0>; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reg = <0>; -+ port@0 { -+ reg = <0>; -+ label = "lan0"; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ label = "lan1"; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ label = "lan2"; -+ }; -+ -+ port@3 { -+ reg = <3>; -+ label = "lan3"; -+ }; -+ -+ port@4 { -+ reg = <4>; -+ label = "wan"; -+ }; -+ -+ port@6 { -+ reg = <6>; -+ label = "cpu"; -+ ethernet = <&gmac0>; -+ phy-mode = "trgmii"; -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ }; -+ }; diff --git a/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch deleted file mode 100644 index 6e65d27359..0000000000 --- a/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Sat, 23 Apr 2016 11:57:21 +0200 -Subject: [PATCH 081/102] net-next: mediatek: fix DQL support - -The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The -current code will assign the TX traffic of each MAC to its own DQL. This -results in the amount of data, that DQL says is in the queue incorrect. As -the data from multiple devices is infact enqueued. This makes any decision -based on these value non deterministic. Fix this by tracking all TX -traffic, regardless of the MAC it belongs to in the DQL of all devices -using the DMA. - -Signed-off-by: John Crispin ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++++----------- - 1 file changed, 20 insertions(+), 13 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -706,7 +706,16 @@ static int mtk_tx_map(struct sk_buff *sk - WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | - (!nr_frags * TX_DMA_LS0))); - -- netdev_sent_queue(dev, skb->len); -+ /* we have a single DMA ring so BQL needs to be updated for all devices -+ * sitting on this ring -+ */ -+ for (i = 0; i < MTK_MAC_COUNT; i++) { -+ if (!eth->netdev[i]) -+ continue; -+ -+ netdev_sent_queue(eth->netdev[i], skb->len); -+ } -+ - skb_tx_timestamp(skb); - - ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); -@@ -998,21 +1007,18 @@ static int mtk_poll_tx(struct mtk_eth *e - struct mtk_tx_dma *desc; - struct sk_buff *skb; - struct mtk_tx_buf *tx_buf; -- unsigned int done[MTK_MAX_DEVS]; -- unsigned int bytes[MTK_MAX_DEVS]; -+ int total = 0, done = 0; -+ unsigned int bytes = 0; - u32 cpu, dma; - static int condition; -- int total = 0, i; -- -- memset(done, 0, sizeof(done)); -- memset(bytes, 0, sizeof(bytes)); -+ int i; - - cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); - dma = mtk_r32(eth, MTK_QTX_DRX_PTR); - - desc = mtk_qdma_phys_to_virt(ring, cpu); - -- while ((cpu != dma) && budget) { -+ while ((cpu != dma) && done < budget) { - u32 next_cpu = desc->txd2; - int mac; - -@@ -1032,9 +1038,8 @@ static int mtk_poll_tx(struct mtk_eth *e - } - - if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { -- bytes[mac] += skb->len; -- done[mac]++; -- budget--; -+ bytes += skb->len; -+ done++; - } - mtk_tx_unmap(eth, tx_buf); - -@@ -1046,11 +1051,13 @@ static int mtk_poll_tx(struct mtk_eth *e - - mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); - -+ /* we have a single DMA ring so BQL needs to be updated for all devices -+ * sitting on this ring -+ */ - for (i = 0; i < MTK_MAC_COUNT; i++) { -- if (!eth->netdev[i] || !done[i]) -+ if (!eth->netdev[i]) - continue; -- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); -- total += done[i]; -+ netdev_completed_queue(eth->netdev[i], done, bytes); - } - - if (mtk_queue_stopped(eth) && diff --git a/target/linux/mediatek/patches-4.9/0092-dsa2.patch b/target/linux/mediatek/patches-4.9/0092-dsa2.patch deleted file mode 100644 index a5b4242eb6..0000000000 --- a/target/linux/mediatek/patches-4.9/0092-dsa2.patch +++ /dev/null @@ -1,206 +0,0 @@ -From patchwork Wed Mar 29 09:38:20 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [net-next,v3,2/5] net-next: dsa: add Mediatek tag RX/TX handler -From: sean.wang@mediatek.com -X-Patchwork-Id: 9651099 -Message-Id: <1490780303-18598-3-git-send-email-sean.wang@mediatek.com> -To: , , - , , - , -Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, - netdev@vger.kernel.org, sean.wang@mediatek.com, - linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net -Date: Wed, 29 Mar 2017 17:38:20 +0800 - -From: Sean Wang - -Add the support for the 4-bytes tag for DSA port distinguishing inserted -allowing receiving and transmitting the packet via the particular port. -The tag is being added after the source MAC address in the ethernet -header. - -Signed-off-by: Sean Wang -Signed-off-by: Landen Chao -Reviewed-by: Andrew Lunn -Reviewed-by: Florian Fainelli ---- - include/net/dsa.h | 1 + - net/dsa/Kconfig | 2 + - net/dsa/Makefile | 1 + - net/dsa/dsa.c | 3 ++ - net/dsa/dsa_priv.h | 3 ++ - net/dsa/tag_mtk.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 127 insertions(+) - create mode 100644 net/dsa/tag_mtk.c - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -27,6 +27,7 @@ enum dsa_tag_protocol { - DSA_TAG_PROTO_EDSA, - DSA_TAG_PROTO_BRCM, - DSA_TAG_PROTO_QCA, -+ DSA_TAG_PROTO_MTK, - DSA_TAG_LAST, /* MUST BE LAST */ - }; - ---- a/net/dsa/Kconfig -+++ b/net/dsa/Kconfig -@@ -41,4 +41,6 @@ config NET_DSA_TAG_TRAILER - config NET_DSA_TAG_QCA - bool - -+config NET_DSA_TAG_MTK -+ bool - endif ---- a/net/dsa/Makefile -+++ b/net/dsa/Makefile -@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += ta - dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o - dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o - dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o -+dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o ---- a/net/dsa/dsa.c -+++ b/net/dsa/dsa.c -@@ -57,6 +57,9 @@ const struct dsa_device_ops *dsa_device_ - #ifdef CONFIG_NET_DSA_TAG_QCA - [DSA_TAG_PROTO_QCA] = &qca_netdev_ops, - #endif -+#ifdef CONFIG_NET_DSA_TAG_MTK -+ [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops, -+#endif - [DSA_TAG_PROTO_NONE] = &none_ops, - }; - ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -84,4 +84,7 @@ extern const struct dsa_device_ops brcm_ - /* tag_qca.c */ - extern const struct dsa_device_ops qca_netdev_ops; - -+/* tag_mtk.c */ -+extern const struct dsa_device_ops mtk_netdev_ops; -+ - #endif ---- /dev/null -+++ b/net/dsa/tag_mtk.c -@@ -0,0 +1,117 @@ -+/* -+ * Mediatek DSA Tag support -+ * Copyright (C) 2017 Landen Chao -+ * Sean Wang -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 and -+ * only version 2 as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include "dsa_priv.h" -+ -+#define MTK_HDR_LEN 4 -+#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) -+#define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0) -+ -+static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, -+ struct net_device *dev) -+{ -+ struct dsa_slave_priv *p = netdev_priv(dev); -+ u8 *mtk_tag; -+ -+ if (skb_cow_head(skb, MTK_HDR_LEN) < 0) -+ goto out_free; -+ -+ skb_push(skb, MTK_HDR_LEN); -+ -+ memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN); -+ -+ /* Build the tag after the MAC Source Address */ -+ mtk_tag = skb->data + 2 * ETH_ALEN; -+ mtk_tag[0] = 0; -+ mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; -+ mtk_tag[2] = 0; -+ mtk_tag[3] = 0; -+ -+ return skb; -+ -+out_free: -+ kfree_skb(skb); -+ return NULL; -+} -+ -+static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, -+ struct packet_type *pt, struct net_device *orig_dev) -+{ -+ struct dsa_switch_tree *dst = dev->dsa_ptr; -+ struct dsa_switch *ds; -+ int port; -+ __be16 *phdr, hdr; -+ -+ if (unlikely(!dst)) -+ goto out_drop; -+ -+ skb = skb_unshare(skb, GFP_ATOMIC); -+ if (!skb) -+ goto out; -+ -+ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) -+ goto out_drop; -+ -+ /* The MTK header is added by the switch between src addr -+ * and ethertype at this point, skb->data points to 2 bytes -+ * after src addr so header should be 2 bytes right before. -+ */ -+ phdr = (__be16 *)(skb->data - 2); -+ hdr = ntohs(*phdr); -+ -+ /* Remove MTK tag and recalculate checksum. */ -+ skb_pull_rcsum(skb, MTK_HDR_LEN); -+ -+ memmove(skb->data - ETH_HLEN, -+ skb->data - ETH_HLEN - MTK_HDR_LEN, -+ 2 * ETH_ALEN); -+ -+ /* This protocol doesn't support cascading multiple -+ * switches so it's safe to assume the switch is first -+ * in the tree. -+ */ -+ ds = dst->ds[0]; -+ if (!ds) -+ goto out_drop; -+ -+ /* Get source port information */ -+ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); -+ if (!ds->ports[port].netdev) -+ goto out_drop; -+ -+ /* Update skb & forward the frame accordingly */ -+ skb_push(skb, ETH_HLEN); -+ -+ skb->pkt_type = PACKET_HOST; -+ skb->dev = ds->ports[port].netdev; -+ skb->protocol = eth_type_trans(skb, skb->dev); -+ -+ skb->dev->stats.rx_packets++; -+ skb->dev->stats.rx_bytes += skb->len; -+ -+ netif_receive_skb(skb); -+ -+ return 0; -+ -+out_drop: -+ kfree_skb(skb); -+out: -+ return 0; -+} -+ -+const struct dsa_device_ops mtk_netdev_ops = { -+ .xmit = mtk_tag_xmit, -+ .rcv = mtk_tag_rcv, -+}; diff --git a/target/linux/mediatek/patches-4.9/0092-dsa3.patch b/target/linux/mediatek/patches-4.9/0092-dsa3.patch deleted file mode 100644 index 385add1e3a..0000000000 --- a/target/linux/mediatek/patches-4.9/0092-dsa3.patch +++ /dev/null @@ -1,63 +0,0 @@ -From patchwork Wed Mar 29 09:38:21 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [net-next, v3, - 3/5] net-next: ethernet: mediatek: add CDM able to recognize the tag - for DSA -From: sean.wang@mediatek.com -X-Patchwork-Id: 9651091 -Message-Id: <1490780303-18598-4-git-send-email-sean.wang@mediatek.com> -To: , , - , , - , -Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, - netdev@vger.kernel.org, sean.wang@mediatek.com, - linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net -Date: Wed, 29 Mar 2017 17:38:21 +0800 - -From: Sean Wang - -The patch adds the setup for allowing CDM can recognize these packets with -carrying port-distinguishing tag. Otherwise, these tagging packets will be -handled incorrectly by CDM. The setup is also working out for general -untag packets as well. - -Signed-off-by: Sean Wang -Signed-off-by: Landen Chao -Reviewed-by: Andrew Lunn -Reviewed-by: Florian Fainelli ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++ - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ - 2 files changed, 10 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1855,6 +1855,12 @@ static int mtk_hw_init(struct mtk_eth *e - /* GE2, Force 1000M/FD, FC ON */ - mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1)); - -+ /* Indicates CDM to parse the MTK special tag from CPU -+ * which also is working out for untag packets. -+ */ -+ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); -+ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); -+ - /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -70,6 +70,10 @@ - /* Frame Engine Interrupt Grouping Register */ - #define MTK_FE_INT_GRP 0x20 - -+/* CDMP Ingress Control Register */ -+#define MTK_CDMQ_IG_CTRL 0x1400 -+#define MTK_CDMQ_STAG_EN BIT(0) -+ - /* CDMP Exgress Control Register */ - #define MTK_CDMP_EG_CTRL 0x404 - diff --git a/target/linux/mediatek/patches-4.9/0092-dsa4.patch b/target/linux/mediatek/patches-4.9/0092-dsa4.patch deleted file mode 100644 index 4daebfbc10..0000000000 --- a/target/linux/mediatek/patches-4.9/0092-dsa4.patch +++ /dev/null @@ -1,44 +0,0 @@ -From patchwork Wed Mar 29 09:38:22 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [net-next, v3, - 4/5] net-next: ethernet: mediatek: add device_node of GMAC pointing - into the netdev instance -From: sean.wang@mediatek.com -X-Patchwork-Id: 9651097 -Message-Id: <1490780303-18598-5-git-send-email-sean.wang@mediatek.com> -To: , , - , , - , -Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, - netdev@vger.kernel.org, sean.wang@mediatek.com, - linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net -Date: Wed, 29 Mar 2017 17:38:22 +0800 - -From: Sean Wang - -the patch adds the setup of the corresponding device node of GMAC into the -netdev instance which could allow other modules such as DSA to find the -instance through the node in dt-bindings using of_find_net_device_by_node() -call. - -Signed-off-by: Sean Wang -Reviewed-by: Andrew Lunn -Reviewed-by: Florian Fainelli ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2333,6 +2333,8 @@ static int mtk_add_mac(struct mtk_eth *e - eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; - - eth->netdev[id]->irq = eth->irq[0]; -+ eth->netdev[id]->dev.of_node = np; -+ - return 0; - - free_netdev: diff --git a/target/linux/mediatek/patches-4.9/0092-dsa5.patch b/target/linux/mediatek/patches-4.9/0092-dsa5.patch deleted file mode 100644 index 63a40d00de..0000000000 --- a/target/linux/mediatek/patches-4.9/0092-dsa5.patch +++ /dev/null @@ -1,1598 +0,0 @@ -From patchwork Wed Mar 29 09:38:23 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [net-next, v3, - 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch -From: sean.wang@mediatek.com -X-Patchwork-Id: 9651095 -Message-Id: <1490780303-18598-6-git-send-email-sean.wang@mediatek.com> -To: , , - , , - , -Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, - netdev@vger.kernel.org, sean.wang@mediatek.com, - linux-kernel@vger.kernel.org, - linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net -Date: Wed, 29 Mar 2017 17:38:23 +0800 - -From: Sean Wang - -MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on -Mediatek router platforms such as MT7623A or MT7623N platform which -includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY. -Among these ports, The port from 0 to 4 are the user ports connecting -with the remote devices while the port 5 and 6 are the CPU ports -connecting into Mediatek Ethernet GMAC. - -For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC -through either the TRGMII or RGMII which could be controlled by phy-mode -in the dt-bindings to specify which mode is preferred to use. And for -port 5, only RGMII can be specified. However, currently, only port 6 is -being supported in this DSA driver. - -The driver is made with the reference to qca8k and other existing DSA -driver. The most of the essential callbacks of the DSA are already -support in the driver, including tag insert for user port distinguishing, -port control, bridge offloading, STP setup and ethtool operation to allow -DSA to model each user port into a standalone netdevice as the other DSA -driver had done. - -Signed-off-by: Sean Wang -Signed-off-by: Landen Chao ---- - drivers/net/dsa/Kconfig | 8 + - drivers/net/dsa/Makefile | 2 +- - drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/mt7530.h | 390 ++++++++++++++++ - 4 files changed, 1525 insertions(+), 1 deletion(-) - create mode 100644 drivers/net/dsa/mt7530.c - create mode 100644 drivers/net/dsa/mt7530.h - ---- a/drivers/net/dsa/Kconfig -+++ b/drivers/net/dsa/Kconfig -@@ -34,4 +34,12 @@ config NET_DSA_QCA8K - This enables support for the Qualcomm Atheros QCA8K Ethernet - switch chips. - -+config NET_DSA_MT7530 -+ tristate "Mediatek MT7530 Ethernet switch support" -+ depends on NET_DSA -+ select NET_DSA_TAG_MTK -+ ---help--- -+ This enables support for the Mediatek MT7530 Ethernet switch -+ chip. -+ - endmenu ---- a/drivers/net/dsa/Makefile -+++ b/drivers/net/dsa/Makefile -@@ -1,6 +1,6 @@ - obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o - obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm_sf2.o - obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o -- -+obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o - obj-y += b53/ - obj-y += mv88e6xxx/ ---- /dev/null -+++ b/drivers/net/dsa/mt7530.c -@@ -0,0 +1,1126 @@ -+/* -+ * Mediatek MT7530 DSA Switch driver -+ * Copyright (C) 2017 Sean Wang -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mt7530.h" -+ -+/* String, offset, and register size in bytes if different from 4 bytes */ -+static const struct mt7530_mib_desc mt7530_mib[] = { -+ MIB_DESC(1, 0x00, "TxDrop"), -+ MIB_DESC(1, 0x04, "TxCrcErr"), -+ MIB_DESC(1, 0x08, "TxUnicast"), -+ MIB_DESC(1, 0x0c, "TxMulticast"), -+ MIB_DESC(1, 0x10, "TxBroadcast"), -+ MIB_DESC(1, 0x14, "TxCollision"), -+ MIB_DESC(1, 0x18, "TxSingleCollision"), -+ MIB_DESC(1, 0x1c, "TxMultipleCollision"), -+ MIB_DESC(1, 0x20, "TxDeferred"), -+ MIB_DESC(1, 0x24, "TxLateCollision"), -+ MIB_DESC(1, 0x28, "TxExcessiveCollistion"), -+ MIB_DESC(1, 0x2c, "TxPause"), -+ MIB_DESC(1, 0x30, "TxPktSz64"), -+ MIB_DESC(1, 0x34, "TxPktSz65To127"), -+ MIB_DESC(1, 0x38, "TxPktSz128To255"), -+ MIB_DESC(1, 0x3c, "TxPktSz256To511"), -+ MIB_DESC(1, 0x40, "TxPktSz512To1023"), -+ MIB_DESC(1, 0x44, "Tx1024ToMax"), -+ MIB_DESC(2, 0x48, "TxBytes"), -+ MIB_DESC(1, 0x60, "RxDrop"), -+ MIB_DESC(1, 0x64, "RxFiltering"), -+ MIB_DESC(1, 0x6c, "RxMulticast"), -+ MIB_DESC(1, 0x70, "RxBroadcast"), -+ MIB_DESC(1, 0x74, "RxAlignErr"), -+ MIB_DESC(1, 0x78, "RxCrcErr"), -+ MIB_DESC(1, 0x7c, "RxUnderSizeErr"), -+ MIB_DESC(1, 0x80, "RxFragErr"), -+ MIB_DESC(1, 0x84, "RxOverSzErr"), -+ MIB_DESC(1, 0x88, "RxJabberErr"), -+ MIB_DESC(1, 0x8c, "RxPause"), -+ MIB_DESC(1, 0x90, "RxPktSz64"), -+ MIB_DESC(1, 0x94, "RxPktSz65To127"), -+ MIB_DESC(1, 0x98, "RxPktSz128To255"), -+ MIB_DESC(1, 0x9c, "RxPktSz256To511"), -+ MIB_DESC(1, 0xa0, "RxPktSz512To1023"), -+ MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"), -+ MIB_DESC(2, 0xa8, "RxBytes"), -+ MIB_DESC(1, 0xb0, "RxCtrlDrop"), -+ MIB_DESC(1, 0xb4, "RxIngressDrop"), -+ MIB_DESC(1, 0xb8, "RxArlDrop"), -+}; -+ -+static struct mt7530_priv *lpriv; -+static void mt7530_port_disable(struct dsa_switch *ds, int port, -+ struct phy_device *phy); -+static int mt7530_cpu_port_enable(struct mt7530_priv *priv, -+ int port); -+ -+static int -+mt7623_trgmii_write(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ int ret; -+ -+ ret = regmap_write(priv->ethernet, TRGMII_BASE(reg), val); -+ if (ret < 0) -+ dev_err(priv->dev, -+ "failed to priv write register\n"); -+ return ret; -+} -+ -+static u32 -+mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg) -+{ -+ int ret; -+ u32 val; -+ -+ ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val); -+ if (ret < 0) { -+ dev_err(priv->dev, -+ "failed to priv read register\n"); -+ return ret; -+ } -+ -+ return val; -+} -+ -+static void -+mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg, -+ u32 mask, u32 set) -+{ -+ u32 val; -+ -+ val = mt7623_trgmii_read(priv, reg); -+ val &= ~mask; -+ val |= set; -+ mt7623_trgmii_write(priv, reg, val); -+} -+ -+static void -+mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ mt7623_trgmii_rmw(priv, reg, 0, val); -+} -+ -+static void -+mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ mt7623_trgmii_rmw(priv, reg, val, 0); -+} -+ -+static int -+core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad) -+{ -+ struct mii_bus *bus = priv->bus; -+ int value, ret; -+ -+ /* Write the desired MMD Devad */ -+ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); -+ if (ret < 0) -+ goto err; -+ -+ /* Write the desired MMD register address */ -+ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); -+ if (ret < 0) -+ goto err; -+ -+ /* Select the Function : DATA with no post increment */ -+ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); -+ if (ret < 0) -+ goto err; -+ -+ /* Read the content of the MMD's selected register */ -+ value = bus->read(bus, 0, MII_MMD_DATA); -+ -+ return value; -+err: -+ dev_err(&bus->dev, "failed to read mmd register\n"); -+ -+ return ret; -+} -+ -+static int -+core_write_mmd_indirect(struct mt7530_priv *priv, int prtad, -+ int devad, u32 data) -+{ -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ /* Write the desired MMD Devad */ -+ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); -+ if (ret < 0) -+ goto err; -+ -+ /* Write the desired MMD register address */ -+ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); -+ if (ret < 0) -+ goto err; -+ -+ /* Select the Function : DATA with no post increment */ -+ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); -+ if (ret < 0) -+ goto err; -+ -+ /* Write the data into MMD's selected register */ -+ ret = bus->write(bus, 0, MII_MMD_DATA, data); -+err: -+ if (ret < 0) -+ dev_err(&bus->dev, -+ "failed to write mmd register\n"); -+ return ret; -+} -+ -+static void -+core_write(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ struct mii_bus *bus = priv->bus; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); -+ -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+static void -+core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set) -+{ -+ struct mii_bus *bus = priv->bus; -+ u32 val; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2); -+ val &= ~mask; -+ val |= set; -+ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); -+ -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+static void -+core_set(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ core_rmw(priv, reg, 0, val); -+} -+ -+static void -+core_clear(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ core_rmw(priv, reg, val, 0); -+} -+ -+static int -+mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 page, r, lo, hi; -+ int ret; -+ -+ page = (reg >> 6) & 0x3ff; -+ r = (reg >> 2) & 0xf; -+ lo = val & 0xffff; -+ hi = val >> 16; -+ -+ /* MT7530 uses 31 as the pseudo port */ -+ ret = bus->write(bus, 0x1f, 0x1f, page); -+ if (ret < 0) -+ goto err; -+ -+ ret = bus->write(bus, 0x1f, r, lo); -+ if (ret < 0) -+ goto err; -+ -+ ret = bus->write(bus, 0x1f, 0x10, hi); -+err: -+ if (ret < 0) -+ dev_err(&bus->dev, -+ "failed to write mt7530 register\n"); -+ return ret; -+} -+ -+static u32 -+mt7530_mii_read(struct mt7530_priv *priv, u32 reg) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 page, r, lo, hi; -+ int ret; -+ -+ page = (reg >> 6) & 0x3ff; -+ r = (reg >> 2) & 0xf; -+ -+ /* MT7530 uses 31 as the pseudo port */ -+ ret = bus->write(bus, 0x1f, 0x1f, page); -+ if (ret < 0) { -+ dev_err(&bus->dev, -+ "failed to read mt7530 register\n"); -+ return ret; -+ } -+ -+ lo = bus->read(bus, 0x1f, r); -+ hi = bus->read(bus, 0x1f, 0x10); -+ -+ return (hi << 16) | (lo & 0xffff); -+} -+ -+static void -+mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ struct mii_bus *bus = priv->bus; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ mt7530_mii_write(priv, reg, val); -+ -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+static u32 -+_mt7530_read(u32 reg) -+{ -+ struct mt7530_priv *priv = lpriv; -+ struct mii_bus *bus = priv->bus; -+ u32 val; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ val = mt7530_mii_read(priv, reg); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return val; -+} -+ -+static u32 -+mt7530_read(struct mt7530_priv *priv, u32 reg) -+{ -+ return _mt7530_read(reg); -+} -+ -+static void -+mt7530_rmw(struct mt7530_priv *priv, u32 reg, -+ u32 mask, u32 set) -+{ -+ struct mii_bus *bus = priv->bus; -+ u32 val; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ val = mt7530_mii_read(priv, reg); -+ val &= ~mask; -+ val |= set; -+ mt7530_mii_write(priv, reg, val); -+ -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+static void -+mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ mt7530_rmw(priv, reg, 0, val); -+} -+ -+static void -+mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val) -+{ -+ mt7530_rmw(priv, reg, val, 0); -+} -+ -+static int -+mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp) -+{ -+ u32 val; -+ int ret; -+ -+ /* Set the command operating upon the MAC address entries */ -+ val = ATC_BUSY | ATC_MAT(0) | cmd; -+ mt7530_write(priv, MT7530_ATC, val); -+ -+ ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val, -+ !(val & ATC_BUSY), 20, 20000); -+ if (ret < 0) { -+ dev_err(priv->dev, "reset timeout\n"); -+ return ret; -+ } -+ -+ /* Additional sanity for read command if the specified -+ * entry is invalid -+ */ -+ val = mt7530_read(priv, MT7530_ATC); -+ if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID)) -+ return -EINVAL; -+ -+ if (rsp) -+ *rsp = val; -+ -+ return 0; -+} -+ -+static void -+mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb) -+{ -+ u32 reg[3]; -+ int i; -+ -+ /* Read from ARL table into an array */ -+ for (i = 0; i < 3; i++) { -+ reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4)); -+ -+ dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n", -+ __func__, __LINE__, i, reg[i]); -+ } -+ -+ fdb->vid = (reg[1] >> CVID) & CVID_MASK; -+ fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK; -+ fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK; -+ fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK; -+ fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK; -+ fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK; -+ fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK; -+ fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK; -+ fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK; -+ fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT; -+} -+ -+static void -+mt7530_fdb_write(struct mt7530_priv *priv, u16 vid, -+ u8 port_mask, const u8 *mac, -+ u8 aging, u8 type) -+{ -+ u32 reg[3] = { 0 }; -+ int i; -+ -+ reg[1] |= vid & CVID_MASK; -+ reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER; -+ reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP; -+ /* STATIC_ENT indicate that entry is static wouldn't -+ * be aged out and STATIC_EMP specified as erasing an -+ * entry -+ */ -+ reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS; -+ reg[1] |= mac[5] << MAC_BYTE_5; -+ reg[1] |= mac[4] << MAC_BYTE_4; -+ reg[0] |= mac[3] << MAC_BYTE_3; -+ reg[0] |= mac[2] << MAC_BYTE_2; -+ reg[0] |= mac[1] << MAC_BYTE_1; -+ reg[0] |= mac[0] << MAC_BYTE_0; -+ -+ /* Write array into the ARL table */ -+ for (i = 0; i < 3; i++) -+ mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]); -+} -+ -+static int -+mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ u32 ncpo1, ssc_delta, trgint, i; -+ -+ switch (mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ trgint = 0; -+ ncpo1 = 0x0c80; -+ ssc_delta = 0x87; -+ break; -+ case PHY_INTERFACE_MODE_TRGMII: -+ trgint = 1; -+ ncpo1 = 0x1400; -+ ssc_delta = 0x57; -+ break; -+ default: -+ dev_err(priv->dev, "xMII mode %d not supported\n", mode); -+ return -EINVAL; -+ } -+ -+ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, -+ P6_INTF_MODE(trgint)); -+ -+ /* Lower Tx Driving for TRGMII path */ -+ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) -+ mt7530_write(priv, MT7530_TRGMII_TD_ODT(i), -+ TD_DM_DRVP(8) | TD_DM_DRVN(8)); -+ -+ /* Setup core clock for MT7530 */ -+ if (!trgint) { -+ /* Disable MT7530 core clock */ -+ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); -+ -+ /* Disable PLL, since phy_device has not yet been created -+ * provided for phy_[read,write]_mmd_indirect is called, we -+ * provide our own core_write_mmd_indirect to complete this -+ * function. -+ */ -+ core_write_mmd_indirect(priv, -+ CORE_GSWPLL_GRP1, -+ MDIO_MMD_VEND2, -+ 0); -+ -+ /* Set core clock into 500Mhz */ -+ core_write(priv, CORE_GSWPLL_GRP2, -+ RG_GSWPLL_POSDIV_500M(1) | -+ RG_GSWPLL_FBKDIV_500M(25)); -+ -+ /* Enable PLL */ -+ core_write(priv, CORE_GSWPLL_GRP1, -+ RG_GSWPLL_EN_PRE | -+ RG_GSWPLL_POSDIV_200M(2) | -+ RG_GSWPLL_FBKDIV_200M(32)); -+ -+ /* Enable MT7530 core clock */ -+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); -+ } -+ -+ /* Setup the MT7530 TRGMII Tx Clock */ -+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); -+ core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); -+ core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); -+ core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); -+ core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); -+ core_write(priv, CORE_PLL_GROUP4, -+ RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | -+ RG_SYSPLL_BIAS_LPF_EN); -+ core_write(priv, CORE_PLL_GROUP2, -+ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | -+ RG_SYSPLL_POSDIV(1)); -+ core_write(priv, CORE_PLL_GROUP7, -+ RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | -+ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); -+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, -+ REG_GSWCK_EN | REG_TRGMIICK_EN); -+ -+ if (!trgint) -+ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) -+ mt7530_rmw(priv, MT7530_TRGMII_RD(i), -+ RD_TAP_MASK, RD_TAP(16)); -+ else -+ mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII); -+ -+ return 0; -+} -+ -+static int -+mt7623_pad_clk_setup(struct dsa_switch *ds) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ int i; -+ -+ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) -+ mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i), -+ TD_DM_DRVP(8) | TD_DM_DRVN(8)); -+ -+ mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL); -+ mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST); -+ -+ return 0; -+} -+ -+static void -+mt7530_mib_reset(struct dsa_switch *ds) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH); -+ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE); -+} -+ -+static void -+mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable) -+{ -+ u32 mask = PMCR_TX_EN | PMCR_RX_EN; -+ -+ if (enable) -+ mt7530_set(priv, MT7530_PMCR_P(port), mask); -+ else -+ mt7530_clear(priv, MT7530_PMCR_P(port), mask); -+} -+ -+static int -+mt7530_setup(struct dsa_switch *ds) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ int ret, i; -+ u32 id, val; -+ struct device_node *dn; -+ -+ /* The parent node of master_netdev which holds the common system -+ * controller also is the container for two GMACs nodes representing -+ * as two netdev instances. -+ */ -+ dn = ds->master_netdev->dev.of_node->parent; -+ priv->ethernet = syscon_node_to_regmap(dn); -+ if (IS_ERR(priv->ethernet)) -+ return PTR_ERR(priv->ethernet); -+ -+ regulator_set_voltage(priv->core_pwr, 1000000, 1000000); -+ ret = regulator_enable(priv->core_pwr); -+ if (ret < 0) { -+ dev_err(priv->dev, -+ "Failed to enable core power: %d\n", ret); -+ return ret; -+ } -+ -+ regulator_set_voltage(priv->io_pwr, 3300000, 3300000); -+ ret = regulator_enable(priv->io_pwr); -+ if (ret < 0) { -+ dev_err(priv->dev, "Failed to enable io pwr: %d\n", -+ ret); -+ return ret; -+ } -+ -+ /* Reset whole chip through gpio pin or memory-mapped registers for -+ * different type of hardware -+ */ -+ if (priv->mcm) { -+ reset_control_assert(priv->rstc); -+ usleep_range(1000, 1100); -+ reset_control_deassert(priv->rstc); -+ } else { -+ gpiod_set_value_cansleep(priv->reset, 0); -+ usleep_range(1000, 1100); -+ gpiod_set_value_cansleep(priv->reset, 1); -+ } -+ -+ /* Waiting for MT7530 got to stable */ -+ ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0, -+ 20, 1000000); -+ if (ret < 0) { -+ dev_err(priv->dev, "reset timeout\n"); -+ return ret; -+ } -+ -+ id = mt7530_read(priv, MT7530_CREV); -+ id >>= CHIP_NAME_SHIFT; -+ if (id != MT7530_ID) { -+ dev_err(priv->dev, "chip %x can't be supported\n", id); -+ return -ENODEV; -+ } -+ -+ /* Reset the switch through internal reset */ -+ mt7530_write(priv, MT7530_SYS_CTRL, -+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | -+ SYS_CTRL_REG_RST); -+ -+ /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ -+ val = mt7530_read(priv, MT7530_MHWTRAP); -+ val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; -+ val |= MHWTRAP_MANUAL; -+ mt7530_write(priv, MT7530_MHWTRAP, val); -+ -+ /* Enable and reset MIB counters */ -+ mt7530_mib_reset(ds); -+ -+ mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ /* Disable forwarding by default on all ports */ -+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, -+ PCR_MATRIX_CLR); -+ -+ if (dsa_is_cpu_port(ds, i)) -+ mt7530_cpu_port_enable(priv, i); -+ else -+ mt7530_port_disable(ds, i, NULL); -+ } -+ -+ /* Flush the FDB table */ -+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ return mdiobus_read_nested(priv->bus, port, regnum); -+} -+ -+int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ return mdiobus_write_nested(priv->bus, port, regnum, val); -+} -+ -+static void -+mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) -+ strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name, -+ ETH_GSTRING_LEN); -+} -+ -+static void -+mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ const struct mt7530_mib_desc *mib; -+ u32 reg, i; -+ u64 hi; -+ -+ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) { -+ mib = &mt7530_mib[i]; -+ reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset; -+ -+ data[i] = mt7530_read(priv, reg); -+ if (mib->size == 2) { -+ hi = mt7530_read(priv, reg + 4); -+ data[i] |= hi << 32; -+ } -+ } -+} -+ -+static int -+mt7530_get_sset_count(struct dsa_switch *ds) -+{ -+ return ARRAY_SIZE(mt7530_mib); -+} -+ -+static void mt7530_adjust_link(struct dsa_switch *ds, int port, -+ struct phy_device *phydev) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ if (phy_is_pseudo_fixed_link(phydev)) { -+ dev_dbg(priv->dev, "phy-mode for master device = %x\n", -+ phydev->interface); -+ -+ /* Setup TX circuit incluing relevant PAD and driving */ -+ mt7530_pad_clk_setup(ds, phydev->interface); -+ -+ /* Setup RX circuit, relevant PAD and driving on the host -+ * which must be placed after the setup on the device side is -+ * all finished. -+ */ -+ mt7623_pad_clk_setup(ds); -+ } -+} -+ -+static int -+mt7530_cpu_port_enable(struct mt7530_priv *priv, -+ int port) -+{ -+ /* Enable Mediatek header mode on the cpu port */ -+ mt7530_write(priv, MT7530_PVC_P(port), -+ PORT_SPEC_TAG); -+ -+ /* Setup the MAC by default for the cpu port */ -+ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); -+ -+ /* Disable auto learning on the cpu port */ -+ mt7530_set(priv, MT7530_PSC_P(port), SA_DIS); -+ -+ /* Unknown unicast frame fordwarding to the cpu port */ -+ mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port))); -+ -+ /* CPU port gets connected to all user ports of -+ * the switch -+ */ -+ mt7530_write(priv, MT7530_PCR_P(port), -+ PCR_MATRIX(priv->ds->enabled_port_mask)); -+ -+ return 0; -+} -+ -+static int -+mt7530_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ /* Setup the MAC for the user port */ -+ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK); -+ -+ /* Allow the user port gets connected to the cpu port and also -+ * restore the port matrix if the port is the member of a certain -+ * bridge. -+ */ -+ priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ priv->ports[port].enable = true; -+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, -+ priv->ports[port].pm); -+ mt7530_port_set_status(priv, port, 1); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static void -+mt7530_port_disable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ /* Clear up all port matrix which could be restored in the next -+ * enablement for the port. -+ */ -+ priv->ports[port].enable = false; -+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, -+ PCR_MATRIX_CLR); -+ mt7530_port_set_status(priv, port, 0); -+ -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static void -+mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ u32 stp_state; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ stp_state = MT7530_STP_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ stp_state = MT7530_STP_BLOCKING; -+ break; -+ case BR_STATE_LISTENING: -+ stp_state = MT7530_STP_LISTENING; -+ break; -+ case BR_STATE_LEARNING: -+ stp_state = MT7530_STP_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ default: -+ stp_state = MT7530_STP_FORWARDING; -+ break; -+ } -+ -+ mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state); -+} -+ -+static int -+mt7530_port_bridge_join(struct dsa_switch *ds, int port, -+ struct net_device *bridge) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ u32 port_bitmap = BIT(MT7530_CPU_PORT); -+ int i; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ /* Add this port to the port matrix of the other ports in the -+ * same bridge. If the port is disabled, port matrix is kept -+ * and not being setup until the port becomes enabled. -+ */ -+ if (ds->enabled_port_mask & BIT(i) && i != port) { -+ if (ds->ports[i].bridge_dev != bridge) -+ continue; -+ if (priv->ports[i].enable) -+ mt7530_set(priv, MT7530_PCR_P(i), -+ PCR_MATRIX(BIT(port))); -+ priv->ports[i].pm |= PCR_MATRIX(BIT(port)); -+ -+ port_bitmap |= BIT(i); -+ } -+ } -+ -+ /* Add the all other ports to this port matrix. */ -+ if (priv->ports[port].enable) -+ mt7530_rmw(priv, MT7530_PCR_P(port), -+ PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap)); -+ priv->ports[port].pm |= PCR_MATRIX(port_bitmap); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static void -+mt7530_port_bridge_leave(struct dsa_switch *ds, int port, -+ struct net_device *bridge) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ int i; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ /* Remove this port from the port matrix of the other ports -+ * in the same bridge. If the port is disabled, port matrix -+ * is kept and not being setup until the port becomes enabled. -+ */ -+ if (ds->enabled_port_mask & BIT(i) && i != port) { -+ if (ds->ports[i].bridge_dev != bridge) -+ continue; -+ if (priv->ports[i].enable) -+ mt7530_clear(priv, MT7530_PCR_P(i), -+ PCR_MATRIX(BIT(port))); -+ priv->ports[i].pm &= ~PCR_MATRIX(BIT(port)); -+ } -+ } -+ -+ /* Set the cpu port to be the only one in the port matrix of -+ * this port. -+ */ -+ if (priv->ports[port].enable) -+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, -+ PCR_MATRIX(BIT(MT7530_CPU_PORT))); -+ priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+mt7530_port_fdb_prepare(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_fdb *fdb, -+ struct switchdev_trans *trans) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ int ret; -+ -+ /* Because auto-learned entrie shares the same FDB table. -+ * an entry is reserved with no port_mask to make sure fdb_add -+ * is called while the entry is still available. -+ */ -+ mutex_lock(&priv->reg_mutex); -+ mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT); -+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static void -+mt7530_port_fdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_fdb *fdb, -+ struct switchdev_trans *trans) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ u8 port_mask = BIT(port); -+ -+ mutex_lock(&priv->reg_mutex); -+ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT); -+ mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+mt7530_port_fdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_fdb *fdb) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ int ret; -+ u8 port_mask = BIT(port); -+ -+ mutex_lock(&priv->reg_mutex); -+ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP); -+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+mt7530_port_fdb_dump(struct dsa_switch *ds, int port, -+ struct switchdev_obj_port_fdb *fdb, -+ int (*cb)(struct switchdev_obj *obj)) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ struct mt7530_fdb _fdb = { 0 }; -+ int cnt = MT7530_NUM_FDB_RECORDS; -+ int ret = 0; -+ u32 rsp = 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp); -+ if (ret < 0) -+ goto err; -+ -+ do { -+ if (rsp & ATC_SRCH_HIT) { -+ mt7530_fdb_read(priv, &_fdb); -+ if (_fdb.port_mask & BIT(port)) { -+ ether_addr_copy(fdb->addr, _fdb.mac); -+ fdb->vid = _fdb.vid; -+ fdb->ndm_state = _fdb.noarp ? -+ NUD_NOARP : NUD_REACHABLE; -+ ret = cb(&fdb->obj); -+ if (ret < 0) -+ break; -+ } -+ } -+ } while (--cnt && -+ !(rsp & ATC_SRCH_END) && -+ !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp)); -+err: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static enum dsa_tag_protocol -+mtk_get_tag_protocol(struct dsa_switch *ds) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { -+ dev_warn(priv->dev, -+ "port not matched with tagging CPU port\n"); -+ return DSA_TAG_PROTO_NONE; -+ } else { -+ return DSA_TAG_PROTO_MTK; -+ } -+} -+ -+static struct dsa_switch_ops mt7530_switch_ops = { -+ .get_tag_protocol = mtk_get_tag_protocol, -+ .setup = mt7530_setup, -+ .get_strings = mt7530_get_strings, -+ .phy_read = mt7530_phy_read, -+ .phy_write = mt7530_phy_write, -+ .get_ethtool_stats = mt7530_get_ethtool_stats, -+ .get_sset_count = mt7530_get_sset_count, -+ .adjust_link = mt7530_adjust_link, -+ .port_enable = mt7530_port_enable, -+ .port_disable = mt7530_port_disable, -+ .port_stp_state_set = mt7530_stp_state_set, -+ .port_bridge_join = mt7530_port_bridge_join, -+ .port_bridge_leave = mt7530_port_bridge_leave, -+ .port_fdb_prepare = mt7530_port_fdb_prepare, -+ .port_fdb_add = mt7530_port_fdb_add, -+ .port_fdb_del = mt7530_port_fdb_del, -+ .port_fdb_dump = mt7530_port_fdb_dump, -+}; -+ -+static int -+mt7530_probe(struct mdio_device *mdiodev) -+{ -+ struct mt7530_priv *priv; -+ struct device_node *dn; -+ -+ dn = mdiodev->dev.of_node; -+ -+ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); -+ if (!priv->ds) -+ return -ENOMEM; -+ -+ /* Use medatek,mcm property to distinguish hardware type that would -+ * casues a little bit differences on power-on sequence. -+ */ -+ priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); -+ if (priv->mcm) { -+ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); -+ -+ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); -+ if (IS_ERR(priv->rstc)) { -+ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); -+ return PTR_ERR(priv->rstc); -+ } -+ } -+ -+ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); -+ if (IS_ERR(priv->core_pwr)) -+ return PTR_ERR(priv->core_pwr); -+ -+ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); -+ if (IS_ERR(priv->io_pwr)) -+ return PTR_ERR(priv->io_pwr); -+ -+ /* Not MCM that indicates switch works as the remote standalone -+ * integrated circuit so the GPIO pin would be used to complete -+ * the reset, otherwise memory-mapped register accessing used -+ * through syscon provides in the case of MCM. -+ */ -+ if (!priv->mcm) { -+ priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", -+ GPIOD_OUT_LOW); -+ if (IS_ERR(priv->reset)) { -+ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); -+ return PTR_ERR(priv->reset); -+ } -+ } -+ -+ priv->bus = mdiodev->bus; -+ priv->dev = &mdiodev->dev; -+ priv->ds->priv = priv; -+ priv->ds->ops = &mt7530_switch_ops; -+ mutex_init(&priv->reg_mutex); -+ lpriv = priv; -+ dev_set_drvdata(&mdiodev->dev, priv); -+ -+ return dsa_register_switch(priv->ds, &mdiodev->dev); -+} -+ -+static void -+mt7530_remove(struct mdio_device *mdiodev) -+{ -+ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ int ret = 0; -+ -+ ret = regulator_disable(priv->core_pwr); -+ if (ret < 0) -+ dev_err(priv->dev, -+ "Failed to disable core power: %d\n", ret); -+ -+ ret = regulator_disable(priv->io_pwr); -+ if (ret < 0) -+ dev_err(priv->dev, "Failed to disable io pwr: %d\n", -+ ret); -+ -+ dsa_unregister_switch(priv->ds); -+ mutex_destroy(&priv->reg_mutex); -+} -+ -+static const struct of_device_id mt7530_of_match[] = { -+ { .compatible = "mediatek,mt7530" }, -+ { /* sentinel */ }, -+}; -+ -+static struct mdio_driver mt7530_mdio_driver = { -+ .probe = mt7530_probe, -+ .remove = mt7530_remove, -+ .mdiodrv.driver = { -+ .name = "mt7530", -+ .of_match_table = mt7530_of_match, -+ }, -+}; -+ -+mdio_module_driver(mt7530_mdio_driver); -+ -+MODULE_AUTHOR("Sean Wang "); -+MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:mediatek-mt7530"); ---- /dev/null -+++ b/drivers/net/dsa/mt7530.h -@@ -0,0 +1,390 @@ -+/* -+ * Copyright (C) 2017 Sean Wang -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef __MT7530_H -+#define __MT7530_H -+ -+#define MT7530_NUM_PORTS 7 -+#define MT7530_CPU_PORT 6 -+#define MT7530_NUM_FDB_RECORDS 2048 -+ -+#define NUM_TRGMII_CTRL 5 -+ -+#define TRGMII_BASE(x) (0x10000 + (x)) -+ -+/* Registers to ethsys access */ -+#define ETHSYS_CLKCFG0 0x2c -+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) -+ -+#define SYSC_REG_RSTCTRL 0x34 -+#define RESET_MCM BIT(2) -+ -+/* Registers to mac forward control for unknown frames */ -+#define MT7530_MFC 0x10 -+#define BC_FFP(x) (((x) & 0xff) << 24) -+#define UNM_FFP(x) (((x) & 0xff) << 16) -+#define UNU_FFP(x) (((x) & 0xff) << 8) -+#define UNU_FFP_MASK UNU_FFP(~0) -+ -+/* Registers for address table access */ -+#define MT7530_ATA1 0x74 -+#define STATIC_EMP 0 -+#define STATIC_ENT 3 -+#define MT7530_ATA2 0x78 -+ -+/* Register for address table write data */ -+#define MT7530_ATWD 0x7c -+ -+/* Register for address table control */ -+#define MT7530_ATC 0x80 -+#define ATC_HASH (((x) & 0xfff) << 16) -+#define ATC_BUSY BIT(15) -+#define ATC_SRCH_END BIT(14) -+#define ATC_SRCH_HIT BIT(13) -+#define ATC_INVALID BIT(12) -+#define ATC_MAT(x) (((x) & 0xf) << 8) -+#define ATC_MAT_MACTAB ATC_MAT(0) -+ -+enum mt7530_fdb_cmd { -+ MT7530_FDB_READ = 0, -+ MT7530_FDB_WRITE = 1, -+ MT7530_FDB_FLUSH = 2, -+ MT7530_FDB_START = 4, -+ MT7530_FDB_NEXT = 5, -+}; -+ -+/* Registers for table search read address */ -+#define MT7530_TSRA1 0x84 -+#define MAC_BYTE_0 24 -+#define MAC_BYTE_1 16 -+#define MAC_BYTE_2 8 -+#define MAC_BYTE_3 0 -+#define MAC_BYTE_MASK 0xff -+ -+#define MT7530_TSRA2 0x88 -+#define MAC_BYTE_4 24 -+#define MAC_BYTE_5 16 -+#define CVID 0 -+#define CVID_MASK 0xfff -+ -+#define MT7530_ATRD 0x8C -+#define AGE_TIMER 24 -+#define AGE_TIMER_MASK 0xff -+#define PORT_MAP 4 -+#define PORT_MAP_MASK 0xff -+#define ENT_STATUS 2 -+#define ENT_STATUS_MASK 0x3 -+ -+/* Register for vlan table control */ -+#define MT7530_VTCR 0x90 -+#define VTCR_BUSY BIT(31) -+#define VTCR_FUNC (((x) & 0xf) << 12) -+#define VTCR_FUNC_RD_VID 0x1 -+#define VTCR_FUNC_WR_VID 0x2 -+#define VTCR_FUNC_INV_VID 0x3 -+#define VTCR_FUNC_VAL_VID 0x4 -+#define VTCR_VID ((x) & 0xfff) -+ -+/* Register for setup vlan and acl write data */ -+#define MT7530_VAWD1 0x94 -+#define PORT_STAG BIT(31) -+#define IVL_MAC BIT(30) -+#define PORT_MEM(x) (((x) & 0xff) << 16) -+#define VALID BIT(1) -+ -+#define MT7530_VAWD2 0x98 -+ -+/* Register for port STP state control */ -+#define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100)) -+#define FID_PST(x) ((x) & 0x3) -+#define FID_PST_MASK FID_PST(0x3) -+ -+enum mt7530_stp_state { -+ MT7530_STP_DISABLED = 0, -+ MT7530_STP_BLOCKING = 1, -+ MT7530_STP_LISTENING = 1, -+ MT7530_STP_LEARNING = 2, -+ MT7530_STP_FORWARDING = 3 -+}; -+ -+/* Register for port control */ -+#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100)) -+#define PORT_VLAN(x) ((x) & 0x3) -+#define PCR_MATRIX(x) (((x) & 0xff) << 16) -+#define PORT_PRI(x) (((x) & 0x7) << 24) -+#define EG_TAG(x) (((x) & 0x3) << 28) -+#define PCR_MATRIX_MASK PCR_MATRIX(0xff) -+#define PCR_MATRIX_CLR PCR_MATRIX(0) -+ -+/* Register for port security control */ -+#define MT7530_PSC_P(x) (0x200c + ((x) * 0x100)) -+#define SA_DIS BIT(4) -+ -+/* Register for port vlan control */ -+#define MT7530_PVC_P(x) (0x2010 + ((x) * 0x100)) -+#define PORT_SPEC_TAG BIT(5) -+#define VLAN_ATTR(x) (((x) & 0x3) << 6) -+#define STAG_VPID (((x) & 0xffff) << 16) -+ -+/* Register for port port-and-protocol based vlan 1 control */ -+#define MT7530_PPBV1_P(x) (0x2014 + ((x) * 0x100)) -+ -+/* Register for port MAC control register */ -+#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100)) -+#define PMCR_IFG_XMIT(x) (((x) & 0x3) << 18) -+#define PMCR_MAC_MODE BIT(16) -+#define PMCR_FORCE_MODE BIT(15) -+#define PMCR_TX_EN BIT(14) -+#define PMCR_RX_EN BIT(13) -+#define PMCR_BACKOFF_EN BIT(9) -+#define PMCR_BACKPR_EN BIT(8) -+#define PMCR_TX_FC_EN BIT(5) -+#define PMCR_RX_FC_EN BIT(4) -+#define PMCR_FORCE_SPEED_1000 BIT(3) -+#define PMCR_FORCE_FDX BIT(1) -+#define PMCR_FORCE_LNK BIT(0) -+#define PMCR_COMMON_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ -+ PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ -+ PMCR_TX_EN | PMCR_RX_EN | \ -+ PMCR_TX_FC_EN | PMCR_RX_FC_EN) -+#define PMCR_CPUP_LINK (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \ -+ PMCR_FORCE_SPEED_1000 | \ -+ PMCR_FORCE_FDX | \ -+ PMCR_FORCE_LNK) -+#define PMCR_USERP_LINK PMCR_COMMON_LINK -+#define PMCR_FIXED_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ -+ PMCR_FORCE_MODE | PMCR_TX_EN | \ -+ PMCR_RX_EN | PMCR_BACKPR_EN | \ -+ PMCR_BACKOFF_EN | \ -+ PMCR_FORCE_SPEED_1000 | \ -+ PMCR_FORCE_FDX | \ -+ PMCR_FORCE_LNK) -+#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \ -+ PMCR_TX_FC_EN | PMCR_RX_FC_EN) -+ -+#define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100) -+ -+/* Register for MIB */ -+#define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100) -+#define MT7530_MIB_CCR 0x4fe0 -+#define CCR_MIB_ENABLE BIT(31) -+#define CCR_RX_OCT_CNT_GOOD BIT(7) -+#define CCR_RX_OCT_CNT_BAD BIT(6) -+#define CCR_TX_OCT_CNT_GOOD BIT(5) -+#define CCR_TX_OCT_CNT_BAD BIT(4) -+#define CCR_MIB_FLUSH (CCR_RX_OCT_CNT_GOOD | \ -+ CCR_RX_OCT_CNT_BAD | \ -+ CCR_TX_OCT_CNT_GOOD | \ -+ CCR_TX_OCT_CNT_BAD) -+#define CCR_MIB_ACTIVATE (CCR_MIB_ENABLE | \ -+ CCR_RX_OCT_CNT_GOOD | \ -+ CCR_RX_OCT_CNT_BAD | \ -+ CCR_TX_OCT_CNT_GOOD | \ -+ CCR_TX_OCT_CNT_BAD) -+/* Register for system reset */ -+#define MT7530_SYS_CTRL 0x7000 -+#define SYS_CTRL_PHY_RST BIT(2) -+#define SYS_CTRL_SW_RST BIT(1) -+#define SYS_CTRL_REG_RST BIT(0) -+ -+/* Register for hw trap status */ -+#define MT7530_HWTRAP 0x7800 -+ -+/* Register for hw trap modification */ -+#define MT7530_MHWTRAP 0x7804 -+#define MHWTRAP_MANUAL BIT(16) -+#define MHWTRAP_P5_MAC_SEL BIT(13) -+#define MHWTRAP_P6_DIS BIT(8) -+#define MHWTRAP_P5_RGMII_MODE BIT(7) -+#define MHWTRAP_P5_DIS BIT(6) -+#define MHWTRAP_PHY_ACCESS BIT(5) -+ -+/* Register for TOP signal control */ -+#define MT7530_TOP_SIG_CTRL 0x7808 -+#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) -+ -+#define MT7530_IO_DRV_CR 0x7810 -+#define P5_IO_CLK_DRV(x) ((x) & 0x3) -+#define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4) -+ -+#define MT7530_P6ECR 0x7830 -+#define P6_INTF_MODE_MASK 0x3 -+#define P6_INTF_MODE(x) ((x) & 0x3) -+ -+/* Registers for TRGMII on the both side */ -+#define MT7530_TRGMII_RCK_CTRL 0x7a00 -+#define GSW_TRGMII_RCK_CTRL 0x300 -+#define RX_RST BIT(31) -+#define RXC_DQSISEL BIT(30) -+#define DQSI1_TAP_MASK (0x7f << 8) -+#define DQSI0_TAP_MASK 0x7f -+#define DQSI1_TAP(x) (((x) & 0x7f) << 8) -+#define DQSI0_TAP(x) ((x) & 0x7f) -+ -+#define MT7530_TRGMII_RCK_RTT 0x7a04 -+#define GSW_TRGMII_RCK_RTT 0x304 -+#define DQS1_GATE BIT(31) -+#define DQS0_GATE BIT(30) -+ -+#define MT7530_TRGMII_RD(x) (0x7a10 + (x) * 8) -+#define GSW_TRGMII_RD(x) (0x310 + (x) * 8) -+#define BSLIP_EN BIT(31) -+#define EDGE_CHK BIT(30) -+#define RD_TAP_MASK 0x7f -+#define RD_TAP(x) ((x) & 0x7f) -+ -+#define GSW_TRGMII_TXCTRL 0x340 -+#define MT7530_TRGMII_TXCTRL 0x7a40 -+#define TRAIN_TXEN BIT(31) -+#define TXC_INV BIT(30) -+#define TX_RST BIT(28) -+ -+#define MT7530_TRGMII_TD_ODT(i) (0x7a54 + 8 * (i)) -+#define GSW_TRGMII_TD_ODT(i) (0x354 + 8 * (i)) -+#define TD_DM_DRVP(x) ((x) & 0xf) -+#define TD_DM_DRVN(x) (((x) & 0xf) << 4) -+ -+#define GSW_INTF_MODE 0x390 -+#define INTF_MODE_TRGMII BIT(1) -+ -+#define MT7530_TRGMII_TCK_CTRL 0x7a78 -+#define TCK_TAP(x) (((x) & 0xf) << 8) -+ -+#define MT7530_P5RGMIIRXCR 0x7b00 -+#define CSR_RGMII_EDGE_ALIGN BIT(8) -+#define CSR_RGMII_RXC_0DEG_CFG(x) ((x) & 0xf) -+ -+#define MT7530_P5RGMIITXCR 0x7b04 -+#define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f) -+ -+#define MT7530_CREV 0x7ffc -+#define CHIP_NAME_SHIFT 16 -+#define MT7530_ID 0x7530 -+ -+/* Registers for core PLL access through mmd indirect */ -+#define CORE_PLL_GROUP2 0x401 -+#define RG_SYSPLL_EN_NORMAL BIT(15) -+#define RG_SYSPLL_VODEN BIT(14) -+#define RG_SYSPLL_LF BIT(13) -+#define RG_SYSPLL_RST_DLY(x) (((x) & 0x3) << 12) -+#define RG_SYSPLL_LVROD_EN BIT(10) -+#define RG_SYSPLL_PREDIV(x) (((x) & 0x3) << 8) -+#define RG_SYSPLL_POSDIV(x) (((x) & 0x3) << 5) -+#define RG_SYSPLL_FBKSEL BIT(4) -+#define RT_SYSPLL_EN_AFE_OLT BIT(0) -+ -+#define CORE_PLL_GROUP4 0x403 -+#define RG_SYSPLL_DDSFBK_EN BIT(12) -+#define RG_SYSPLL_BIAS_EN BIT(11) -+#define RG_SYSPLL_BIAS_LPF_EN BIT(10) -+ -+#define CORE_PLL_GROUP5 0x404 -+#define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff) -+ -+#define CORE_PLL_GROUP6 0x405 -+#define RG_LCDDS_PCW_NCPO0(x) ((x) & 0xffff) -+ -+#define CORE_PLL_GROUP7 0x406 -+#define RG_LCDDS_PWDB BIT(15) -+#define RG_LCDDS_ISO_EN BIT(13) -+#define RG_LCCDS_C(x) (((x) & 0x7) << 4) -+#define RG_LCDDS_PCW_NCPO_CHG BIT(3) -+ -+#define CORE_PLL_GROUP10 0x409 -+#define RG_LCDDS_SSC_DELTA(x) ((x) & 0xfff) -+ -+#define CORE_PLL_GROUP11 0x40a -+#define RG_LCDDS_SSC_DELTA1(x) ((x) & 0xfff) -+ -+#define CORE_GSWPLL_GRP1 0x40d -+#define RG_GSWPLL_PREDIV(x) (((x) & 0x3) << 14) -+#define RG_GSWPLL_POSDIV_200M(x) (((x) & 0x3) << 12) -+#define RG_GSWPLL_EN_PRE BIT(11) -+#define RG_GSWPLL_FBKSEL BIT(10) -+#define RG_GSWPLL_BP BIT(9) -+#define RG_GSWPLL_BR BIT(8) -+#define RG_GSWPLL_FBKDIV_200M(x) ((x) & 0xff) -+ -+#define CORE_GSWPLL_GRP2 0x40e -+#define RG_GSWPLL_POSDIV_500M(x) (((x) & 0x3) << 8) -+#define RG_GSWPLL_FBKDIV_500M(x) ((x) & 0xff) -+ -+#define CORE_TRGMII_GSW_CLK_CG 0x410 -+#define REG_GSWCK_EN BIT(0) -+#define REG_TRGMIICK_EN BIT(1) -+ -+#define MIB_DESC(_s, _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+struct mt7530_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+struct mt7530_fdb { -+ u16 vid; -+ u8 port_mask; -+ u8 aging; -+ u8 mac[6]; -+ bool noarp; -+}; -+ -+struct mt7530_port { -+ bool enable; -+ u32 pm; -+}; -+ -+/* struct mt7530_priv - This is the main data structure for holding the state -+ * of the driver -+ * @dev: The device pointer -+ * @ds: The pointer to the dsa core structure -+ * @bus: The bus used for the device and built-in PHY -+ * @rstc: The pointer to reset control used by MCM -+ * @ethernet: The regmap used for access TRGMII-based registers -+ * @core_pwr: The power supplied into the core -+ * @io_pwr: The power supplied into the I/O -+ * @reset: The descriptor for GPIO line tied to its reset pin -+ * @mcm: Flag for distinguishing if standalone IC or module -+ * coupling -+ * @ports: Holding the state among ports -+ * @reg_mutex: The lock for protecting among process accessing -+ * registers -+ */ -+struct mt7530_priv { -+ struct device *dev; -+ struct dsa_switch *ds; -+ struct mii_bus *bus; -+ struct reset_control *rstc; -+ struct regmap *ethernet; -+ struct regulator *core_pwr; -+ struct regulator *io_pwr; -+ struct gpio_desc *reset; -+ bool mcm; -+ -+ struct mt7530_port ports[MT7530_NUM_PORTS]; -+ /* protect among processes for registers access*/ -+ struct mutex reg_mutex; -+}; -+ -+struct mt7530_hw_stats { -+ const char *string; -+ u16 reg; -+ u8 sizeof_stat; -+}; -+ -+#endif /* __MT7530_H */ diff --git a/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch deleted file mode 100644 index f69078cb4c..0000000000 --- a/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch +++ /dev/null @@ -1,92 +0,0 @@ ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc - int i; - - mutex_lock(&priv->reg_mutex); -+ priv->bridge_dev[port] = bridge; - - for (i = 0; i < MT7530_NUM_PORTS; i++) { - /* Add this port to the port matrix of the other ports in the -@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc - * and not being setup until the port becomes enabled. - */ - if (ds->enabled_port_mask & BIT(i) && i != port) { -- if (ds->ports[i].bridge_dev != bridge) -+ if (priv->bridge_dev[i] != bridge) - continue; - if (priv->ports[i].enable) - mt7530_set(priv, MT7530_PCR_P(i), -@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc - } - - static void --mt7530_port_bridge_leave(struct dsa_switch *ds, int port, -- struct net_device *bridge) -+mt7530_port_bridge_leave(struct dsa_switch *ds, int port) - { - struct mt7530_priv *priv = ds->priv; - int i; -@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit - * is kept and not being setup until the port becomes enabled. - */ - if (ds->enabled_port_mask & BIT(i) && i != port) { -- if (ds->ports[i].bridge_dev != bridge) -+ if (priv->bridge_dev[i] != priv->bridge_dev[port]) - continue; - if (priv->ports[i].enable) - mt7530_clear(priv, MT7530_PCR_P(i), -@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit - /* Set the cpu port to be the only one in the port matrix of - * this port. - */ -+ priv->bridge_dev[port] = NULL; - if (priv->ports[port].enable) - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, - PCR_MATRIX(BIT(MT7530_CPU_PORT))); -@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev - if (!priv) - return -ENOMEM; - -- priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); -+ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); - if (!priv->ds) - return -ENOMEM; - -@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev - priv->bus = mdiodev->bus; - priv->dev = &mdiodev->dev; - priv->ds->priv = priv; -+ priv->ds->dev = &mdiodev->dev; - priv->ds->ops = &mt7530_switch_ops; - mutex_init(&priv->reg_mutex); - lpriv = priv; - dev_set_drvdata(&mdiodev->dev, priv); - -- return dsa_register_switch(priv->ds, &mdiodev->dev); -+ return dsa_register_switch(priv->ds, priv->ds->dev->of_node); - } - - static void ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -379,6 +379,8 @@ struct mt7530_priv { - struct mt7530_port ports[MT7530_NUM_PORTS]; - /* protect among processes for registers access*/ - struct mutex reg_mutex; -+ -+ struct net_device *bridge_dev[MT7530_NUM_PORTS]; - }; - - struct mt7530_hw_stats { ---- a/net/dsa/tag_mtk.c -+++ b/net/dsa/tag_mtk.c -@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru - /* Build the tag after the MAC Source Address */ - mtk_tag = skb->data + 2 * ETH_ALEN; - mtk_tag[0] = 0; -- mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; -+ mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK; - mtk_tag[2] = 0; - mtk_tag[3] = 0; - diff --git a/target/linux/mediatek/patches-4.9/0094-net-affinity.patch b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch deleted file mode 100644 index 0c468fbceb..0000000000 --- a/target/linux/mediatek/patches-4.9/0094-net-affinity.patch +++ /dev/null @@ -1,36 +0,0 @@ ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2459,15 +2459,23 @@ static int mtk_probe(struct platform_dev - goto err_deinit_hw; - } - -+ for (i = 0; i < 3; i++) { -+ int cpu = i % num_online_cpus(); -+ -+ cpumask_set_cpu(cpu, ð->affinity_mask[i]); -+ } -+ - err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, - dev_name(eth->dev), eth); - if (err) - goto err_free_dev; -+ irq_set_affinity_hint(eth->irq[1], ð->affinity_mask[1]); - - err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, - dev_name(eth->dev), eth); - if (err) - goto err_free_dev; -+ irq_set_affinity_hint(eth->irq[2], ð->affinity_mask[2]); - - err = mtk_mdio_init(eth); - if (err) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -539,6 +539,7 @@ struct mtk_eth { - struct net_device *netdev[MTK_MAX_DEVS]; - struct mtk_mac *mac[MTK_MAX_DEVS]; - int irq[3]; -+ cpumask_t affinity_mask[3]; - u32 msg_enable; - unsigned long sysclk; - struct regmap *ethsys; diff --git a/target/linux/mediatek/patches-4.9/0095-ephy.patch b/target/linux/mediatek/patches-4.9/0095-ephy.patch deleted file mode 100644 index dc88ca2ccd..0000000000 --- a/target/linux/mediatek/patches-4.9/0095-ephy.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -629,6 +629,11 @@ mt7530_setup(struct dsa_switch *ds) - val = mt7530_read(priv, MT7530_MHWTRAP); - val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; - val |= MHWTRAP_MANUAL; -+ if (!dsa_is_cpu_port(ds, 5)) { -+ val |= MHWTRAP_P5_DIS; -+ val |= MHWTRAP_P5_MAC_SEL; -+ val |= MHWTRAP_P5_RGMII_MODE; -+ } - mt7530_write(priv, MT7530_MHWTRAP, val); - - /* Enable and reset MIB counters */ ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -221,6 +221,9 @@ static void mtk_phy_link_adjust(struct n - netif_carrier_on(dev); - else - netif_carrier_off(dev); -+ -+ if (!of_phy_is_fixed_link(mac->of_node)) -+ phy_print_status(dev->phydev); - } - - static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, diff --git a/target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch b/target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch deleted file mode 100644 index 6394e14412..0000000000 --- a/target/linux/mediatek/patches-4.9/0096-dsa-multi-cpu.patch +++ /dev/null @@ -1,258 +0,0 @@ ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -996,15 +996,7 @@ err: - static enum dsa_tag_protocol - mtk_get_tag_protocol(struct dsa_switch *ds) - { -- struct mt7530_priv *priv = ds->priv; -- -- if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { -- dev_warn(priv->dev, -- "port not matched with tagging CPU port\n"); -- return DSA_TAG_PROTO_NONE; -- } else { -- return DSA_TAG_PROTO_MTK; -- } -+ return DSA_TAG_PROTO_MTK; - } - - static struct dsa_switch_ops mt7530_switch_ops = { ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -145,6 +145,8 @@ struct dsa_port { - struct device_node *dn; - unsigned int ageing_time; - u8 stp_state; -+ struct net_device *ethernet; -+ int upstream; - }; - - struct dsa_switch { -@@ -205,7 +207,7 @@ struct dsa_switch { - - static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) - { -- return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); -+ return !!(ds->cpu_port_mask & (1 << p)); - } - - static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p) -@@ -218,6 +220,11 @@ static inline bool dsa_is_port_initializ - return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; - } - -+static inline bool dsa_is_upstream_port(struct dsa_switch *ds, int p) -+{ -+ return dsa_is_cpu_port(ds, p) || dsa_is_dsa_port(ds, p); -+} -+ - static inline u8 dsa_upstream_port(struct dsa_switch *ds) - { - struct dsa_switch_tree *dst = ds->dst; -@@ -234,6 +241,18 @@ static inline u8 dsa_upstream_port(struc - return ds->rtable[dst->cpu_switch]; - } - -+static inline u8 dsa_port_upstream_port(struct dsa_switch *ds, int port) -+{ -+ /* -+ * If this port has a specific upstream cpu port, use it, -+ * otherwise use the switch default. -+ */ -+ if (ds->ports[port].upstream) -+ return ds->ports[port].upstream; -+ else -+ return dsa_upstream_port(ds); -+} -+ - struct switchdev_trans; - struct switchdev_obj; - struct switchdev_obj_port_fdb; ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -248,8 +248,6 @@ static int dsa_cpu_port_apply(struct dev - return err; - } - -- ds->cpu_port_mask |= BIT(index); -- - return 0; - } - -@@ -259,6 +257,10 @@ static void dsa_cpu_port_unapply(struct - dsa_cpu_dsa_destroy(port); - ds->cpu_port_mask &= ~BIT(index); - -+ if (ds->ports[index].ethernet) { -+ dev_put(ds->ports[index].ethernet); -+ ds->ports[index].ethernet = NULL; -+ } - } - - static int dsa_user_port_apply(struct device_node *port, u32 index, -@@ -479,6 +481,29 @@ static int dsa_cpu_parse(struct device_n - - dst->rcv = dst->tag_ops->rcv; - -+ dev_hold(ethernet_dev); -+ ds->ports[index].ethernet = ethernet_dev; -+ ds->cpu_port_mask |= BIT(index); -+ -+ return 0; -+} -+ -+static int dsa_user_parse(struct device_node *port, u32 index, -+ struct dsa_switch *ds) -+{ -+ struct device_node *cpu_port; -+ const unsigned int *cpu_port_reg; -+ int cpu_port_index; -+ -+ cpu_port = of_parse_phandle(port, "cpu", 0); -+ if (cpu_port) { -+ cpu_port_reg = of_get_property(cpu_port, "reg", NULL); -+ if (!cpu_port_reg) -+ return -EINVAL; -+ cpu_port_index = be32_to_cpup(cpu_port_reg); -+ ds->ports[index].upstream = cpu_port_index; -+ } -+ - return 0; - } - -@@ -486,18 +511,19 @@ static int dsa_ds_parse(struct dsa_switc - { - struct device_node *port; - u32 index; -- int err; -+ int err = 0; - - for (index = 0; index < DSA_MAX_PORTS; index++) { - port = ds->ports[index].dn; - if (!port) - continue; - -- if (dsa_port_is_cpu(port)) { -+ if (dsa_port_is_cpu(port)) - err = dsa_cpu_parse(port, index, dst, ds); -- if (err) -- return err; -- } -+ else if (!dsa_port_is_dsa(port)) -+ err = dsa_user_parse(port, index, ds); -+ if (err) -+ return err; - } - - pr_info("DSA: switch %d %d parsed\n", dst->tree, ds->index); ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -43,6 +43,7 @@ struct dsa_slave_priv { - int old_duplex; - - struct net_device *bridge_dev; -+ struct net_device *master; - #ifdef CONFIG_NET_POLL_CONTROLLER - struct netpoll *netpoll; - #endif ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -61,7 +61,7 @@ static int dsa_slave_get_iflink(const st - { - struct dsa_slave_priv *p = netdev_priv(dev); - -- return p->parent->dst->master_netdev->ifindex; -+ return p->master->ifindex; - } - - static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) -@@ -96,7 +96,7 @@ static void dsa_port_set_stp_state(struc - static int dsa_slave_open(struct net_device *dev) - { - struct dsa_slave_priv *p = netdev_priv(dev); -- struct net_device *master = p->parent->dst->master_netdev; -+ struct net_device *master = p->master; - struct dsa_switch *ds = p->parent; - u8 stp_state = dsa_port_is_bridged(p) ? - BR_STATE_BLOCKING : BR_STATE_FORWARDING; -@@ -151,7 +151,7 @@ out: - static int dsa_slave_close(struct net_device *dev) - { - struct dsa_slave_priv *p = netdev_priv(dev); -- struct net_device *master = p->parent->dst->master_netdev; -+ struct net_device *master = p->master; - struct dsa_switch *ds = p->parent; - - if (p->phy) -@@ -178,7 +178,7 @@ static int dsa_slave_close(struct net_de - static void dsa_slave_change_rx_flags(struct net_device *dev, int change) - { - struct dsa_slave_priv *p = netdev_priv(dev); -- struct net_device *master = p->parent->dst->master_netdev; -+ struct net_device *master = p->master; - - if (change & IFF_ALLMULTI) - dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); -@@ -189,7 +189,7 @@ static void dsa_slave_change_rx_flags(st - static void dsa_slave_set_rx_mode(struct net_device *dev) - { - struct dsa_slave_priv *p = netdev_priv(dev); -- struct net_device *master = p->parent->dst->master_netdev; -+ struct net_device *master = p->master; - - dev_mc_sync(master, dev); - dev_uc_sync(master, dev); -@@ -198,7 +198,7 @@ static void dsa_slave_set_rx_mode(struct - static int dsa_slave_set_mac_address(struct net_device *dev, void *a) - { - struct dsa_slave_priv *p = netdev_priv(dev); -- struct net_device *master = p->parent->dst->master_netdev; -+ struct net_device *master = p->master; - struct sockaddr *addr = a; - int err; - -@@ -633,7 +633,7 @@ static netdev_tx_t dsa_slave_xmit(struct - /* Queue the SKB for transmission on the parent interface, but - * do not modify its EtherType - */ -- nskb->dev = p->parent->dst->master_netdev; -+ nskb->dev = p->master; - dev_queue_xmit(nskb); - - return NETDEV_TX_OK; -@@ -945,7 +945,7 @@ static int dsa_slave_netpoll_setup(struc - { - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->parent; -- struct net_device *master = ds->dst->master_netdev; -+ struct net_device *master = p->master; - struct netpoll *netpoll; - int err = 0; - -@@ -1233,11 +1233,16 @@ int dsa_slave_create(struct dsa_switch * - struct net_device *master; - struct net_device *slave_dev; - struct dsa_slave_priv *p; -+ int port_cpu = ds->ports[port].upstream; - int ret; - -- master = ds->dst->master_netdev; -- if (ds->master_netdev) -+ if (port_cpu && ds->ports[port_cpu].ethernet) -+ master = ds->ports[port_cpu].ethernet; -+ else if (ds->master_netdev) - master = ds->master_netdev; -+ else -+ master = ds->dst->master_netdev; -+ master->dsa_ptr = (void *)ds->dst; - - slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), name, - NET_NAME_UNKNOWN, ether_setup); -@@ -1263,6 +1268,7 @@ int dsa_slave_create(struct dsa_switch * - p->parent = ds; - p->port = port; - p->xmit = dst->tag_ops->xmit; -+ p->master = master; - - p->old_pause = -1; - p->old_link = -1; diff --git a/target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch b/target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch deleted file mode 100644 index 26eff60003..0000000000 --- a/target/linux/mediatek/patches-4.9/0097-dsa-mt7530.patch +++ /dev/null @@ -1,81 +0,0 @@ ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -627,7 +627,7 @@ mt7530_setup(struct dsa_switch *ds) - - /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ - val = mt7530_read(priv, MT7530_MHWTRAP); -- val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; -+ val &= ~MHWTRAP_P5_DIS & ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; - val |= MHWTRAP_MANUAL; - if (!dsa_is_cpu_port(ds, 5)) { - val |= MHWTRAP_P5_DIS; -@@ -735,6 +735,9 @@ static int - mt7530_cpu_port_enable(struct mt7530_priv *priv, - int port) - { -+ u8 port_mask = 0; -+ int i; -+ - /* Enable Mediatek header mode on the cpu port */ - mt7530_write(priv, MT7530_PVC_P(port), - PORT_SPEC_TAG); -@@ -751,8 +754,12 @@ mt7530_cpu_port_enable(struct mt7530_pri - /* CPU port gets connected to all user ports of - * the switch - */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ if ((priv->ds->enabled_port_mask & BIT(i)) && -+ (dsa_port_upstream_port(priv->ds, i) == port)) -+ port_mask |= BIT(i); - mt7530_write(priv, MT7530_PCR_P(port), -- PCR_MATRIX(priv->ds->enabled_port_mask)); -+ PCR_MATRIX(port_mask)); - - return 0; - } -@@ -762,6 +769,7 @@ mt7530_port_enable(struct dsa_switch *ds - struct phy_device *phy) - { - struct mt7530_priv *priv = ds->priv; -+ u8 upstream = dsa_port_upstream_port(ds, port); - - mutex_lock(&priv->reg_mutex); - -@@ -772,7 +780,7 @@ mt7530_port_enable(struct dsa_switch *ds - * restore the port matrix if the port is the member of a certain - * bridge. - */ -- priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ priv->ports[port].pm |= PCR_MATRIX(BIT(upstream)); - priv->ports[port].enable = true; - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, - priv->ports[port].pm); -@@ -835,7 +843,8 @@ mt7530_port_bridge_join(struct dsa_switc - struct net_device *bridge) - { - struct mt7530_priv *priv = ds->priv; -- u32 port_bitmap = BIT(MT7530_CPU_PORT); -+ u8 upstream = dsa_port_upstream_port(ds, port); -+ u32 port_bitmap = BIT(upstream); - int i; - - mutex_lock(&priv->reg_mutex); -@@ -873,6 +882,7 @@ static void - mt7530_port_bridge_leave(struct dsa_switch *ds, int port) - { - struct mt7530_priv *priv = ds->priv; -+ u8 upstream = dsa_port_upstream_port(ds, port); - int i; - - mutex_lock(&priv->reg_mutex); -@@ -898,8 +908,8 @@ mt7530_port_bridge_leave(struct dsa_swit - priv->bridge_dev[port] = NULL; - if (priv->ports[port].enable) - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, -- PCR_MATRIX(BIT(MT7530_CPU_PORT))); -- priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ PCR_MATRIX(BIT(upstream))); -+ priv->ports[port].pm = PCR_MATRIX(BIT(upstream)); - - mutex_unlock(&priv->reg_mutex); - } diff --git a/target/linux/mediatek/patches-4.9/0103-nand_fixes.patch b/target/linux/mediatek/patches-4.9/0103-nand_fixes.patch deleted file mode 100644 index 874661db3e..0000000000 --- a/target/linux/mediatek/patches-4.9/0103-nand_fixes.patch +++ /dev/null @@ -1,22 +0,0 @@ ---- a/drivers/mtd/nand/mtk_nand.c -+++ b/drivers/mtd/nand/mtk_nand.c -@@ -1073,8 +1073,8 @@ static int mtk_nfc_ooblayout_free(struct - if (section >= eccsteps) - return -ERANGE; - -- oob_region->length = fdm->reg_size - fdm->ecc_size; -- oob_region->offset = section * fdm->reg_size + fdm->ecc_size; -+ oob_region->length = fdm->reg_size - 1; -+ oob_region->offset = section * fdm->reg_size + 1; - - return 0; - } -@@ -1114,7 +1114,7 @@ static void mtk_nfc_set_fdm(struct mtk_n - fdm->reg_size = NFI_FDM_MAX_SIZE; - - /* bad block mark storage */ -- fdm->ecc_size = 1; -+ fdm->ecc_size = fdm->reg_size; - } - - static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl, diff --git a/target/linux/mediatek/patches-4.9/0200-devicetree.patch b/target/linux/mediatek/patches-4.9/0200-devicetree.patch deleted file mode 100644 index 4eca20a7bd..0000000000 --- a/target/linux/mediatek/patches-4.9/0200-devicetree.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -950,6 +950,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ - mt6589-aquaris5.dtb \ - mt6592-evb.dtb \ - mt7623-evb.dtb \ -+ mt7623-eMMC.dtb \ -+ mt7623-NAND.dtb \ -+ mt7623-NAND-ePHY.dtb \ - mt8127-moose.dtb \ - mt8135-evbp1.dtb - dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb diff --git a/target/linux/mediatek/patches-4.9/0201-block2mtd.patch b/target/linux/mediatek/patches-4.9/0201-block2mtd.patch deleted file mode 100644 index 395884b730..0000000000 --- a/target/linux/mediatek/patches-4.9/0201-block2mtd.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- a/drivers/mtd/devices/block2mtd.c -+++ b/drivers/mtd/devices/block2mtd.c -@@ -32,6 +32,8 @@ - #include - #include - -+static const char * const block2mtd_probe_types[] = { "cmdlinepart", NULL }; -+ - /* Info for the block device */ - struct block2mtd_dev { - struct list_head list; -@@ -227,6 +229,7 @@ static struct block2mtd_dev *add_device( - #endif - const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev = ERR_PTR(-ENODEV); -+ struct mtd_part_parser_data ppdata = { 0 }; - struct block2mtd_dev *dev; - struct mtd_partition *part; - char *name; -@@ -307,11 +310,7 @@ static struct block2mtd_dev *add_device( - dev->mtd.priv = dev; - dev->mtd.owner = THIS_MODULE; - -- part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); -- part->name = name; -- part->offset = 0; -- part->size = dev->mtd.size; -- if (mtd_device_register(&dev->mtd, part, 1)) { -+ if (mtd_device_parse_register(&dev->mtd, block2mtd_probe_types, &ppdata, NULL, 0)) { - /* Device didn't get added, so free the entry */ - goto err_destroy_mutex; - }