From: John Crispin Date: Fri, 1 Apr 2016 07:11:18 +0000 (+0000) Subject: mediatek: update patches X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=3f4018aed0bee258b9f1f09828cc033eaaf43e2d;p=openwrt%2Fsvn-archive%2Farchive.git mediatek: update patches add fixes for * ethernet * cpufreq * nand * a7-timer Signed-off-by: John Crispin SVN-Revision: 49098 --- diff --git a/target/linux/mediatek/config-4.4 b/target/linux/mediatek/config-4.4 index f9d5d06765..4ebfe4d4a5 100644 --- a/target/linux/mediatek/config-4.4 +++ b/target/linux/mediatek/config-4.4 @@ -27,6 +27,8 @@ CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y CONFIG_ARM=y CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y # CONFIG_ARM_ATAG_DTB_COMPAT is not set CONFIG_ARM_CPU_SUSPEND=y # CONFIG_ARM_CPU_TOPOLOGY is not set @@ -35,6 +37,7 @@ CONFIG_ARM_HAS_SG_CHAIN=y CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_L1_CACHE_SHIFT_6=y # CONFIG_ARM_LPAE is not set +CONFIG_ARM_MT7623_CPUFREQ=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_SMMU is not set CONFIG_ARM_THUMB=y @@ -65,6 +68,7 @@ CONFIG_COMMON_CLK_MT2701=y # CONFIG_COMMON_CLK_MT8173 is not set CONFIG_COMPACTION=y CONFIG_COREDUMP=y +# CONFIG_CPUFREQ_DT is not set CONFIG_CPU_32v6K=y CONFIG_CPU_32v7=y CONFIG_CPU_ABRT_EV7=y @@ -74,11 +78,21 @@ CONFIG_CPU_CACHE_VIPT=y CONFIG_CPU_COPY_V6=y CONFIG_CPU_CP15=y CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_HAS_ASID=y # CONFIG_CPU_ICACHE_DISABLE is not set CONFIG_CPU_PABRT_V7=y CONFIG_CPU_PM=y CONFIG_CPU_RMAP=y +# CONFIG_CPU_THERMAL is not set CONFIG_CPU_TLB_V7=y CONFIG_CPU_V7=y CONFIG_CRC16=y @@ -168,6 +182,7 @@ CONFIG_HAVE_ARCH_KGDB=y CONFIG_HAVE_ARCH_PFN_VALID=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARM_ARCH_TIMER=y # CONFIG_HAVE_BOOTMEM_INFO_NODE is not set CONFIG_HAVE_BPF_JIT=y CONFIG_HAVE_CC_STACKPROTECTOR=y @@ -375,6 +390,7 @@ CONFIG_PM_CLK=y CONFIG_PM_GENERIC_DOMAINS=y CONFIG_PM_GENERIC_DOMAINS_OF=y CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_OPP=y CONFIG_PM_SLEEP=y CONFIG_PM_SLEEP_SMP=y CONFIG_POWER_RESET=y diff --git a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch index 239e434dbb..007c03c688 100644 --- a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch +++ b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch @@ -1,7 +1,7 @@ From c30a296646a42302065ba452abe95b0b4b550883 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 27 Jul 2014 09:38:50 +0100 -Subject: [PATCH 01/66] NET: multi phy support +Subject: [PATCH 01/78] NET: multi phy support Signed-off-by: John Crispin --- diff --git a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch index f99496ae62..b0e4d29931 100644 --- a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch +++ b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch @@ -1,7 +1,7 @@ From 2c93328ed05061a50e3bd4111379dbcf6946d3ac Mon Sep 17 00:00:00 2001 From: James Liao Date: Wed, 30 Dec 2015 14:41:43 +0800 -Subject: [PATCH 02/66] soc: mediatek: Separate scpsys driver common code +Subject: [PATCH 02/78] soc: mediatek: Separate scpsys driver common code Separate scpsys driver common code to mtk-scpsys.c, and move MT8173 platform code to mtk-scpsys-mt8173.c. diff --git a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch index 0fc766cada..7d77391cc5 100644 --- a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch +++ b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch @@ -1,7 +1,7 @@ From c359272f86805259c5801385d60fdeea9d629cf9 Mon Sep 17 00:00:00 2001 From: James Liao Date: Wed, 30 Dec 2015 14:41:44 +0800 -Subject: [PATCH 03/66] soc: mediatek: Init MT8173 scpsys driver earlier +Subject: [PATCH 03/78] soc: mediatek: Init MT8173 scpsys driver earlier Some power domain comsumers may init before module_init. So the power domain provider (scpsys) need to be initialized diff --git a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch index 1b45c44161..c0bb55bf9a 100644 --- a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch +++ b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch @@ -1,7 +1,7 @@ From f371844374fff273f817d6c43f679606417af59e Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Wed, 30 Dec 2015 14:41:45 +0800 -Subject: [PATCH 04/66] soc: mediatek: Add MT2701 power dt-bindings +Subject: [PATCH 04/78] soc: mediatek: Add MT2701 power dt-bindings Add power dt-bindings for MT2701. diff --git a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch index 505292e6a6..b2527b4772 100644 --- a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch +++ b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch @@ -1,7 +1,7 @@ From c6711565985f359d7d3c05f01f081e4c216902de Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Wed, 30 Dec 2015 14:41:46 +0800 -Subject: [PATCH 05/66] soc: mediatek: Add MT2701/MT7623 scpsys driver +Subject: [PATCH 05/78] soc: mediatek: Add MT2701/MT7623 scpsys driver Add scpsys driver for MT2701 and MT7623. diff --git a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch index e02b7a546b..5ac02deea4 100644 --- a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch +++ b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch @@ -1,7 +1,7 @@ From 0c39bcd17fa6ce723f56ad3756b4bb36c4690342 Mon Sep 17 00:00:00 2001 From: James Liao Date: Tue, 5 Jan 2016 14:30:17 +0800 -Subject: [PATCH 06/66] clk: mediatek: Refine the makefile to support multiple +Subject: [PATCH 06/78] clk: mediatek: Refine the makefile to support multiple clock drivers Add a Kconfig to define clock configuration for each SoC, and diff --git a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch index c562647e36..382699995b 100644 --- a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch +++ b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch @@ -1,7 +1,7 @@ From d7e96f87f66c571e9f4171ecd89c656fbd2de89b Mon Sep 17 00:00:00 2001 From: James Liao Date: Tue, 5 Jan 2016 14:30:18 +0800 -Subject: [PATCH 07/66] dt-bindings: ARM: Mediatek: Document bindings for +Subject: [PATCH 07/78] dt-bindings: ARM: Mediatek: Document bindings for MT2701 This patch adds the binding documentation for apmixedsys, bdpsys, diff --git a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch index 6e80e1adc4..f88cd18a1e 100644 --- a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch +++ b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch @@ -1,7 +1,7 @@ From 2fcbc15da2f13164e0851b9c7fae290249f0b44d Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 5 Jan 2016 14:30:19 +0800 -Subject: [PATCH 08/66] clk: mediatek: Add dt-bindings for MT2701 clocks +Subject: [PATCH 08/78] clk: mediatek: Add dt-bindings for MT2701 clocks Add MT2701 clock dt-bindings, include topckgen, apmixedsys, infracfg, pericfg and subsystem clocks. diff --git a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch index e2bb10dedd..7256eab494 100644 --- a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch +++ b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch @@ -1,7 +1,7 @@ From f2c07eaa2df52f9acac9ffc3457d3d81079dd723 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 5 Jan 2016 14:30:20 +0800 -Subject: [PATCH 09/66] clk: mediatek: Add MT2701 clock support +Subject: [PATCH 09/78] clk: mediatek: Add MT2701 clock support Add MT2701 clock support, include topckgen, apmixedsys, infracfg, pericfg and subsystem clocks. diff --git a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch index bb4eb5b84f..4e3686bb62 100644 --- a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch +++ b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch @@ -1,7 +1,7 @@ From 8d134cbe750b59d15c591622d81e2e9daa09f0c4 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 5 Jan 2016 14:30:21 +0800 -Subject: [PATCH 10/66] reset: mediatek: mt2701 reset controller dt-binding +Subject: [PATCH 10/78] reset: mediatek: mt2701 reset controller dt-binding file Dt-binding file about reset controller is used to provide diff --git a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch index fc1a35ac7d..7f4d066ca4 100644 --- a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch +++ b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch @@ -1,7 +1,7 @@ From b86d3303db25a8296e4c3de46ee1470f60f71b0c Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 5 Jan 2016 14:30:22 +0800 -Subject: [PATCH 11/66] reset: mediatek: mt2701 reset driver +Subject: [PATCH 11/78] reset: mediatek: mt2701 reset driver In infrasys and perifsys, there are many reset control bits for kinds of modules. These bits are diff --git a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch index 6c7632ee9f..1c52c15732 100644 --- a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch +++ b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch @@ -1,7 +1,7 @@ From 3b5df542d52b13a1b20d25311fa4c4029a3b83af Mon Sep 17 00:00:00 2001 From: Erin Lo Date: Mon, 28 Dec 2015 15:09:02 +0800 -Subject: [PATCH 12/66] ARM: mediatek: Add MT2701 config options for mediatek +Subject: [PATCH 12/78] ARM: mediatek: Add MT2701 config options for mediatek SoCs. The upcoming MTK pinctrl driver have a big pin table for each SoC diff --git a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch index 11f2cf9ea9..715ca08397 100644 --- a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch +++ b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch @@ -1,7 +1,7 @@ From 1a254735cad9db5c8605c972b0f16b3929dc0d6e Mon Sep 17 00:00:00 2001 From: Biao Huang Date: Mon, 28 Dec 2015 15:09:03 +0800 -Subject: [PATCH 13/66] dt-bindings: mediatek: Modify pinctrl bindings for +Subject: [PATCH 13/78] dt-bindings: mediatek: Modify pinctrl bindings for mt2701 Signed-off-by: Biao Huang diff --git a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch index 58de1fe217..e97ddb1300 100644 --- a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch +++ b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch @@ -1,7 +1,7 @@ From 416720ba33d4fd7d3166c17be7c13651cc08d408 Mon Sep 17 00:00:00 2001 From: Biao Huang Date: Mon, 28 Dec 2015 15:09:04 +0800 -Subject: [PATCH 14/66] pinctrl: dt bindings: Add pinfunc header file for +Subject: [PATCH 14/78] pinctrl: dt bindings: Add pinfunc header file for mt2701 Add pinfunc header file, mt2701 related dts will include it diff --git a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch index 974f39ea3a..4cae264eae 100644 --- a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch +++ b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch @@ -1,7 +1,7 @@ From ddc72b659b3642d0496dee4e1ee39416ca008053 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 7 Jan 2016 23:42:06 +0100 -Subject: [PATCH 15/66] dt-bindings: mediatek: Modify pinctrl bindings for +Subject: [PATCH 15/78] dt-bindings: mediatek: Modify pinctrl bindings for mt7623 Signed-off-by: John Crispin diff --git a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch index fca1fab9f3..299be7c962 100644 --- a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch +++ b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch @@ -1,7 +1,7 @@ From 1255eaacd6cc9d1fa6bb33185380efed22008baf Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sat, 27 Jun 2015 13:13:05 +0200 -Subject: [PATCH 16/66] pinctrl: dt bindings: Add pinctrl file for mt7623 +Subject: [PATCH 16/78] pinctrl: dt bindings: Add pinctrl file for mt7623 Add the driver and header files required to make pinctrl work on MediaTek MT7623. diff --git a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch index 685a496f85..f2f1c19ba6 100644 --- a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch +++ b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch @@ -1,7 +1,7 @@ From 294cf90337d70ad74edf147180bbeef837298bd0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 6 Jan 2016 20:06:49 +0100 -Subject: [PATCH 17/66] clk: add hifsys reset +Subject: [PATCH 17/78] clk: add hifsys reset Hi, diff --git a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch index 216d388572..6f64c709ea 100644 --- a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch +++ b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch @@ -1,7 +1,7 @@ From 84d37aeef94deae3ce87e677f6016a5d980429e8 Mon Sep 17 00:00:00 2001 From: "chunfeng.yun@mediatek.com" Date: Tue, 17 Nov 2015 17:18:39 +0800 -Subject: [PATCH 18/66] dt-bindings: Add a binding for Mediatek xHCI host +Subject: [PATCH 18/78] dt-bindings: Add a binding for Mediatek xHCI host controller add a DT binding documentation of xHCI host controller for the diff --git a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch index 188728d779..29a6b45355 100644 --- a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch +++ b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch @@ -1,7 +1,7 @@ From 651d8fff94718c7e48b8a40d7774878eb8ed62ee Mon Sep 17 00:00:00 2001 From: "chunfeng.yun@mediatek.com" Date: Tue, 17 Nov 2015 17:18:40 +0800 -Subject: [PATCH 19/66] xhci: mediatek: support MTK xHCI host controller +Subject: [PATCH 19/78] xhci: mediatek: support MTK xHCI host controller There some vendor quirks for MTK xhci host controller: 1. It defines some extra SW scheduling parameters for HW diff --git a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch index e9ce56e3af..33d68085fb 100644 --- a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch +++ b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch @@ -1,7 +1,7 @@ From 31a22fbd0d3b187be61c4c5d22b19c95abb327c3 Mon Sep 17 00:00:00 2001 From: "chunfeng.yun@mediatek.com" Date: Tue, 17 Nov 2015 17:18:41 +0800 -Subject: [PATCH 20/66] arm64: dts: mediatek: add xHCI & usb phy for mt8173 +Subject: [PATCH 20/78] arm64: dts: mediatek: add xHCI & usb phy for mt8173 add xHCI and phy drivers for MT8173-EVB diff --git a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch index b7aae926c8..61b0aa4ac2 100644 --- a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch +++ b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch @@ -1,7 +1,7 @@ From 162deec293400cb132161606629654acaec7cb4b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Jan 2016 12:13:54 +0100 -Subject: [PATCH 21/66] Document: DT: Add bindings for mediatek MT7623 SoC +Subject: [PATCH 21/78] Document: DT: Add bindings for mediatek MT7623 SoC Platform This adds a DT binding documentation for the MT7623 SoC from Mediatek. diff --git a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch index eefbffdf41..36aea67ed7 100644 --- a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch +++ b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch @@ -1,7 +1,7 @@ From fa5d94d6b4b314f751b1c32bb5a87a80b866d05e Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Jan 2016 16:52:31 +0100 -Subject: [PATCH 22/66] soc: mediatek: add compat string for mt7623 to scpsys +Subject: [PATCH 22/78] soc: mediatek: add compat string for mt7623 to scpsys Signed-off-by: John Crispin --- diff --git a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch index af0a68f213..b25c91bee8 100644 --- a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch +++ b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch @@ -1,7 +1,7 @@ -From cfe366d7a20f88c7fc92faaf8b25c24e730bd40b Mon Sep 17 00:00:00 2001 +From a4df3e7e4e906a4e9dac1f8c43f6192f22ef6242 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Jan 2016 12:16:17 +0100 -Subject: [PATCH 23/66] ARM: dts: mediatek: add MT7623 basic support +Subject: [PATCH 23/78] ARM: dts: mediatek: add MT7623 basic support This adds basic chip support for Mediatek MT7623. @@ -9,16 +9,18 @@ Signed-off-by: John Crispin --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/mt7623-evb.dts | 459 +++++++++++++++++++++++++++++++++ - arch/arm/boot/dts/mt7623.dtsi | 507 +++++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/mt7623.dtsi | 510 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-mediatek/Kconfig | 4 + arch/arm/mach-mediatek/mediatek.c | 1 + - 5 files changed, 972 insertions(+) + 5 files changed, 975 insertions(+) create mode 100644 arch/arm/boot/dts/mt7623-evb.dts create mode 100644 arch/arm/boot/dts/mt7623.dtsi +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 30bbc37..2bce370 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -774,6 +774,7 @@ +@@ -774,6 +774,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ mt6580-evbp1.dtb \ mt6589-aquaris5.dtb \ mt6592-evb.dtb \ @@ -26,6 +28,9 @@ Signed-off-by: John Crispin mt8127-moose.dtb \ mt8135-evbp1.dtb dtb-$(CONFIG_ARCH_ZX) += zx296702-ad1.dtb +diff --git a/arch/arm/boot/dts/mt7623-evb.dts b/arch/arm/boot/dts/mt7623-evb.dts +new file mode 100644 +index 0000000..5e9381d --- /dev/null +++ b/arch/arm/boot/dts/mt7623-evb.dts @@ -0,0 +1,459 @@ @@ -488,9 +493,12 @@ Signed-off-by: John Crispin + mediatek,reset-pin = <&pio 15 0>; + status = "okay"; +}; +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +new file mode 100644 +index 0000000..c53c10d --- /dev/null +++ b/arch/arm/boot/dts/mt7623.dtsi -@@ -0,0 +1,508 @@ +@@ -0,0 +1,510 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: John Crispin @@ -947,7 +955,9 @@ Signed-off-by: John Crispin + + clocks = <&topckgen CLK_TOP_ETHIF_SEL>; + clock-names = "ethif"; -+ interrupts = ; ++ interrupts = ; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + + mediatek,ethsys = <ðsys>; @@ -999,9 +1009,11 @@ Signed-off-by: John Crispin + status = "disabled"; + }; +}; +diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig +index 37dd438..7fb605e 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig -@@ -21,6 +21,10 @@ +@@ -21,6 +21,10 @@ config MACH_MT6592 bool "MediaTek MT6592 SoCs support" default ARCH_MEDIATEK @@ -1012,9 +1024,11 @@ Signed-off-by: John Crispin config MACH_MT8127 bool "MediaTek MT8127 SoCs support" default ARCH_MEDIATEK +diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c +index d019a08..bcfca37 100644 --- a/arch/arm/mach-mediatek/mediatek.c +++ b/arch/arm/mach-mediatek/mediatek.c -@@ -46,6 +46,7 @@ +@@ -46,6 +46,7 @@ static void __init mediatek_timer_init(void) static const char * const mediatek_board_dt_compat[] = { "mediatek,mt6589", "mediatek,mt6592", @@ -1022,3 +1036,6 @@ Signed-off-by: John Crispin "mediatek,mt8127", "mediatek,mt8135", NULL, +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch index 53db649c25..408946109a 100644 --- a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch +++ b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch @@ -1,7 +1,7 @@ -From 2ff725af8a512481d68ebd7f8ad122b1c98f3fad Mon Sep 17 00:00:00 2001 +From 97478bae3a11b5e87d61b88267e915f7c5ddf4e9 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 6 Jan 2016 21:55:10 +0100 -Subject: [PATCH 24/66] dt-bindings: add MediaTek PCIe binding documentation +Subject: [PATCH 24/78] dt-bindings: add MediaTek PCIe binding documentation Signed-off-by: John Crispin --- @@ -157,10 +157,10 @@ index 0000000..8fea3ed + }; + }; diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi -index 1ba7790..ec19283 100644 +index c53c10d..c8c802d 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi -@@ -291,6 +291,18 @@ +@@ -292,6 +292,18 @@ status = "disabled"; }; diff --git a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch index 36a7a85582..fe67755acb 100644 --- a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch +++ b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch @@ -1,7 +1,7 @@ -From 1ac5a6be891fb934e2a864bb2e424f05315f7385 Mon Sep 17 00:00:00 2001 +From b44b44cfdcb9b2d7ba513d24df1b16b8c57cce59 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Jan 2016 20:20:04 +0100 -Subject: [PATCH 25/66] PCI: mediatek: add support for PCIe found on +Subject: [PATCH 25/78] PCI: mediatek: add support for PCIe found on MT7623/MT2701 Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports diff --git a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch index bf26783964..dea9152252 100644 --- a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch +++ b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch @@ -1,7 +1,7 @@ -From 6c5c23a6c21b1a244db79d6387db915c72f50367 Mon Sep 17 00:00:00 2001 +From fe8fd85507870bf3aa5ff257944f15b50888d17c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 21 Feb 2016 13:52:12 +0100 -Subject: [PATCH 26/66] scpsys: various fixes +Subject: [PATCH 26/78] scpsys: various fixes --- drivers/clk/mediatek/clk-mt2701.c | 2 ++ diff --git a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch index 2607f93b65..d9b98c1f46 100644 --- a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch +++ b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch @@ -1,7 +1,7 @@ -From dadfca5daee5cb40d34542425392e694eddc5bc1 Mon Sep 17 00:00:00 2001 +From 2fc7dd0f48d9c2096d76562a1960b78b064701f7 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Mon, 4 Jan 2016 20:02:52 +0800 -Subject: [PATCH 27/66] soc: mediatek: PMIC wrap: Clear the vldclr if state +Subject: [PATCH 27/78] soc: mediatek: PMIC wrap: Clear the vldclr if state machine stay on FSM_VLDCLR state. Sometimes PMIC is too busy to send data in time to cause pmic wrap timeout, diff --git a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch index 24521cb369..4bbfe7427a 100644 --- a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch +++ b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch @@ -1,7 +1,7 @@ -From 7512d9b4bf8ab222b4d542ada87368229770383f Mon Sep 17 00:00:00 2001 +From b7d11ec865f99085a907f1a082f70404734e954c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 5 Jan 2016 17:24:28 +0100 -Subject: [PATCH 28/66] ARM: mediatek: add MT7623 smp bringup code +Subject: [PATCH 28/78] ARM: mediatek: add MT7623 smp bringup code Add support for booting secondary CPUs on MT7623. diff --git a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch index eab74bcf30..592b13f0f0 100644 --- a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch +++ b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch @@ -1,7 +1,7 @@ -From f8296ee9561945b5cebb570e06259b8865ef0b91 Mon Sep 17 00:00:00 2001 +From 7e0c3f4f4c7a55eda670c97b1b3b793ceecc1655 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Thu, 21 Jan 2016 19:04:00 +0800 -Subject: [PATCH 29/66] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of +Subject: [PATCH 29/78] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of WDT_SRC_EN Since STAUPD interrupts aren't handled on mt8173, disable watchdog timeout diff --git a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch index 9039cc1f38..e901a63c19 100644 --- a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch +++ b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch @@ -1,7 +1,7 @@ -From 977ccf394047647354093535f9b07f13a74949df Mon Sep 17 00:00:00 2001 +From 672ed0995e4ebf3f14bb58d08d6ba4c78337b90b Mon Sep 17 00:00:00 2001 From: Louis Yu Date: Thu, 7 Jan 2016 20:09:43 +0800 -Subject: [PATCH 30/66] ARM: mediatek: add mt2701 smp bringup code +Subject: [PATCH 30/78] ARM: mediatek: add mt2701 smp bringup code Add support for booting secondary CPUs on mt2701. diff --git a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch index fd44518320..d360096656 100644 --- a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch +++ b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch @@ -1,7 +1,7 @@ -From add1cc43bd41e6fc755852a5767e710cb3314013 Mon Sep 17 00:00:00 2001 +From 1474be4d7f9559804671ab01911232368496a1de Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 13:12:19 +0100 -Subject: [PATCH 31/66] dt-bindings: ARM: Mediatek: add MT2701/7623 string to +Subject: [PATCH 31/78] dt-bindings: ARM: Mediatek: add MT2701/7623 string to the PMIC wrapper doc Signed-off-by: John Crispin diff --git a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch index 5ee4ea4240..a29df296ed 100644 --- a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch +++ b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch @@ -1,7 +1,7 @@ -From 6792f25663b6064f21f033241bbeb6b023fa8ce7 Mon Sep 17 00:00:00 2001 +From 542f2cd3287fb955efcc5ceca14b690ba19f8c57 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 06:42:01 +0100 -Subject: [PATCH 32/66] soc: mediatek: PMIC wrap: don't duplicate the wrapper +Subject: [PATCH 32/78] soc: mediatek: PMIC wrap: don't duplicate the wrapper data As we add support for more devices struct pmic_wrapper_type will grow and diff --git a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch index 55881e0ffd..ec0cd5dba5 100644 --- a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch +++ b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch @@ -1,7 +1,7 @@ -From b67fd66c46f7cc6ac869aafc7f920846aed6bc12 Mon Sep 17 00:00:00 2001 +From 915340f70c0594d1f0717fee3eb678fa71206509 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 05:27:17 +0100 -Subject: [PATCH 33/66] soc: mediatek: PMIC wrap: add wrapper callbacks for +Subject: [PATCH 33/78] soc: mediatek: PMIC wrap: add wrapper callbacks for init_reg_clock Split init_reg_clock up into SoC specific callbacks. The patch also diff --git a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch index e73c43a38a..e9132db6e3 100644 --- a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch +++ b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch @@ -1,7 +1,7 @@ -From 4dd080818ec30dd101b6248b418751de5ac508f2 Mon Sep 17 00:00:00 2001 +From b2287b0afb757870ce0f4324bb4bc597d3f90a2a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 10:12:00 +0100 -Subject: [PATCH 34/66] soc: mediatek: PMIC wrap: split SoC specific init into +Subject: [PATCH 34/78] soc: mediatek: PMIC wrap: split SoC specific init into callback This patch moves the SoC specific wrapper init code into separate callback diff --git a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch index 8451679633..97300eed9c 100644 --- a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch +++ b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch @@ -1,7 +1,7 @@ -From 72300493dbf58de75972fce86e64f4728ff9b594 Mon Sep 17 00:00:00 2001 +From 76f0c7770046ed436be085af1257e0ab06fdd41f Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 10:14:39 +0100 -Subject: [PATCH 35/66] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a +Subject: [PATCH 35/78] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a different bitmask for MT2701/7623 MT2701 and MT7623 use a different bitmask for PWRAP_INT_EN. diff --git a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch index 7f7a905a7e..6110d007fd 100644 --- a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch +++ b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch @@ -1,7 +1,7 @@ -From 8e28fd218224df9c1a108a0b0d4c3a2ec51ddc62 Mon Sep 17 00:00:00 2001 +From fca1819591e7824d474c900a3524c0c1fee6a300 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 10:21:42 +0100 -Subject: [PATCH 36/66] soc: mediatek: PMIC wrap: SPI_WRITE needs a different +Subject: [PATCH 36/78] soc: mediatek: PMIC wrap: SPI_WRITE needs a different bitmask for MT2701/7623 Different SoCs will use different bitmask for the SPI_WRITE command. This diff --git a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch index ed225a5daf..f3307be5b1 100644 --- a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch +++ b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch @@ -1,7 +1,7 @@ -From 3a01206ed5749b5469459f82f1152e3699cb8baf Mon Sep 17 00:00:00 2001 +From dfdef729324d87d40468f76f0f2767a09c9b0ab0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 10:48:35 +0100 -Subject: [PATCH 37/66] soc: mediatek: PMIC wrap: move wdt_src into the +Subject: [PATCH 37/78] soc: mediatek: PMIC wrap: move wdt_src into the pmic_wrapper_type struct Different SoCs will use different bitmask for the wdt_src. This patch diff --git a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch index ad8ff5ff3b..3dfc7bd212 100644 --- a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch +++ b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch @@ -1,7 +1,7 @@ -From 20f4eef2f061619762aa87d484b359c3f9a0b228 Mon Sep 17 00:00:00 2001 +From 34d49f015488dcb3de31060846414bd4254e752a Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 10:54:18 +0100 -Subject: [PATCH 38/66] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and +Subject: [PATCH 38/78] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and pwrap_is_mt8173() With more SoCs being added the list of helper functions like these would diff --git a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch index 5cde24249d..47658dc1b9 100644 --- a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch +++ b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch @@ -1,7 +1,7 @@ -From 023e530aa86c95352dfc97df960ee0039ef2c030 Mon Sep 17 00:00:00 2001 +From ae593b270b87f9ed6c35dec3ac69dd6bda43c0a0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 09:55:08 +0100 -Subject: [PATCH 39/66] soc: mediatek: PMIC wrap: add a slave specific struct +Subject: [PATCH 39/78] soc: mediatek: PMIC wrap: add a slave specific struct This patch adds a new struct pwrap_slv_type that we use to store the slave specific data. The patch adds 2 new helper functions to access the dew diff --git a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch index a01f992c81..5aaced639f 100644 --- a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch +++ b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch @@ -1,7 +1,7 @@ -From 5db18f42fc5584a516cb7a8b705c97a7f1c4bf1b Mon Sep 17 00:00:00 2001 +From 8f3597ca8c8a28d2501d03643569f0cea920c24d Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 11:40:43 +0100 -Subject: [PATCH 40/66] soc: mediatek: PMIC wrap: add mt6323 slave support +Subject: [PATCH 40/78] soc: mediatek: PMIC wrap: add mt6323 slave support Add support for MT6323 slaves. This PMIC can be found on MT2701 and MT7623 EVB. The only function that we need to touch is pwrap_init_cipher(). diff --git a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch index a7e8775edf..a897640964 100644 --- a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch +++ b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch @@ -1,7 +1,7 @@ -From 444c4931cc6c2d1d9c94d8bbd4ee89438abca212 Mon Sep 17 00:00:00 2001 +From 09351f7c59e08d9c259546e03af3af05c10d644c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 20 Jan 2016 12:09:14 +0100 -Subject: [PATCH 41/66] soc: mediatek: PMIC wrap: add MT2701/7623 support +Subject: [PATCH 41/78] soc: mediatek: PMIC wrap: add MT2701/7623 support Add the registers, callbacks and data structures required to make the wrapper work on MT2701 and MT7623. diff --git a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch index b31f063679..cdb930a891 100644 --- a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch +++ b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch @@ -1,7 +1,7 @@ -From eb574bce59e66295ee288de0df450a6e82bb5b56 Mon Sep 17 00:00:00 2001 +From 94f7b9dabcd073bf629268514f87e5dbd2cafd13 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 10 Jan 2016 17:12:37 +0100 -Subject: [PATCH 42/66] dt-bindings: mfd: Add bindings for the MediaTek MT6323 +Subject: [PATCH 42/78] dt-bindings: mfd: Add bindings for the MediaTek MT6323 PMIC Signed-off-by: John Crispin diff --git a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch index 9d2379dc96..1761e7745a 100644 --- a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch +++ b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch @@ -1,7 +1,7 @@ -From 337807a89aec90a313a77336a9296ccd926c7015 Mon Sep 17 00:00:00 2001 +From aa90d988b627b41c774891fd72560699f30faefa Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 8 Jan 2016 08:33:17 +0100 -Subject: [PATCH 43/66] mfd: mt6397: int_con and int_status may vary in +Subject: [PATCH 43/78] mfd: mt6397: int_con and int_status may vary in location MT6323 has the INT_CON and INT_STATUS located at a different position. diff --git a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch index 0550087533..38ba17f016 100644 --- a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch +++ b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch @@ -1,7 +1,7 @@ -From c6fab1574939f968257029dd75da51ab266081c9 Mon Sep 17 00:00:00 2001 +From 1ef53a11f0c282008aa572eb7c97fa1e79621ea3 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 8 Jan 2016 08:41:52 +0100 -Subject: [PATCH 44/66] mfd: mt6397: add support for different Slave types +Subject: [PATCH 44/78] mfd: mt6397: add support for different Slave types Signed-off-by: John Crispin --- diff --git a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch index 3b8a752c1c..dac60eeeff 100644 --- a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch +++ b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch @@ -1,7 +1,7 @@ -From d3d044cff01ef835ef36b6f7d22b19fe47b65e46 Mon Sep 17 00:00:00 2001 +From 49d9c28b1252c7920840662425aa7e4705cfbccf Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 8 Jan 2016 04:09:43 +0100 -Subject: [PATCH 45/66] mfd: mt6397: add MT6323 support to MT6397 driver +Subject: [PATCH 45/78] mfd: mt6397: add MT6323 support to MT6397 driver Signed-off-by: John Crispin --- diff --git a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch index f5b7f2363d..5beb8d186b 100644 --- a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch +++ b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch @@ -1,7 +1,7 @@ -From 9877cc960be38947b6bce371e3dce2be185dc337 Mon Sep 17 00:00:00 2001 +From f5b5c70021187c0ef70edf83865b62fec473e8fb Mon Sep 17 00:00:00 2001 From: John Crispin Date: Sun, 10 Jan 2016 17:31:46 +0100 -Subject: [PATCH 46/66] regulator: Add document for MT6323 regulator +Subject: [PATCH 46/78] regulator: Add document for MT6323 regulator Signed-off-by: John Crispin Cc: devicetree@vger.kernel.org diff --git a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch index 37d7fd1904..fc2b3d2fb2 100644 --- a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch +++ b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch @@ -1,7 +1,7 @@ -From 34163b123140c2668d52385bb9ab501cb025f943 Mon Sep 17 00:00:00 2001 +From 031a2ff537366855e88bc95e5d42ea522b6c5ad8 Mon Sep 17 00:00:00 2001 From: Chen Zhong Date: Fri, 8 Jan 2016 04:17:37 +0100 -Subject: [PATCH 47/66] regulator: mt6323: Add support for MT6323 regulator +Subject: [PATCH 47/78] regulator: mt6323: Add support for MT6323 regulator The MT6323 is a regulator found on boards based on MediaTek MT7623 and probably other SoCs. It is a so called pmic and connects as a slave to diff --git a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch index 34a033e450..3e668992ab 100644 --- a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch +++ b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch @@ -1,7 +1,7 @@ -From 13e64dd7fb55bf3948005863a494646874c22c1b Mon Sep 17 00:00:00 2001 +From b79b0519fb67c22cbed341c5e9dca5ad0aa4d15c Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 2 Mar 2016 07:18:52 +0100 -Subject: [PATCH 48/66] net-next: mediatek: document MediaTek SoC ethernet +Subject: [PATCH 48/78] net-next: mediatek: document MediaTek SoC ethernet binding This adds the binding documentation for the MediaTek Ethernet diff --git a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch index a3e3efd999..792e9e76a1 100644 --- a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch +++ b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch @@ -1,7 +1,7 @@ -From ce02aa9cebf5805427b874201b4ccb2a5e770597 Mon Sep 17 00:00:00 2001 +From 999621b6bfff903d16691799a23bfccac91c31df Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 2 Mar 2016 04:27:10 +0100 -Subject: [PATCH 49/66] net-next: mediatek: add support for MT7623 ethernet +Subject: [PATCH 49/78] net-next: mediatek: add support for MT7623 ethernet Add ethernet support for MediaTek SoCs from the MT7623 family. These have dual GMAC. Depending on the exact version, there might be a built-in diff --git a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch index d2bd7a866f..4c6ff0196b 100644 --- a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch +++ b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch @@ -1,7 +1,7 @@ -From e39d6547a391e3e32f88b6dde16dee271e905562 Mon Sep 17 00:00:00 2001 +From 0189b71d0ce9feef1c3fac7d9c3eb7dae57dabdf Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 2 Mar 2016 04:32:43 +0100 -Subject: [PATCH 50/66] net-next: mediatek: add Kconfig and Makefile +Subject: [PATCH 50/78] net-next: mediatek: add Kconfig and Makefile This patch adds the Makefile and Kconfig required to make the driver build. diff --git a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch index fe1f4af182..41c1b69aa9 100644 --- a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch +++ b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch @@ -1,7 +1,7 @@ -From 0ab2afe39e683c82b5c176047e81eeb2d1b9119c Mon Sep 17 00:00:00 2001 +From 76ac7ac355452b4a2cf5cf7b1d9ab5b08e349b4b Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 2 Mar 2016 04:34:04 +0100 -Subject: [PATCH 51/66] net-next: mediatek: add an entry to MAINTAINERS +Subject: [PATCH 51/78] net-next: mediatek: add an entry to MAINTAINERS Add myself and Felix as the Maintainers for the MediaTek ethernet driver. diff --git a/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch b/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch new file mode 100644 index 0000000000..8cc0075b93 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch @@ -0,0 +1,35 @@ +From 17b9724cf84aa32f15334c23d5df34ad3cb885f3 Mon Sep 17 00:00:00 2001 +From: Boris BREZILLON +Date: Mon, 16 Nov 2015 14:37:35 +0100 +Subject: [PATCH 52/78] mtd: nand: add an mtd_to_nand() helper + +Some drivers are retrieving the nand_chip pointer using the container_of +macro on a struct wrapping both the nand_chip and the mtd_info struct while +the standard way of retrieving this pointer is through mtd->priv. +Provide an helper to do that. + +Signed-off-by: Boris Brezillon +Signed-off-by: Brian Norris +--- + include/linux/mtd/nand.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 5a9d1d4..a4839b3 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -719,6 +719,11 @@ struct nand_chip { + void *priv; + }; + ++static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) ++{ ++ return mtd->priv; ++} ++ + /* + * NAND Flash Manufacturer ID Codes + */ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0052-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch b/target/linux/mediatek/patches-4.4/0052-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch deleted file mode 100644 index 5e542916e0..0000000000 --- a/target/linux/mediatek/patches-4.4/0052-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 7809955b6f4319773a5ef561a5e98c61dc891a47 Mon Sep 17 00:00:00 2001 -From: Dan Carpenter -Date: Tue, 15 Mar 2016 10:18:49 +0300 -Subject: [PATCH 52/66] net: mediatek: checking for IS_ERR() instead of NULL - -of_phy_connect() returns NULL on error, it never returns error pointers. - -Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet') -Signed-off-by: Dan Carpenter ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index ba3afa5..9759fe5 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -186,9 +186,9 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, - - phydev = of_phy_connect(eth->netdev[mac->id], phy_node, - mtk_phy_link_adjust, 0, phy_mode); -- if (IS_ERR(phydev)) { -+ if (!phydev) { - dev_err(eth->dev, "could not connect to PHY\n"); -- return PTR_ERR(phydev); -+ return -ENODEV; - } - - dev_info(eth->dev, --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch b/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch new file mode 100644 index 0000000000..29c0d1b427 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch @@ -0,0 +1,32 @@ +From 86e5fe2edbe2ca4f0d83a26d9b3d02620cd78f37 Mon Sep 17 00:00:00 2001 +From: Boris BREZILLON +Date: Tue, 1 Dec 2015 12:03:07 +0100 +Subject: [PATCH 53/78] mtd: nand: add nand_to_mtd() helper + +Add a new helper to retrieve the MTD device attached to a NAND chip. + +Signed-off-by: Boris Brezillon +Signed-off-by: Brian Norris +--- + include/linux/mtd/nand.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index a4839b3..c75424f 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -724,6 +724,11 @@ static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) + return mtd->priv; + } + ++static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) ++{ ++ return &chip->mtd; ++} ++ + /* + * NAND Flash Manufacturer ID Codes + */ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0053-net-mediatek-unlock-on-error-in-mtk_tx_map.patch b/target/linux/mediatek/patches-4.4/0053-net-mediatek-unlock-on-error-in-mtk_tx_map.patch deleted file mode 100644 index 89ad003855..0000000000 --- a/target/linux/mediatek/patches-4.4/0053-net-mediatek-unlock-on-error-in-mtk_tx_map.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a2559aaca7c4a9b80699147390efda51df20ac96 Mon Sep 17 00:00:00 2001 -From: Dan Carpenter -Date: Tue, 15 Mar 2016 10:19:04 +0300 -Subject: [PATCH 53/66] net: mediatek: unlock on error in mtk_tx_map() - -There was a missing unlock on the error path. - -Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet') -Signed-off-by: Dan Carpenter ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index 9759fe5..c2c2e206 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -661,6 +661,8 @@ err_dma: - itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); - } while (itxd != txd); - -+ spin_unlock_irqrestore(ð->page_lock, flags); -+ - return -ENOMEM; - } - --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch b/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch new file mode 100644 index 0000000000..9cbc064075 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch @@ -0,0 +1,39 @@ +From ca10b32de369729b8e7947fe1945e8e393d803cd Mon Sep 17 00:00:00 2001 +From: Boris BREZILLON +Date: Thu, 10 Dec 2015 09:00:39 +0100 +Subject: [PATCH 54/78] mtd: nand: add helpers to access ->priv + +Add two helpers to access the field reserved for private controller data. +This makes it clearer what this field is reserved for and ease future +refactoring. + +Signed-off-by: Boris Brezillon +Signed-off-by: Brian Norris +--- + include/linux/mtd/nand.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index c75424f..345f864 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -729,6 +729,16 @@ static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) + return &chip->mtd; + } + ++static inline void *nand_get_controller_data(struct nand_chip *chip) ++{ ++ return chip->priv; ++} ++ ++static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) ++{ ++ chip->priv = priv; ++} ++ + /* + * NAND Flash Manufacturer ID Codes + */ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0054-net-mediatek-use-dma_addr_t-correctly.patch b/target/linux/mediatek/patches-4.4/0054-net-mediatek-use-dma_addr_t-correctly.patch deleted file mode 100644 index d00d9b6bcb..0000000000 --- a/target/linux/mediatek/patches-4.4/0054-net-mediatek-use-dma_addr_t-correctly.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ca4d9b6f3476e18e3136e488debdb35cd402d8d3 Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Mon, 14 Mar 2016 15:07:10 +0100 -Subject: [PATCH 54/66] net: mediatek: use dma_addr_t correctly - -dma_alloc_coherent() expects a dma_addr_t pointer as its argument, -not an 'unsigned int', and gcc correctly warns about broken -code in the mtk_init_fq_dma function: - -drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_init_fq_dma': -drivers/net/ethernet/mediatek/mtk_eth_soc.c:463:13: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type [-Werror=incompatible-pointer-types] - -This changes the type of the local variable to dma_addr_t. - -Signed-off-by: Arnd Bergmann ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index c2c2e206..a005bc4 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -453,7 +453,7 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd, - /* the qdma core needs scratch memory to be setup */ - static int mtk_init_fq_dma(struct mtk_eth *eth) - { -- unsigned int phy_ring_head, phy_ring_tail; -+ dma_addr_t phy_ring_head, phy_ring_tail; - int cnt = MTK_DMA_SIZE; - dma_addr_t dma_addr; - int i; --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch b/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch new file mode 100644 index 0000000000..29a6cd6f97 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch @@ -0,0 +1,42 @@ +From b4a93bff70545d73337e2cae7209fd1ae4d9d8e8 Mon Sep 17 00:00:00 2001 +From: Boris BREZILLON +Date: Tue, 1 Dec 2015 12:03:06 +0100 +Subject: [PATCH 55/78] mtd: nand: embed an mtd_info structure into nand_chip + +Currently all NAND controller drivers are providing both the mtd_info and +nand_chip struct and then let the NAND subsystem to initialize a few +things before registering the mtd instance to the MTD layer. +Embed an mtd_info field into nand_chip to add some consistency to all NAND +controller drivers. +This change will also help factorizing boilerplate code copied in all NAND +drivers. + +Signed-off-by: Boris Brezillon +Signed-off-by: Brian Norris +--- + include/linux/mtd/nand.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 345f864..1ded588 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -540,6 +540,7 @@ struct nand_buffers { + + /** + * struct nand_chip - NAND Private Flash Chip Data ++ * @mtd: MTD device registered to the MTD framework + * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the + * flash device + * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the +@@ -640,6 +641,7 @@ struct nand_buffers { + */ + + struct nand_chip { ++ struct mtd_info mtd; + void __iomem *IO_ADDR_R; + void __iomem *IO_ADDR_W; + +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0055-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0055-net-mediatek-remove-incorrect-dma_mask-assignment.patch deleted file mode 100644 index 4bf0947db8..0000000000 --- a/target/linux/mediatek/patches-4.4/0055-net-mediatek-remove-incorrect-dma_mask-assignment.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 9d602a7040c0fe9c81f2beffb3c277442a6d9ea2 Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Mon, 14 Mar 2016 15:07:11 +0100 -Subject: [PATCH 55/66] net: mediatek: remove incorrect dma_mask assignment - -Device drivers should not mess with the DMA mask directly, -but instead call dma_set_mask() etc if needed. - -In case of the mtk_eth_soc driver, the mask already gets set -correctly when the device is created, and setting it again -is against the documented API. - -This removes the incorrect setting. - -Signed-off-by: Arnd Bergmann ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index a005bc4..fcd4ed7 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1678,9 +1678,6 @@ static int mtk_probe(struct platform_device *pdev) - struct mtk_eth *eth; - int err; - -- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); -- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; -- - device_reset(&pdev->dev); - - match = of_match_device(of_mtk_match, &pdev->dev); --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch new file mode 100644 index 0000000000..a7ec4c44ac --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch @@ -0,0 +1,87 @@ +From 3ed29e95facfd50427721f8e9093dc36c2304e42 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 22 Mar 2016 03:52:07 +0100 +Subject: [PATCH 56/78] mtd: add get/set of_node/flash_node helpers + +We are going to begin using the mtd->dev.of_node field for MTD device +nodes, so let's add helpers for it. Also, we'll be making some +conversions on spi_nor (and nand_chip eventually) too, so get that ready +with their own helpers. + +Signed-off-by: Brian Norris +Reviewed-by: Boris Brezillon +--- + include/linux/mtd/mtd.h | 11 +++++++++++ + include/linux/mtd/nand.h | 11 +++++++++++ + include/linux/mtd/spi-nor.h | 11 +++++++++++ + 3 files changed, 33 insertions(+) + +diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h +index f17fa75..cc84923 100644 +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -254,6 +254,17 @@ struct mtd_info { + int usecount; + }; + ++static inline void mtd_set_of_node(struct mtd_info *mtd, ++ struct device_node *np) ++{ ++ mtd->dev.of_node = np; ++} ++ ++static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd) ++{ ++ return mtd->dev.of_node; ++} ++ + int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); + int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, + void **virt, resource_size_t *phys); +diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h +index 1ded588..3c34ca4 100644 +--- a/include/linux/mtd/nand.h ++++ b/include/linux/mtd/nand.h +@@ -741,6 +741,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) + chip->priv = priv; + } + ++static inline void nand_set_flash_node(struct nand_chip *chip, ++ struct device_node *np) ++{ ++ chip->flash_node = np; ++} ++ ++static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) ++{ ++ return chip->flash_node; ++} ++ + /* + * NAND Flash Manufacturer ID Codes + */ +diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h +index c8723b6..6d991df 100644 +--- a/include/linux/mtd/spi-nor.h ++++ b/include/linux/mtd/spi-nor.h +@@ -185,6 +185,17 @@ struct spi_nor { + void *priv; + }; + ++static inline void spi_nor_set_flash_node(struct spi_nor *nor, ++ struct device_node *np) ++{ ++ nor->flash_node = np; ++} ++ ++static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor) ++{ ++ return nor->flash_node; ++} ++ + /** + * spi_nor_scan() - scan the SPI NOR + * @nor: the spi_nor structure +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0056-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0056-net-mediatek-check-device_reset-return-code.patch deleted file mode 100644 index 00e5c8bfc8..0000000000 --- a/target/linux/mediatek/patches-4.4/0056-net-mediatek-check-device_reset-return-code.patch +++ /dev/null @@ -1,38 +0,0 @@ -From b461f1a8dfcf32f289a559b6eba4e784b37d121c Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Mon, 14 Mar 2016 15:07:12 +0100 -Subject: [PATCH 56/66] net: mediatek: check device_reset return code - -The device_reset() function may fail, so we have to check -its return value, e.g. to make deferred probing work correctly. -gcc warns about it because of the warn_unused_result attribute: - -drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_probe': -drivers/net/ethernet/mediatek/mtk_eth_soc.c:1679:2: error: ignoring return value of 'device_reset', declared with attribute warn_unused_result [-Werror=unused-result] - -This adds the trivial error check to propagate the return value -to the generic platform device probe code. - -Signed-off-by: Arnd Bergmann ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index fcd4ed7..7f2126b 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1678,7 +1678,9 @@ static int mtk_probe(struct platform_device *pdev) - struct mtk_eth *eth; - int err; - -- device_reset(&pdev->dev); -+ err = device_reset(&pdev->dev); -+ if (err) -+ return err; - - match = of_match_device(of_mtk_match, &pdev->dev); - soc = (struct mtk_soc_data *)match->data; --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch new file mode 100644 index 0000000000..e42d66092a --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch @@ -0,0 +1,64 @@ +From 5f0a1fa77e5d53b8dbb751fcfc59c7ef3d78ddf2 Mon Sep 17 00:00:00 2001 +From: Jorge Ramirez-Ortiz +Date: Wed, 2 Mar 2016 12:00:11 -0500 +Subject: [PATCH 57/78] mtd: mediatek: device tree docs for MTK Smart Device + Gen1 NAND + +This patch adds documentation support for Smart Device Gen1 type of +NAND controllers. + +Mediatek's SoC 2701 is one of the SoCs that implements this controller. + +Signed-off-by: Jorge Ramirez-Ortiz +--- + .../devicetree/bindings/mtd/mtksdg1-nand.txt | 38 ++++++++++++++++++++ + 1 file changed, 38 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt + +diff --git a/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt +new file mode 100644 +index 0000000..129d17b +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt +@@ -0,0 +1,38 @@ ++MTK Smart Device SoCs NAND controller DT binding ++ ++Required properties: ++- compatible: Should be "mediatek,mt2701-nfc". ++- reg: The first contains base physical address and size of ++ NAND controller's registers. The second contains base ++ physical address and size of NAND ECC engine. ++- interrupts: the NFC NFI interrupt, and the NFC ECC interrupt ++- clocks: NAND controller clocks. ++- clock-names: NAND controller clocks internal name. ++- vmch-supply: NAND power supply. ++- #address-cells: Partition address, should be set 1. ++- #size-cells: Partition size, should be set 1. ++ ++Optional properties: ++ ++nand-on-flash-bbt: Use a flash based bad block table. ++ ++Optional subnodes: ++- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt ++ ++Example: ++ ++ nand: nand@1100d000 { ++ compatible = "mediatek,mt2701-nfc"; ++ reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>; ++ interrupts = , ++ ; ++ clocks = <&pericfg CLK_PERI_NFI>, <&pericfg CLK_PERI_NFI_ECC>, ++ <&pericfg CLK_PERI_NFI_PAD>; ++ clock-names = "nfi_ck", "nfi_ecc_ck", "nfi_pad_ck"; ++ vmch-supply = <&mt6323_vmch_reg>; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ... ++ }; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0057-net-mediatek-out-of-tree-fixes.patch b/target/linux/mediatek/patches-4.4/0057-net-mediatek-out-of-tree-fixes.patch deleted file mode 100644 index 1e78d49999..0000000000 --- a/target/linux/mediatek/patches-4.4/0057-net-mediatek-out-of-tree-fixes.patch +++ /dev/null @@ -1,2469 +0,0 @@ -From cee958b55f35f953481c2ddf9609dbd018ef5979 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Mon, 21 Mar 2016 16:36:22 +0100 -Subject: [PATCH 57/66] net: mediatek: out of tree fixes - -Signed-off-by: John Crispin ---- - arch/arm/boot/dts/mt7623-evb.dts | 1 - - arch/arm/boot/dts/mt7623.dtsi | 40 +- - drivers/net/ethernet/mediatek/Makefile | 2 +- - drivers/net/ethernet/mediatek/gsw_mt7620.h | 250 +++++++ - drivers/net/ethernet/mediatek/gsw_mt7623.c | 1058 +++++++++++++++++++++++++++ - drivers/net/ethernet/mediatek/mt7530.c | 808 ++++++++++++++++++++ - drivers/net/ethernet/mediatek/mt7530.h | 20 + - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 41 +- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 + - 9 files changed, 2202 insertions(+), 23 deletions(-) - create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h - create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c - create mode 100644 drivers/net/ethernet/mediatek/mt7530.c - create mode 100644 drivers/net/ethernet/mediatek/mt7530.h - -diff --git a/arch/arm/boot/dts/mt7623-evb.dts b/arch/arm/boot/dts/mt7623-evb.dts -index 5e9381d..bc2b3f1 100644 ---- a/arch/arm/boot/dts/mt7623-evb.dts -+++ b/arch/arm/boot/dts/mt7623-evb.dts -@@ -425,7 +425,6 @@ - &usb1 { - vusb33-supply = <&mt6323_vusb_reg>; - vbus-supply = <&usb_p1_vbus>; --// mediatek,wakeup-src = <1>; - status = "okay"; - }; - -diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi -index ec19283..0c65045 100644 ---- a/arch/arm/boot/dts/mt7623.dtsi -+++ b/arch/arm/boot/dts/mt7623.dtsi -@@ -452,23 +452,30 @@ - }; - - ethsys: syscon@1b000000 { -- #address-cells = <1>; -- #size-cells = <1>; - compatible = "mediatek,mt2701-ethsys", "syscon"; - reg = <0 0x1b000000 0 0x1000>; -+ #reset-cells = <1>; - #clock-cells = <1>; - }; - - eth: ethernet@1b100000 { - compatible = "mediatek,mt7623-eth"; -- reg = <0 0x1b100000 0 0x10000>; -+ reg = <0 0x1b100000 0 0x20000>; - -- clocks = <&topckgen CLK_TOP_ETHIF_SEL>; -- clock-names = "ethif"; -+ clocks = <&topckgen CLK_TOP_ETHIF_SEL>, -+ <ðsys CLK_ETHSYS_ESW>, -+ <ðsys CLK_ETHSYS_GP2>, -+ <ðsys CLK_ETHSYS_GP1>; -+ clock-names = "ethif", "esw", "gp2", "gp1"; - interrupts = ; - power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; - -+ resets = <ðsys 6>; -+ reset-names = "eth"; -+ - mediatek,ethsys = <ðsys>; -+ mediatek,pctl = <&syscfg_pctl_a>; -+ - mediatek,switch = <&gsw>; - - #address-cells = <1>; -@@ -480,6 +487,8 @@ - compatible = "mediatek,eth-mac"; - reg = <0>; - -+ phy-handle = <&phy4>; -+ - status = "disabled"; - }; - -@@ -487,6 +496,7 @@ - compatible = "mediatek,eth-mac"; - reg = <1>; - -+ phy-handle = <&phy5>; - status = "disabled"; - }; - -@@ -494,6 +504,16 @@ - #address-cells = <1>; - #size-cells = <0>; - -+ phy4: ethernet-phy@4 { -+ reg = <4>; -+ phy-mode = "rgmii"; -+ }; -+ -+ phy5: ethernet-phy@5 { -+ reg = <5>; -+ phy-mode = "rgmii"; -+ }; -+ - phy1f: ethernet-phy@1f { - reg = <0x1f>; - phy-mode = "rgmii"; -@@ -503,14 +523,12 @@ - - gsw: switch@1b100000 { - compatible = "mediatek,mt7623-gsw"; -- reg = <0 0x1b110000 0 0x300000>; - interrupt-parent = <&pio>; - interrupts = <168 IRQ_TYPE_EDGE_RISING>; -- clocks = <&apmixedsys CLK_APMIXED_TRGPLL>, -- <ðsys CLK_ETHSYS_ESW>, -- <ðsys CLK_ETHSYS_GP2>, -- <ðsys CLK_ETHSYS_GP1>; -- clock-names = "trgpll", "esw", "gp2", "gp1"; -+ resets = <ðsys 2>; -+ reset-names = "eth"; -+ clocks = <&apmixedsys CLK_APMIXED_TRGPLL>; -+ clock-names = "trgpll"; - mt7530-supply = <&mt6323_vpa_reg>; - mediatek,pctl-regmap = <&syscfg_pctl_a>; - mediatek,ethsys = <ðsys>; -diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile -index aa3f1c8..82001c4 100644 ---- a/drivers/net/ethernet/mediatek/Makefile -+++ b/drivers/net/ethernet/mediatek/Makefile -@@ -2,4 +2,4 @@ - # Makefile for the Mediatek SoCs built-in ethernet macs - # - --obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o -+obj-$(CONFIG_NET_MEDIATEK_SOC) += mt7530.o gsw_mt7623.o mtk_eth_soc.o -diff --git a/drivers/net/ethernet/mediatek/gsw_mt7620.h b/drivers/net/ethernet/mediatek/gsw_mt7620.h -new file mode 100644 -index 0000000..7013803 ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h -@@ -0,0 +1,250 @@ -+/* 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) 2009-2016 John Crispin -+ * Copyright (C) 2009-2016 Felix Fietkau -+ * Copyright (C) 2013-2016 Michael Lee -+ */ -+ -+#ifndef _RALINK_GSW_MT7620_H__ -+#define _RALINK_GSW_MT7620_H__ -+ -+#define GSW_REG_PHY_TIMEOUT (5 * HZ) -+ -+#define MT7620_GSW_REG_PIAC 0x0004 -+ -+#define GSW_NUM_VLANS 16 -+#define GSW_NUM_VIDS 4096 -+#define GSW_NUM_PORTS 7 -+#define GSW_PORT6 6 -+ -+#define GSW_MDIO_ACCESS BIT(31) -+#define GSW_MDIO_READ BIT(19) -+#define GSW_MDIO_WRITE BIT(18) -+#define GSW_MDIO_START BIT(16) -+#define GSW_MDIO_ADDR_SHIFT 20 -+#define GSW_MDIO_REG_SHIFT 25 -+ -+#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100)) -+#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100)) -+#define GSW_REG_SMACCR0 0x3fE4 -+#define GSW_REG_SMACCR1 0x3fE8 -+#define GSW_REG_CKGCR 0x3ff0 -+ -+#define GSW_REG_IMR 0x7008 -+#define GSW_REG_ISR 0x700c -+#define GSW_REG_GPC1 0x7014 -+ -+#define SYSC_REG_CHIP_REV_ID 0x0c -+#define SYSC_REG_CFG 0x10 -+#define SYSC_REG_CFG1 0x14 -+#define RST_CTRL_MCM BIT(2) -+#define SYSC_PAD_RGMII2_MDIO 0x58 -+#define SYSC_GPIO_MODE 0x60 -+ -+#define PORT_IRQ_ST_CHG 0x7f -+ -+#define MT7621_ESW_PHY_POLLING 0x0000 -+#define MT7620_ESW_PHY_POLLING 0x7000 -+ -+#define PMCR_IPG BIT(18) -+#define PMCR_MAC_MODE BIT(16) -+#define PMCR_FORCE BIT(15) -+#define PMCR_TX_EN BIT(14) -+#define PMCR_RX_EN BIT(13) -+#define PMCR_BACKOFF BIT(9) -+#define PMCR_BACKPRES BIT(8) -+#define PMCR_RX_FC BIT(5) -+#define PMCR_TX_FC BIT(4) -+#define PMCR_SPEED(_x) (_x << 2) -+#define PMCR_DUPLEX BIT(1) -+#define PMCR_LINK BIT(0) -+ -+#define PHY_AN_EN BIT(31) -+#define PHY_PRE_EN BIT(30) -+#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24) -+ -+/* ethernet subsystem config register */ -+#define ETHSYS_SYSCFG0 0x14 -+/* ethernet subsystem clock register */ -+#define ETHSYS_CLKCFG0 0x2c -+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) -+ -+/* p5 RGMII wrapper TX clock control register */ -+#define MT7530_P5RGMIITXCR 0x7b04 -+/* p5 RGMII wrapper RX clock control register */ -+#define MT7530_P5RGMIIRXCR 0x7b00 -+/* TRGMII TDX ODT registers */ -+#define MT7530_TRGMII_TD0_ODT 0x7a54 -+#define MT7530_TRGMII_TD1_ODT 0x7a5c -+#define MT7530_TRGMII_TD2_ODT 0x7a64 -+#define MT7530_TRGMII_TD3_ODT 0x7a6c -+#define MT7530_TRGMII_TD4_ODT 0x7a74 -+#define MT7530_TRGMII_TD5_ODT 0x7a7c -+/* TRGMII TCK ctrl register */ -+#define MT7530_TRGMII_TCK_CTRL 0x7a78 -+/* TRGMII Tx ctrl register */ -+#define MT7530_TRGMII_TXCTRL 0x7a40 -+/* port 6 extended control register */ -+#define MT7530_P6ECR 0x7830 -+/* IO driver control register */ -+#define MT7530_IO_DRV_CR 0x7810 -+/* top signal control register */ -+#define MT7530_TOP_SIG_CTRL 0x7808 -+/* modified hwtrap register */ -+#define MT7530_MHWTRAP 0x7804 -+/* hwtrap status register */ -+#define MT7530_HWTRAP 0x7800 -+/* status interrupt register */ -+#define MT7530_SYS_INT_STS 0x700c -+/* system nterrupt register */ -+#define MT7530_SYS_INT_EN 0x7008 -+/* system control register */ -+#define MT7530_SYS_CTRL 0x7000 -+/* port MAC status register */ -+#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100)) -+/* port MAC control register */ -+#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100)) -+ -+#define MT7621_XTAL_SHIFT 6 -+#define MT7621_XTAL_MASK 0x7 -+#define MT7621_XTAL_25 6 -+#define MT7621_XTAL_40 3 -+#define MT7621_MDIO_DRV_MASK (3 << 4) -+#define MT7621_GE1_MODE_MASK (3 << 12) -+ -+#define TRGMII_TXCTRL_TXC_INV BIT(30) -+#define P6ECR_INTF_MODE_RGMII BIT(1) -+#define P5RGMIIRXCR_C_ALIGN BIT(8) -+#define P5RGMIIRXCR_DELAY_2 BIT(1) -+#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2)) -+ -+/* TOP_SIG_CTRL bits */ -+#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) -+ -+/* MHWTRAP bits */ -+#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) -+ -+/* HWTRAP bits */ -+#define HWTRAP_XTAL_SHIFT 9 -+#define HWTRAP_XTAL_MASK 0x3 -+ -+/* SYS_CTRL bits */ -+#define SYS_CTRL_SW_RST BIT(1) -+#define SYS_CTRL_REG_RST BIT(0) -+ -+/* PMCR bits */ -+#define PMCR_IFG_XMIT_96 BIT(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_BACK_PRES_EN BIT(9) -+#define PMCR_BACKOFF_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_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \ -+ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \ -+ PMCR_BACK_PRES_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) -+ -+/* TRGMII control registers */ -+#define GSW_INTF_MODE 0x390 -+#define GSW_TRGMII_TD0_ODT 0x354 -+#define GSW_TRGMII_TD1_ODT 0x35c -+#define GSW_TRGMII_TD2_ODT 0x364 -+#define GSW_TRGMII_TD3_ODT 0x36c -+#define GSW_TRGMII_TXCTL_ODT 0x374 -+#define GSW_TRGMII_TCK_ODT 0x37c -+#define GSW_TRGMII_RCK_CTRL 0x300 -+ -+#define INTF_MODE_TRGMII BIT(1) -+#define TRGMII_RCK_CTRL_RX_RST BIT(31) -+ -+ -+/* possible XTAL speed */ -+#define MT7623_XTAL_40 0 -+#define MT7623_XTAL_20 1 -+#define MT7623_XTAL_25 3 -+ -+/* GPIO port control registers */ -+#define GPIO_OD33_CTRL8 0x4c0 -+#define GPIO_BIAS_CTRL 0xed0 -+#define GPIO_DRV_SEL10 0xf00 -+ -+/* on MT7620 the functio of port 4 can be software configured */ -+enum { -+ PORT4_EPHY = 0, -+ PORT4_EXT, -+}; -+ -+/* struct mt7620_gsw - the structure that holds the SoC specific data -+ * @dev: The Device struct -+ * @base: The base address -+ * @piac_offset: The PIAC base may change depending on SoC -+ * @irq: The IRQ we are using -+ * @port4: The port4 mode on MT7620 -+ * @autopoll: Is MDIO autopolling enabled -+ * @ethsys: The ethsys register map -+ * @pctl: The pin control register map -+ * @clk_trgpll: The trgmii pll clock -+ */ -+struct mt7620_gsw { -+ struct mtk_eth *eth; -+ struct device *dev; -+ void __iomem *base; -+ u32 piac_offset; -+ int irq; -+ int port4; -+ unsigned long int autopoll; -+ -+ struct regmap *ethsys; -+ struct regmap *pctl; -+ -+ struct clk *clk_trgpll; -+ -+ int trgmii_force; -+}; -+ -+/* switch register I/O wrappers */ -+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg); -+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg); -+ -+/* the callback used by the driver core to bringup the switch */ -+int mtk_gsw_init(struct mtk_eth *eth); -+ -+/* MDIO access wrappers */ -+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); -+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); -+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port); -+int mt7620_has_carrier(struct mtk_eth *eth); -+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link, -+ int speed, int duplex); -+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val); -+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg); -+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg); -+ -+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, -+ u32 phy_register, u32 write_data); -+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg); -+void mt7620_handle_carrier(struct mtk_eth *eth); -+ -+#endif -diff --git a/drivers/net/ethernet/mediatek/gsw_mt7623.c b/drivers/net/ethernet/mediatek/gsw_mt7623.c -new file mode 100644 -index 0000000..4e486af ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c -@@ -0,0 +1,1058 @@ -+/* 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) 2009-2016 John Crispin -+ * Copyright (C) 2009-2016 Felix Fietkau -+ * Copyright (C) 2013-2016 Michael Lee -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mtk_eth_soc.h" -+#include "gsw_mt7620.h" -+#include "mt7530.h" -+ -+#define ETHSYS_CLKCFG0 0x2c -+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) -+ -+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val) -+{ -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ _mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff); -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16); -+} -+ -+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg) -+{ -+ u16 high, low; -+ -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf); -+ high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10); -+ -+ return (high << 16) | (low & 0xffff); -+} -+ -+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg) -+{ -+ u32 val = mt7530_mdio_r32(gsw, reg); -+ -+ val &= mask; -+ val |= set; -+ mt7530_mdio_w32(gsw, reg, val); -+} -+ -+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) -+{ -+ mtk_w32(gsw->eth, val, reg + 0x10000); -+} -+ -+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) -+{ -+ return mtk_r32(gsw->eth, reg + 0x10000); -+} -+ -+void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg) -+{ -+ u32 val = mtk_switch_r32(gsw, reg); -+ -+ val &= mask; -+ val |= set; -+ -+ mtk_switch_w32(gsw, val, reg); -+} -+ -+int mt7623_gsw_config(struct mtk_eth *eth) -+{ -+ if (eth->mii_bus && eth->mii_bus->phy_map[0x1f]) -+ mt7530_probe(eth->dev, NULL, eth->mii_bus, 1); -+ -+ return 0; -+} -+ -+static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth) -+{ -+ struct mtk_eth *eth = (struct mtk_eth *)_eth; -+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; -+ u32 reg, i; -+ -+ reg = mt7530_mdio_r32(gsw, 0x700c); -+ -+ for (i = 0; i < 5; i++) -+ if (reg & BIT(i)) { -+ unsigned int link; -+ -+ link = mt7530_mdio_r32(gsw, -+ 0x3008 + (i * 0x100)) & 0x1; -+ -+ if (link) -+ dev_info(gsw->dev, -+ "port %d link up\n", i); -+ else -+ dev_info(gsw->dev, -+ "port %d link down\n", i); -+ } -+ -+// mt7620_handle_carrier(eth); -+ mt7530_mdio_w32(gsw, 0x700c, 0x1f); -+ -+ return IRQ_HANDLED; -+} -+ -+static void wait_loop(struct mt7620_gsw *gsw) -+{ -+ int i; -+ int read_data; -+ -+ for (i = 0; i < 320; i = i + 1) -+ read_data = mtk_switch_r32(gsw, 0x610); -+} -+ -+static void trgmii_calibration_7623(struct mt7620_gsw *gsw) -+{ -+ -+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; /* minumum delay for all correct */ -+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; /* maximum delay for all correct */ -+ unsigned int final_tap[5]; -+ unsigned int rxc_step_size; -+ unsigned int rxd_step_size; -+ unsigned int read_data; -+ unsigned int tmp; -+ unsigned int rd_wd; -+ int i; -+ unsigned int err_cnt[5]; -+ unsigned int init_toggle_data; -+ unsigned int err_flag[5]; -+ unsigned int err_total_flag; -+ unsigned int training_word; -+ unsigned int rd_tap; -+ u32 val; -+ -+ u32 TRGMII_7623_base; -+ u32 TRGMII_7623_RD_0; -+ u32 TRGMII_RCK_CTRL; -+ -+ TRGMII_7623_base = 0x300; /* 0xFB110300 */ -+ TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10; -+ TRGMII_RCK_CTRL = TRGMII_7623_base; -+ rxd_step_size = 0x1; -+ rxc_step_size = 0x4; -+ init_toggle_data = 0x00000055; -+ training_word = 0x000000AC; -+ -+ /* RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); -+ -+ /* Assert RX reset in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00); -+ -+ /* Set TX OE edge in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78); -+ -+ /* Disable RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); -+ -+ /* Release RX reset in MT7623 */ -+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base); -+ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); -+ -+ pr_err("Enable Training Mode in MT7530\n"); -+ read_data = mt7530_mdio_r32(gsw, 0x7A40); -+ read_data |= 0xC0000000; -+ mt7530_mdio_w32(gsw, 0x7A40, read_data); /* Enable Training Mode in MT7530 */ -+ err_total_flag = 0; -+ pr_err("Adjust RXC delay in MT7623\n"); -+ read_data = 0x0; -+ while (err_total_flag == 0 && read_data != 0x68) { -+ pr_err("2nd Enable EDGE CHK in MT7623\n"); -+ /* Enable EDGE CHK in MT7623 */ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ -+ wait_loop(gsw); -+ err_total_flag = 1; -+ for (i = 0; i < 5; i++) { -+ err_cnt[i] = -+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8; -+ err_cnt[i] &= 0x0000000f; -+ rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16; -+ rd_wd &= 0x000000ff; -+ val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n", -+ err_cnt[i], rd_wd, val); -+ if (err_cnt[i] != 0) { -+ err_flag[i] = 1; -+ } else if (rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ err_total_flag = err_flag[i] & err_total_flag; -+ } -+ -+ pr_err("2nd Disable EDGE CHK in MT7623\n"); -+ /* Disable EDGE CHK in MT7623 */ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ pr_err("2nd Disable EDGE CHK in MT7623\n"); -+ /* Adjust RXC delay */ -+ /* RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_base); -+ if (err_total_flag == 0) { -+ tmp = (read_data & 0x0000007f) + rxc_step_size; -+ pr_err(" RXC delay = %d\n", tmp); -+ read_data >>= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ read_data <<= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); -+ } else { -+ tmp = (read_data & 0x0000007f) + 16; -+ pr_err(" RXC delay = %d\n", tmp); -+ read_data >>= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ read_data <<= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); -+ } -+ read_data &= 0x000000ff; -+ -+ /* Disable RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ /* Read RD_WD MT7623 */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] != 0 && rd_tap != 128) { -+ /* Enable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ /* Disable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ if (err_flag[i] != 0) { -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, -+ TRGMII_7623_RD_0 + i * 8); -+ tap_a[i] = rd_tap; -+ } else { -+ rd_tap = (read_data & 0x0000007f) + 48; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, -+ TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ } -+ pr_err("MT7623 %dth bit Tap_a = %d\n", i, tap_a[i]); -+ } -+ /* pr_err("Last While Loop\n"); */ -+ for (i = 0; i < 5; i++) { -+ while ((err_flag[i] == 0) && (rd_tap != 128)) { -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); -+ /* Enable EDGE CHK in MT7623 */ -+ val = -+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000; -+ val &= 0x4fffffff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ -+ /* Disable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ -+ } -+ -+ tap_b[i] = rd_tap; /* -rxd_step_size; */ -+ pr_err("MT7623 %dth bit Tap_b = %d\n", i, tap_b[i]); -+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ -+ read_data = (read_data & 0xffffff80) | final_tap[i]; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ read_data = mt7530_mdio_r32(gsw, 0x7A40); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, 0x7A40, read_data); -+} -+ -+static void trgmii_calibration_7530(struct mt7620_gsw *gsw) -+{ -+ -+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; -+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; -+ unsigned int final_tap[5]; -+ unsigned int rxc_step_size; -+ unsigned int rxd_step_size; -+ unsigned int read_data; -+ unsigned int tmp = 0; -+ int i; -+ unsigned int err_cnt[5]; -+ unsigned int rd_wd; -+ unsigned int init_toggle_data; -+ unsigned int err_flag[5]; -+ unsigned int err_total_flag; -+ unsigned int training_word; -+ unsigned int rd_tap; -+ -+ u32 TRGMII_7623_base; -+ u32 TRGMII_7530_RD_0; -+ u32 TRGMII_RCK_CTRL; -+ u32 TRGMII_7530_base; -+ u32 TRGMII_7530_TX_base; -+ u32 val; -+ -+ TRGMII_7623_base = 0x300; -+ TRGMII_7530_base = 0x7A00; -+ TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10; -+ TRGMII_RCK_CTRL = TRGMII_7623_base; -+ rxd_step_size = 0x1; -+ rxc_step_size = 0x8; -+ init_toggle_data = 0x00000055; -+ training_word = 0x000000AC; -+ -+ TRGMII_7530_TX_base = TRGMII_7530_base + 0x50; -+ -+ /* pr_err("Calibration begin ........\n"); */ -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ read_data = mt7530_mdio_r32(gsw, 0x7a10); -+ /* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78); -+ read_data |= 0x00002000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data); /* Set TX OE edge in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data |= 0x80000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data &= 0x7fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data |= 0xC0000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ -+ -+ /* pr_err("Enable Training Mode in MT7623\n"); */ -+ /*Enable Training Mode in MT7623 */ -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ if (gsw->trgmii_force == 2000) { -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ } else { -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ } -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78); -+ err_total_flag = 0; -+ /* pr_err("Adjust RXC delay in MT7530\n"); */ -+ read_data = 0x0; -+ while (err_total_flag == 0 && (read_data != 0x68)) { -+ /* pr_err("2nd Enable EDGE CHK in MT7530\n"); */ -+ /* Enable EDGE CHK in MT7530 */ -+ for (i = 0; i < 5; i++) { -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ /* pr_err("2nd Disable EDGE CHK in MT7530\n"); */ -+ err_cnt[i] = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ /* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ -+ /* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ -+ err_cnt[i] >>= 8; -+ err_cnt[i] &= 0x0000ff0f; -+ rd_wd = err_cnt[i] >> 8; -+ rd_wd &= 0x000000ff; -+ err_cnt[i] &= 0x0000000f; -+ /* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */ -+ if (err_cnt[i] != 0) { -+ err_flag[i] = 1; -+ } else if (rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ if (i == 0) { -+ err_total_flag = err_flag[i]; -+ } else { -+ err_total_flag = err_flag[i] & err_total_flag; -+ } -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ } -+ /*Adjust RXC delay */ -+ if (err_total_flag == 0) { -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data |= 0x80000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ -+ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ tmp = read_data; -+ tmp &= 0x0000007f; -+ tmp += rxc_step_size; -+ /* pr_err("Current rxc delay = %d\n", tmp); */ -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ /* pr_err("Current RXC delay = %x\n", read_data); */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data &= 0x7fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ -+ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data |= 0xc0000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ -+ pr_err("####### MT7530 RXC delay is %d\n", tmp); -+ } -+ read_data = tmp; -+ } -+ pr_err("Finish RXC Adjustment while loop\n"); -+ -+ /* pr_err("Read RD_WD MT7530\n"); */ -+ /* Read RD_WD MT7530 */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] != 0 && rd_tap != 128) { -+ /* Enable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ if (err_flag[i] != 0) { -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7530 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ tap_a[i] = rd_tap; -+ } else { -+ tap_a[i] = (read_data & 0x0000007f); /* Record the min delay TAP_A */ -+ rd_tap = tap_a[i] + 0x4; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ } -+ -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ -+ } -+ pr_err("MT7530 %dth bit Tap_a = %d\n", i, tap_a[i]); -+ } -+ -+ /* pr_err("Last While Loop\n"); */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] == 0 && (rd_tap != 128)) { -+ /* Enable EDGE CHK in MT7530 */ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) -+ err_flag[i] = 1; -+ else -+ err_flag[i] = 0; -+ -+ if (err_flag[i] == 0 && (rd_tap != 128)) { -+ /* Add RXD delay in MT7530 */ -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ } -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ } -+ tap_b[i] = rd_tap; /* - rxd_step_size; */ -+ pr_err("MT7530 %dth bit Tap_b = %d\n", i, tap_b[i]); -+ /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ -+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; -+ /* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */ -+ -+ read_data = (read_data & 0xffffff80) | final_tap[i]; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data); -+ } -+ -+ if (gsw->trgmii_force == 2000) -+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40); -+ else -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40); -+ -+} -+ -+static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode) -+{ -+ -+ u32 regValue; -+ -+ /* TRGMII Clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x404); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ -+ if (xtal_mode == 1) { -+ /* 25MHz */ -+ if (gsw->trgmii_force == 2600) -+ /* 325MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1a00); -+ else if (gsw->trgmii_force == 2000) -+ /* 250MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1400); -+ } else if (xtal_mode == 2) { -+ /* 40MHz */ -+ if (gsw->trgmii_force == 2600) -+ /* 325MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1040); -+ else if (gsw->trgmii_force == 2000) -+ /* 250MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0c80); -+ } -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x405); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x409); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ if (xtal_mode == 1) -+ /* 25MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); -+ else -+ /* 40MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40a); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ if (xtal_mode == 1) -+ /* 25MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); -+ else -+ /* 40MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1800); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1c00); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x401); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xc020); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa030); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa038); -+ -+// udelay(120); /* for MT7623 bring up test */ -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x3); -+ -+ regValue = mt7530_mdio_r32(gsw, 0x7830); -+ regValue &= 0xFFFFFFFC; -+ regValue |= 0x00000001; -+ mt7530_mdio_w32(gsw, 0x7830, regValue); -+ -+ regValue = mt7530_mdio_r32(gsw, 0x7a40); -+ regValue &= ~(0x1 << 30); -+ regValue &= ~(0x1 << 28); -+ mt7530_mdio_w32(gsw, 0x7a40, regValue); -+ -+ mt7530_mdio_w32(gsw, 0x7a78, 0x55); -+// udelay(100); /* for mt7623 bring up test */ -+ -+ mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300); -+ -+ trgmii_calibration_7623(gsw); -+ trgmii_calibration_7530(gsw); -+ -+ mtk_switch_m32(gsw, 0, 0x80000000, 0x300); -+ mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300); -+ -+ /*MT7530 RXC reset */ -+ regValue = mt7530_mdio_r32(gsw, 0x7a00); -+ regValue |= (0x1 << 31); -+ mt7530_mdio_w32(gsw, 0x7a00, regValue); -+ mdelay(1); -+ regValue &= ~(0x1 << 31); -+ mt7530_mdio_w32(gsw, 0x7a00, regValue); -+ mdelay(100); -+} -+ -+static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np) -+{ -+ u32 i; -+ u32 val; -+ u32 xtal_mode; -+ -+ regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0, -+ ETHSYS_TRGMII_CLK_SEL362_5, -+ ETHSYS_TRGMII_CLK_SEL362_5); -+ -+ /* reset the TRGMII core */ -+ mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE); -+ mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL); -+ -+ /* Hardware reset Switch */ -+ device_reset(eth->dev); -+ -+ /* Wait for Switch Reset Completed*/ -+ for (i = 0; i < 100; i++) { -+ mdelay(10); -+ if (mt7530_mdio_r32(gsw, MT7530_HWTRAP)) -+ break; -+ } -+ -+ /* turn off all PHYs */ -+ for (i = 0; i <= 4; i++) { -+ val = _mtk_mdio_read(gsw->eth, i, 0x0); -+ val |= BIT(11); -+ _mtk_mdio_write(gsw->eth, i, 0x0, val); -+ } -+ -+ /* reset the switch */ -+ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL, -+ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); -+ udelay(100); -+ -+ /* GE1, Force 1000M/FD, FC ON */ -+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC); -+ -+ /* GE2, Force 1000M/FD, FC ON */ -+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC); -+ -+ /* Enable Port 6, P5 as GMAC5, P5 disable */ -+ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP); -+ /* Enable Port 6 */ -+ val &= ~MHWTRAP_P6_DIS; -+ /* Enable Port 5 */ -+ val &= ~MHWTRAP_P5_DIS; -+ /* Port 5 as GMAC */ -+ val |= MHWTRAP_P5_MAC_SEL; -+ /* Port 5 Interface mode */ -+ val |= MHWTRAP_P5_RGMII_MODE; -+ /* Set MT7530 phy direct access mode**/ -+ val &= ~MHWTRAP_PHY_ACCESS; -+ /* manual override of HW-Trap */ -+ val |= MHWTRAP_MANUAL; -+ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val); -+ -+ val = mt7530_mdio_r32(gsw, 0x7800); -+ val = (val >> 9) & 0x3; -+ pr_err("!!%s: Mhz value= %d\n", __func__, val); -+ if (val == 0x3) { -+ xtal_mode = 1; -+ /* 25Mhz Xtal - do nothing */ -+ } else if (val == 0x2) { -+ /* 40Mhz */ -+ xtal_mode = 2; -+ -+ /* disable MT7530 core clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); -+ -+ /* disable MT7530 PLL */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2020); -+ -+ /* for MT7530 core clock = 500Mhz */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40e); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x119); -+ -+ /* enable MT7530 PLL */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2820); -+ -+ udelay(20); -+ -+ /* enable MT7530 core clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ } else { -+ xtal_mode = 3; -+ /* 20Mhz Xtal - TODO */ -+ } -+ -+ /* RGMII */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); -+ -+ /* set MT7530 central align */ -+ val = mt7530_mdio_r32(gsw, 0x7830); -+ val &= ~1; -+ val |= 1<<1; -+ mt7530_mdio_w32(gsw, 0x7830, val); -+ -+ val = mt7530_mdio_r32(gsw, 0x7a40); -+ val &= ~(1<<30); -+ mt7530_mdio_w32(gsw, 0x7a40, val); -+ -+ mt7530_mdio_w32(gsw, 0x7a78, 0x855); -+ -+ /* delay setting for 10/1000M */ -+ mt7530_mdio_w32(gsw, 0x7b00, 0x104); -+ mt7530_mdio_w32(gsw, 0x7b04, 0x10); -+ -+ /* lower Tx Driving */ -+ mt7530_mdio_w32(gsw, 0x7a54, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a5c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a64, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a6c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a74, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a7c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7810, 0x11); -+ -+ /* Set MT7623/MT7683 TX Driving */ -+ mtk_switch_w32(gsw, 0x88, 0x354); -+ mtk_switch_w32(gsw, 0x88, 0x35c); -+ mtk_switch_w32(gsw, 0x88, 0x364); -+ mtk_switch_w32(gsw, 0x88, 0x36c); -+ mtk_switch_w32(gsw, 0x88, 0x374); -+ mtk_switch_w32(gsw, 0x88, 0x37c); -+ -+#if defined (CONFIG_GE2_RGMII_AN) -+// *(volatile u_long *)(0xf0005f00) = 0xe00; //Set GE2 driving and slew rate -+#else -+ // *(volatile u_long *)(0xf0005f00) = 0xa00; //Set GE2 driving and slew rate -+#endif -+ // *(volatile u_long *)(0xf00054c0) = 0x5; //set GE2 TDSEL -+ // *(volatile u_long *)(0xf0005ed0) = 0; //set GE2 TUNE -+ -+ mt7530_trgmii_clock_setting(gsw, xtal_mode); -+ -+ //LANWANPartition(gsw); -+ -+ /* disable EEE */ -+ for (i = 0; i <= 4; i++) { -+ _mtk_mdio_write(gsw->eth, i, 13, 0x7); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x3C); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x4007); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x0); -+ -+ /* Increase SlvDPSready time */ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x52b5); -+ _mtk_mdio_write(gsw->eth, i, 16, 0xafae); -+ _mtk_mdio_write(gsw->eth, i, 18, 0x2f); -+ _mtk_mdio_write(gsw->eth, i, 16, 0x8fae); -+ -+ /* Incease post_update_timer */ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x3); -+ _mtk_mdio_write(gsw->eth, i, 17, 0x4b); -+ -+ /* Adjust 100_mse_threshold */ -+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x123); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0xffff); -+ -+ /* Disable mcc */ -+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0xa6); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x300); -+ -+ /* Disable HW auto downshift*/ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x1); -+ val = _mtk_mdio_read(gsw->eth, i, 0x14); -+ val &= ~(1<<4); -+ _mtk_mdio_write(gsw->eth, i, 0x14, val); -+ } -+ -+ /* turn on all PHYs */ -+ for (i = 0; i <= 4; i++) { -+ val = _mtk_mdio_read(gsw->eth, i, 0); -+ val &= ~BIT(11); -+ _mtk_mdio_write(gsw->eth, i, 0, val); -+ } -+ -+ /* enable irq */ -+ mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL); -+} -+ -+static const struct of_device_id mediatek_gsw_match[] = { -+ { .compatible = "mediatek,mt7623-gsw" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mediatek_gsw_match); -+ -+int mtk_gsw_init(struct mtk_eth *eth) -+{ -+ struct device_node *np = eth->switch_np; -+ struct platform_device *pdev = of_find_device_by_node(np); -+ struct mt7620_gsw *gsw; -+ -+ if (!pdev) -+ return -ENODEV; -+ -+ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) -+ return -EINVAL; -+ -+ gsw = platform_get_drvdata(pdev); -+ if (!gsw) -+ return -ENODEV; -+ gsw->eth = eth; -+ eth->sw_priv = gsw; -+ -+ mt7623_hw_init(eth, gsw, np); -+ -+ request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0, -+ "gsw", eth); -+ mt7530_mdio_w32(gsw, 0x7008, 0x1f); -+ -+ return 0; -+} -+ -+static int mt7623_gsw_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *pctl; -+ int reset_pin, ret; -+ struct mt7620_gsw *gsw; -+ struct regulator *supply; -+ -+ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); -+ if (!gsw) -+ return -ENOMEM; -+ -+ gsw->dev = &pdev->dev; -+ gsw->trgmii_force = 2000; -+ gsw->irq = irq_of_parse_and_map(np, 0); -+ if (gsw->irq < 0) -+ return -EINVAL; -+ -+ gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys"); -+ if (IS_ERR(gsw->ethsys)) -+ return PTR_ERR(gsw->ethsys); -+ -+ reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0); -+ if (reset_pin < 0) -+ return reset_pin; -+ -+ pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0); -+ if (IS_ERR(pctl)) -+ return PTR_ERR(pctl); -+ -+ gsw->pctl = syscon_node_to_regmap(pctl); -+ if (IS_ERR(pctl)) -+ return PTR_ERR(pctl); -+ -+ ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset"); -+ if (ret) -+ return ret; -+ -+ gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll"); -+ -+ if (IS_ERR(gsw->clk_trgpll)) -+ return -ENODEV; -+ -+ supply = devm_regulator_get(&pdev->dev, "mt7530"); -+ if (IS_ERR(supply)) -+ return PTR_ERR(supply); -+ -+ regulator_set_voltage(supply, 1000000, 1000000); -+ ret = regulator_enable(supply); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret); -+ return ret; -+ } -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_sync(&pdev->dev); -+ -+ ret = clk_set_rate(gsw->clk_trgpll, 500000000); -+ if (ret) -+ return ret; -+ -+ clk_prepare_enable(gsw->clk_trgpll); -+ -+ gpio_direction_output(reset_pin, 0); -+ udelay(1000); -+ gpio_set_value(reset_pin, 1); -+ mdelay(100); -+ -+ /* Set GE2 driving and slew rate */ -+ regmap_write(gsw->pctl, 0xF00, 0xa00); -+ /* set GE2 TDSEL */ -+ regmap_write(gsw->pctl, 0x4C0, 0x5); -+ /* set GE2 TUNE */ -+ regmap_write(gsw->pctl, 0xED0, 0x0); -+ -+ platform_set_drvdata(pdev, gsw); -+ -+ return 0; -+} -+ -+static int mt7623_gsw_remove(struct platform_device *pdev) -+{ -+ struct mt7620_gsw *gsw = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(gsw->clk_trgpll); -+ -+ pm_runtime_put_sync(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver gsw_driver = { -+ .probe = mt7623_gsw_probe, -+ .remove = mt7623_gsw_remove, -+ .driver = { -+ .name = "mt7623-gsw", -+ .owner = THIS_MODULE, -+ .of_match_table = mediatek_gsw_match, -+ }, -+}; -+ -+module_platform_driver(gsw_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin "); -+MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC"); -diff --git a/drivers/net/ethernet/mediatek/mt7530.c b/drivers/net/ethernet/mediatek/mt7530.c -new file mode 100644 -index 0000000..2e9d280 ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mt7530.c -@@ -0,0 +1,808 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2013 John Crispin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mt7530.h" -+ -+#define MT7530_CPU_PORT 6 -+#define MT7530_NUM_PORTS 8 -+#define MT7530_NUM_VLANS 16 -+#define MT7530_MAX_VID 4095 -+#define MT7530_MIN_VID 0 -+ -+/* registers */ -+#define REG_ESW_VLAN_VTCR 0x90 -+#define REG_ESW_VLAN_VAWD1 0x94 -+#define REG_ESW_VLAN_VAWD2 0x98 -+#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2)) -+ -+#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30) -+#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28) -+#define REG_ESW_VLAN_VAWD1_VALID BIT(0) -+ -+/* vlan egress mode */ -+enum { -+ ETAG_CTRL_UNTAG = 0, -+ ETAG_CTRL_TAG = 2, -+ ETAG_CTRL_SWAP = 1, -+ ETAG_CTRL_STACK = 3, -+}; -+ -+#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8)) -+#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8)) -+#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8)) -+ -+#define REG_HWTRAP 0x7804 -+ -+#define MIB_DESC(_s , _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+struct mt7xxx_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+#define MT7621_MIB_COUNTER_BASE 0x4000 -+#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100 -+#define MT7621_STATS_TDPC 0x00 -+#define MT7621_STATS_TCRC 0x04 -+#define MT7621_STATS_TUPC 0x08 -+#define MT7621_STATS_TMPC 0x0C -+#define MT7621_STATS_TBPC 0x10 -+#define MT7621_STATS_TCEC 0x14 -+#define MT7621_STATS_TSCEC 0x18 -+#define MT7621_STATS_TMCEC 0x1C -+#define MT7621_STATS_TDEC 0x20 -+#define MT7621_STATS_TLCEC 0x24 -+#define MT7621_STATS_TXCEC 0x28 -+#define MT7621_STATS_TPPC 0x2C -+#define MT7621_STATS_TL64PC 0x30 -+#define MT7621_STATS_TL65PC 0x34 -+#define MT7621_STATS_TL128PC 0x38 -+#define MT7621_STATS_TL256PC 0x3C -+#define MT7621_STATS_TL512PC 0x40 -+#define MT7621_STATS_TL1024PC 0x44 -+#define MT7621_STATS_TOC 0x48 -+#define MT7621_STATS_RDPC 0x60 -+#define MT7621_STATS_RFPC 0x64 -+#define MT7621_STATS_RUPC 0x68 -+#define MT7621_STATS_RMPC 0x6C -+#define MT7621_STATS_RBPC 0x70 -+#define MT7621_STATS_RAEPC 0x74 -+#define MT7621_STATS_RCEPC 0x78 -+#define MT7621_STATS_RUSPC 0x7C -+#define MT7621_STATS_RFEPC 0x80 -+#define MT7621_STATS_ROSPC 0x84 -+#define MT7621_STATS_RJEPC 0x88 -+#define MT7621_STATS_RPPC 0x8C -+#define MT7621_STATS_RL64PC 0x90 -+#define MT7621_STATS_RL65PC 0x94 -+#define MT7621_STATS_RL128PC 0x98 -+#define MT7621_STATS_RL256PC 0x9C -+#define MT7621_STATS_RL512PC 0xA0 -+#define MT7621_STATS_RL1024PC 0xA4 -+#define MT7621_STATS_ROC 0xA8 -+#define MT7621_STATS_RDPC_CTRL 0xB0 -+#define MT7621_STATS_RDPC_ING 0xB4 -+#define MT7621_STATS_RDPC_ARL 0xB8 -+ -+static const struct mt7xxx_mib_desc mt7621_mibs[] = { -+ MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"), -+ MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"), -+ MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"), -+ MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"), -+ MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"), -+ MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"), -+ MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"), -+ MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"), -+ MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"), -+ MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"), -+ MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"), -+ MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"), -+ MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"), -+ MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"), -+ MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"), -+ MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"), -+ MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"), -+ MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"), -+ MIB_DESC(2, MT7621_STATS_TOC, "TxByte"), -+ MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"), -+ MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"), -+ MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"), -+ MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"), -+ MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"), -+ MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"), -+ MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"), -+ MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"), -+ MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"), -+ MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"), -+ MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"), -+ MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"), -+ MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"), -+ MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"), -+ MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"), -+ MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"), -+ MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"), -+ MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"), -+ MIB_DESC(2, MT7621_STATS_ROC, "RxByte"), -+ MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"), -+ MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"), -+ MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop") -+}; -+ -+enum { -+ /* Global attributes. */ -+ MT7530_ATTR_ENABLE_VLAN, -+}; -+ -+struct mt7530_port_entry { -+ u16 pvid; -+}; -+ -+struct mt7530_vlan_entry { -+ u16 vid; -+ u8 member; -+ u8 etags; -+}; -+ -+struct mt7530_priv { -+ void __iomem *base; -+ struct mii_bus *bus; -+ struct switch_dev swdev; -+ -+ bool global_vlan_enable; -+ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS]; -+ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS]; -+}; -+ -+struct mt7530_mapping { -+ char *name; -+ u16 pvids[MT7530_NUM_PORTS]; -+ u8 members[MT7530_NUM_VLANS]; -+ u8 etags[MT7530_NUM_VLANS]; -+ u16 vids[MT7530_NUM_VLANS]; -+} mt7530_defaults[] = { -+ { -+ .name = "llllw", -+ .pvids = { 1, 1, 1, 1, 2, 1, 1 }, -+ .members = { 0, 0x6f, 0x50 }, -+ .etags = { 0, 0x40, 0x40 }, -+ .vids = { 0, 1, 2 }, -+ }, { -+ .name = "wllll", -+ .pvids = { 2, 1, 1, 1, 1, 1, 1 }, -+ .members = { 0, 0x7e, 0x41 }, -+ .etags = { 0, 0x40, 0x40 }, -+ .vids = { 0, 1, 2 }, -+ }, -+}; -+ -+struct mt7530_mapping* -+mt7530_find_mapping(struct device_node *np) -+{ -+ const char *map; -+ int i; -+ -+ if (of_property_read_string(np, "mediatek,portmap", &map)) -+ return NULL; -+ -+ for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++) -+ if (!strcmp(map, mt7530_defaults[i].name)) -+ return &mt7530_defaults[i]; -+ -+ return NULL; -+} -+ -+static void -+mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map) -+{ -+ int i = 0; -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530->port_entries[i].pvid = map->pvids[i]; -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ mt7530->vlan_entries[i].member = map->members[i]; -+ mt7530->vlan_entries[i].etags = map->etags[i]; -+ mt7530->vlan_entries[i].vid = map->vids[i]; -+ } -+} -+ -+static int -+mt7530_reset_switch(struct switch_dev *dev) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i; -+ -+ memset(eth->port_entries, 0, sizeof(eth->port_entries)); -+ memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries)); -+ -+ /* set default vid of each vlan to the same number of vlan, so the vid -+ * won't need be set explicitly. -+ */ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ eth->vlan_entries[i].vid = i; -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_get_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ val->value.i = eth->global_vlan_enable; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ eth->global_vlan_enable = val->value.i != 0; -+ -+ return 0; -+} -+ -+static u32 -+mt7530_r32(struct mt7530_priv *eth, u32 reg) -+{ -+ u32 val; -+ if (eth->bus) { -+ u16 high, low; -+ -+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf); -+ high = mdiobus_read(eth->bus, 0x1f, 0x10); -+ -+ return (high << 16) | (low & 0xffff); -+ } -+ -+ val = ioread32(eth->base + reg); -+ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val); -+ -+ return val; -+} -+ -+static void -+mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val) -+{ -+ if (eth->bus) { -+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff); -+ mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16); -+ return; -+ } -+ -+ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val); -+ iowrite32(val, eth->base + reg); -+} -+ -+static void -+mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val) -+{ -+ int i; -+ -+ mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val); -+ -+ for (i = 0; i < 20; i++) { -+ u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR); -+ -+ if ((val & BIT(31)) == 0) -+ break; -+ -+ udelay(1000); -+ } -+ if (i == 20) -+ printk("mt7530: vtcr timeout\n"); -+} -+ -+static int -+mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ if (port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ *val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port)); -+ *val &= 0xfff; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ if (port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID) -+ return -EINVAL; -+ -+ eth->port_entries[port].pvid = pvid; -+ -+ return 0; -+} -+ -+static int -+mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 member; -+ u32 etags; -+ int i; -+ -+ val->len = 0; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS) -+ return -EINVAL; -+ -+ mt7530_vtcr(eth, 0, val->port_vlan); -+ -+ member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1); -+ member >>= 16; -+ member &= 0xff; -+ -+ etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ struct switch_port *p; -+ int etag; -+ -+ if (!(member & BIT(i))) -+ continue; -+ -+ p = &val->value.ports[val->len++]; -+ p->id = i; -+ -+ etag = (etags >> (i * 2)) & 0x3; -+ -+ if (etag == ETAG_CTRL_TAG) -+ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED); -+ else if (etag != ETAG_CTRL_UNTAG) -+ printk("vlan egress tag control neither untag nor tag.\n"); -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u8 member = 0; -+ u8 etags = 0; -+ int i; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS || -+ val->len > MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ for (i = 0; i < val->len; i++) { -+ struct switch_port *p = &val->value.ports[i]; -+ -+ if (p->id >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ member |= BIT(p->id); -+ -+ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) -+ etags |= BIT(p->id); -+ } -+ eth->vlan_entries[val->port_vlan].member = member; -+ eth->vlan_entries[val->port_vlan].etags = etags; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int vlan; -+ u16 vid; -+ -+ vlan = val->port_vlan; -+ vid = (u16)val->value.i; -+ -+ if (vlan < 0 || vlan >= MT7530_NUM_VLANS) -+ return -EINVAL; -+ -+ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID) -+ return -EINVAL; -+ -+ eth->vlan_entries[vlan].vid = vid; -+ return 0; -+} -+ -+static int -+mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 vid; -+ int vlan; -+ -+ vlan = val->port_vlan; -+ -+ vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan)); -+ if (vlan & 1) -+ vid = vid >> 12; -+ vid &= 0xfff; -+ -+ val->value.i = vid; -+ return 0; -+} -+ -+static int -+mt7530_apply_config(struct switch_dev *dev) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i, j; -+ u8 tag_ports; -+ u8 untag_ports; -+ -+ if (!eth->global_vlan_enable) { -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0); -+ -+ return 0; -+ } -+ -+ /* set all ports as security mode */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003); -+ -+ /* check if a port is used in tag/untag vlan egress mode */ -+ tag_ports = 0; -+ untag_ports = 0; -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ u8 member = eth->vlan_entries[i].member; -+ u8 etags = eth->vlan_entries[i].etags; -+ -+ if (!member) -+ continue; -+ -+ for (j = 0; j < MT7530_NUM_PORTS; j++) { -+ if (!(member & BIT(j))) -+ continue; -+ -+ if (etags & BIT(j)) -+ tag_ports |= 1u << j; -+ else -+ untag_ports |= 1u << j; -+ } -+ } -+ -+ /* set all untag-only ports as transparent and the rest as user port */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ u32 pvc_mode = 0x81000000; -+ -+ if (untag_ports & BIT(i) && !(tag_ports & BIT(i))) -+ pvc_mode = 0x810000c0; -+ -+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode); -+ } -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ u16 vid = eth->vlan_entries[i].vid; -+ u8 member = eth->vlan_entries[i].member; -+ u8 etags = eth->vlan_entries[i].etags; -+ u32 val; -+ -+ /* vid of vlan */ -+ val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i)); -+ if (i % 2 == 0) { -+ val &= 0xfff000; -+ val |= vid; -+ } else { -+ val &= 0xfff; -+ val |= (vid << 12); -+ } -+ mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val); -+ -+ /* vlan port membership */ -+ if (member) -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC | -+ REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) | -+ REG_ESW_VLAN_VAWD1_VALID); -+ else -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0); -+ -+ /* egress mode */ -+ val = 0; -+ for (j = 0; j < MT7530_NUM_PORTS; j++) { -+ if (etags & BIT(j)) -+ val |= ETAG_CTRL_TAG << (j * 2); -+ else -+ val |= ETAG_CTRL_UNTAG << (j * 2); -+ } -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val); -+ -+ /* write to vlan table */ -+ mt7530_vtcr(eth, 1, i); -+ } -+ -+ /* Port Default PVID */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ u32 val; -+ val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i)); -+ val &= ~0xfff; -+ val |= eth->port_entries[i].pvid; -+ mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val); -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_get_port_link(struct switch_dev *dev, int port, -+ struct switch_port_link *link) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 speed, pmsr; -+ -+ if (port < 0 || port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port)); -+ -+ link->link = pmsr & 1; -+ link->duplex = (pmsr >> 1) & 1; -+ speed = (pmsr >> 2) & 3; -+ -+ switch (speed) { -+ case 0: -+ link->speed = SWITCH_PORT_SPEED_10; -+ break; -+ case 1: -+ link->speed = SWITCH_PORT_SPEED_100; -+ break; -+ case 2: -+ case 3: /* forced gige speed can be 2 or 3 */ -+ link->speed = SWITCH_PORT_SPEED_1000; -+ break; -+ default: -+ link->speed = SWITCH_PORT_SPEED_UNKNOWN; -+ break; -+ } -+ -+ return 0; -+} -+ -+static const struct switch_attr mt7530_global[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_vlan", -+ .description = "VLAN mode (1:enabled)", -+ .max = 1, -+ .id = MT7530_ATTR_ENABLE_VLAN, -+ .get = mt7530_get_vlan_enable, -+ .set = mt7530_set_vlan_enable, -+ }, -+}; -+ -+static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port) -+{ -+ unsigned int port_base; -+ u64 t; -+ -+ port_base = MT7621_MIB_COUNTER_BASE + -+ MT7621_MIB_COUNTER_PORT_OFFSET * port; -+ -+ t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset); -+ if (mt7621_mibs[i].size == 2) { -+ u64 hi; -+ -+ hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4); -+ t |= hi << 32; -+ } -+ -+ return t; -+} -+ -+static int mt7621_sw_get_port_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ static char buf[4096]; -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i, len = 0; -+ -+ if (val->port_vlan >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ len += snprintf(buf + len, sizeof(buf) - len, -+ "Port %d MIB counters\n", val->port_vlan); -+ -+ for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) { -+ u64 counter; -+ len += snprintf(buf + len, sizeof(buf) - len, -+ "%-11s: ", mt7621_mibs[i].name); -+ counter = get_mib_counter(eth, i, val->port_vlan); -+ len += snprintf(buf + len, sizeof(buf) - len, "%llu\n", -+ counter); -+ } -+ -+ val->value.s = buf; -+ val->len = len; -+ return 0; -+} -+ -+static const struct switch_attr mt7621_port[] = { -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "mib", -+ .description = "Get MIB counters for port", -+ .get = mt7621_sw_get_port_mib, -+ .set = NULL, -+ }, -+}; -+ -+static const struct switch_attr mt7530_port[] = { -+}; -+ -+static const struct switch_attr mt7530_vlan[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "vid", -+ .description = "VLAN ID (0-4094)", -+ .set = mt7530_set_vid, -+ .get = mt7530_get_vid, -+ .max = 4094, -+ }, -+}; -+ -+static const struct switch_dev_ops mt7621_ops = { -+ .attr_global = { -+ .attr = mt7530_global, -+ .n_attr = ARRAY_SIZE(mt7530_global), -+ }, -+/* .attr_port = { -+ .attr = mt7621_port, -+ .n_attr = ARRAY_SIZE(mt7621_port), -+ },*/ -+ .attr_vlan = { -+ .attr = mt7530_vlan, -+ .n_attr = ARRAY_SIZE(mt7530_vlan), -+ }, -+ .get_vlan_ports = mt7530_get_vlan_ports, -+ .set_vlan_ports = mt7530_set_vlan_ports, -+ .get_port_pvid = mt7530_get_port_pvid, -+ .set_port_pvid = mt7530_set_port_pvid, -+ .get_port_link = mt7530_get_port_link, -+ .apply_config = mt7530_apply_config, -+ .reset_switch = mt7530_reset_switch, -+}; -+ -+static const struct switch_dev_ops mt7530_ops = { -+ .attr_global = { -+ .attr = mt7530_global, -+ .n_attr = ARRAY_SIZE(mt7530_global), -+ }, -+ .attr_port = { -+ .attr = mt7530_port, -+ .n_attr = ARRAY_SIZE(mt7530_port), -+ }, -+ .attr_vlan = { -+ .attr = mt7530_vlan, -+ .n_attr = ARRAY_SIZE(mt7530_vlan), -+ }, -+ .get_vlan_ports = mt7530_get_vlan_ports, -+ .set_vlan_ports = mt7530_set_vlan_ports, -+ .get_port_pvid = mt7530_get_port_pvid, -+ .set_port_pvid = mt7530_set_port_pvid, -+ .get_port_link = mt7530_get_port_link, -+ .apply_config = mt7530_apply_config, -+ .reset_switch = mt7530_reset_switch, -+}; -+ -+int -+mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan) -+{ -+ struct switch_dev *swdev; -+ struct mt7530_priv *mt7530; -+ struct mt7530_mapping *map; -+ int ret; -+ -+ mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL); -+ if (!mt7530) -+ return -ENOMEM; -+ -+ mt7530->base = base; -+ mt7530->bus = bus; -+ mt7530->global_vlan_enable = vlan; -+ -+ swdev = &mt7530->swdev; -+ if (bus) { -+ swdev->alias = "mt7530"; -+ swdev->name = "mt7530"; -+ } else if (IS_ENABLED(CONFIG_MACH_MT7623)) { -+ swdev->alias = "mt7623"; -+ swdev->name = "mt7623"; -+ } else if (IS_ENABLED(CONFIG_SOC_MT7621)) { -+ swdev->alias = "mt7621"; -+ swdev->name = "mt7621"; -+ } else { -+ swdev->alias = "mt7620"; -+ swdev->name = "mt7620"; -+ } -+ swdev->cpu_port = MT7530_CPU_PORT; -+ swdev->ports = MT7530_NUM_PORTS; -+ swdev->vlans = MT7530_NUM_VLANS; -+ if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) -+ swdev->ops = &mt7621_ops; -+ else -+ swdev->ops = &mt7530_ops; -+ -+ ret = register_switch(swdev, NULL); -+ if (ret) { -+ dev_err(dev, "failed to register mt7530\n"); -+ return ret; -+ } -+ -+ mt7530_reset_switch(swdev); -+ -+ map = mt7530_find_mapping(dev->of_node); -+ if (map) -+ mt7530_apply_mapping(mt7530, map); -+ mt7530_apply_config(swdev); -+ -+ /* magic vodoo */ -+ if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) { -+ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n"); -+ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf); -+ } -+ dev_info(dev, "loaded %s driver\n", swdev->name); -+ -+ return 0; -+} -diff --git a/drivers/net/ethernet/mediatek/mt7530.h b/drivers/net/ethernet/mediatek/mt7530.h -new file mode 100644 -index 0000000..1fc8c62 ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mt7530.h -@@ -0,0 +1,20 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2013 John Crispin -+ */ -+ -+#ifndef _MT7530_H__ -+#define _MT7530_H__ -+ -+int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan); -+ -+#endif -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index 7f2126b..dd7f6e3 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -24,6 +24,9 @@ - - #include "mtk_eth_soc.h" - -+/* the callback used by the driver core to bringup the switch */ -+int mtk_gsw_init(struct mtk_eth *eth); -+ - static int mtk_msg_level = -1; - module_param_named(msg_level, mtk_msg_level, int, 0); - MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); -@@ -69,7 +72,7 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth) - return 0; - if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) - break; -- usleep_range(10, 20); -+// usleep_range(10, 20); - } - - dev_err(eth->dev, "mdio: MDIO timeout\n"); -@@ -138,6 +141,15 @@ static void mtk_phy_link_adjust(struct net_device *dev) - MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | - MAC_MCR_BACKPR_EN; - -+ if (!mac->id) { -+ mcr |= MAC_MCR_SPEED_1000; -+ mcr |= MAC_MCR_FORCE_LINK; -+ mcr |= MAC_MCR_FORCE_DPX; -+ mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC; -+ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); -+ return; -+ } -+ - switch (mac->phy_dev->speed) { - case SPEED_1000: - mcr |= MAC_MCR_SPEED_1000; -@@ -157,11 +169,12 @@ static void mtk_phy_link_adjust(struct net_device *dev) - mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC; - - mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); -- - if (mac->phy_dev->link) - netif_carrier_on(dev); - else - netif_carrier_off(dev); -+ -+ return; - } - - static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, -@@ -193,7 +206,7 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, - - dev_info(eth->dev, - "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", -- mac->id, phydev_name(phydev), phydev->phy_id, -+ mac->id, dev_name(&phydev->dev), phydev->phy_id, - phydev->drv->name); - - mac->phy_dev = phydev; -@@ -634,7 +647,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, - - spin_unlock_irqrestore(ð->page_lock, flags); - -- netdev_sent_queue(dev, skb->len); - skb_tx_timestamp(skb); - - ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); -@@ -884,7 +896,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) - for (i = 0; i < MTK_MAC_COUNT; i++) { - if (!eth->netdev[i] || !done[i]) - continue; -- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); - total += done[i]; - } - -@@ -1251,6 +1262,8 @@ static int mtk_open(struct net_device *dev) - phy_start(mac->phy_dev); - netif_start_queue(dev); - -+ netif_carrier_on(dev); -+ - return 0; - } - -@@ -1283,6 +1296,7 @@ static int mtk_stop(struct net_device *dev) - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; - -+ netif_carrier_off(dev); - netif_tx_disable(dev); - phy_stop(mac->phy_dev); - -@@ -1328,6 +1342,7 @@ static int __init mtk_hw_init(struct mtk_eth *eth) - /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - -+ mtk_gsw_init(eth); - err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0, - dev_name(eth->dev), eth); - if (err) -@@ -1360,6 +1375,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth) - mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); - } - -+ mt7623_gsw_config(eth); -+ - return 0; - } - -@@ -1466,11 +1483,13 @@ static int mtk_set_settings(struct net_device *dev, - { - struct mtk_mac *mac = netdev_priv(dev); - -- if (cmd->phy_address != mac->phy_dev->mdio.addr) { -- mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus, -- cmd->phy_address); -- if (!mac->phy_dev) -+ if (cmd->phy_address != mac->phy_dev->addr) { -+ if (mac->hw->mii_bus->phy_map[cmd->phy_address]) { -+ mac->phy_dev = -+ mac->hw->mii_bus->phy_map[cmd->phy_address]; -+ } else { - return -ENODEV; -+ } - } - - return phy_ethtool_sset(mac->phy_dev, cmd); -@@ -1563,7 +1582,6 @@ static void mtk_get_ethtool_stats(struct net_device *dev, - data_src = (u64*)hwstats; - data_dst = data; - start = u64_stats_fetch_begin_irq(&hwstats->syncp); -- - for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) - *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); - } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); -@@ -1734,6 +1752,9 @@ static int mtk_probe(struct platform_device *pdev) - clk_prepare_enable(eth->clk_gp1); - clk_prepare_enable(eth->clk_gp2); - -+ eth->switch_np = of_parse_phandle(pdev->dev.of_node, -+ "mediatek,switch", 0); -+ - eth->dev = &pdev->dev; - eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -index 48a5292..d737d61 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -389,6 +389,9 @@ struct mtk_eth { - struct clk *clk_gp1; - struct clk *clk_gp2; - struct mii_bus *mii_bus; -+ -+ struct device_node *switch_np; -+ void *sw_priv; - }; - - /* struct mtk_mac - the structure that holds the info about the MACs of the -@@ -418,4 +421,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac); - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); - u32 mtk_r32(struct mtk_eth *eth, unsigned reg); - -+int mt7623_gsw_config(struct mtk_eth *eth); -+ - #endif /* MTK_ETH_H */ --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0058-dont-disable-clocks.patch b/target/linux/mediatek/patches-4.4/0058-dont-disable-clocks.patch deleted file mode 100644 index d91915ccde..0000000000 --- a/target/linux/mediatek/patches-4.4/0058-dont-disable-clocks.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 36875ed8153d9b1eeae676579302a2fc746b286b Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 23 Jun 2015 23:46:00 +0200 -Subject: [PATCH 58/66] dont disable clocks - ---- - drivers/clk/clk.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index f13c3f4..5e9ddae 100644 ---- a/drivers/clk/clk.c -+++ b/drivers/clk/clk.c -@@ -233,7 +233,7 @@ unlock_out: - clk_enable_unlock(flags); - } - --static bool clk_ignore_unused; -+static bool clk_ignore_unused = true; - static int __init clk_ignore_unused_setup(char *__unused) - { - clk_ignore_unused = true; --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch new file mode 100644 index 0000000000..df3c218476 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch @@ -0,0 +1,1798 @@ +From cc1959d5bc9a709729fcd02d78f4c27394393109 Mon Sep 17 00:00:00 2001 +From: Jorge Ramirez-Ortiz +Date: Wed, 2 Mar 2016 12:00:12 -0500 +Subject: [PATCH 58/78] mtd: mediatek: driver for MTK Smart Device Gen1 NAND + +This patch adds support for mediatek's SDG1 NFC nand controller +embedded in SoC 2701. + +UBIFS support has been successfully tested. + +Signed-off-by: Jorge Ramirez-Ortiz +--- + drivers/mtd/nand/Kconfig | 6 + + drivers/mtd/nand/Makefile | 1 + + drivers/mtd/nand/mtksdg1_nand.c | 1535 +++++++++++++++++++++++++++++++++++ + drivers/mtd/nand/mtksdg1_nand_ecc.h | 75 ++ + drivers/mtd/nand/mtksdg1_nand_nfi.h | 119 +++ + 5 files changed, 1736 insertions(+) + create mode 100644 drivers/mtd/nand/mtksdg1_nand.c + create mode 100644 drivers/mtd/nand/mtksdg1_nand_ecc.h + create mode 100644 drivers/mtd/nand/mtksdg1_nand_nfi.h + +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index 2896640..5ec072a 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -546,4 +546,10 @@ config MTD_NAND_HISI504 + help + Enables support for NAND controller on Hisilicon SoC Hip04. + ++config MTD_NAND_MTKSDG1 ++ tristate "Support for NAND controller on MTK Smart Device SoCs" ++ depends on HAS_DMA ++ help ++ Enables support for NAND controller on MTK Smart Device SoCs. ++ + endif # MTD_NAND +diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile +index 2c7f014..2a2620c 100644 +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ + obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o + obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o + obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ ++obj-$(CONFIG_MTD_NAND_MTKSDG1) += mtksdg1_nand.o + + nand-objs := nand_base.o nand_bbt.o nand_timings.o +diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c +new file mode 100644 +index 0000000..55dd17d +--- /dev/null ++++ b/drivers/mtd/nand/mtksdg1_nand.c +@@ -0,0 +1,1535 @@ ++/* ++ * MTK smart device NAND Flash controller driver. ++ * Copyright (C) 2015-2016 MediaTek Inc. ++ * Authors: Xiaolei Li ++ * Jorge Ramirez-Ortiz ++ * ++ * 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 "mtksdg1_nand_nfi.h" ++#include "mtksdg1_nand_ecc.h" ++ ++#define MTK_IRQ_ECC "mtksdg1-nand-ecc" ++#define MTK_IRQ_NFI "mtksdg1-nand-nfi" ++#define MTK_NAME "mtksdg1-nand" ++ ++#define KB(x) ((x) * 1024UL) ++#define MB(x) (KB(x) * 1024UL) ++ ++#define SECTOR_SHIFT (10) ++#define SECTOR_SIZE (1UL << SECTOR_SHIFT) ++#define BYTES_TO_SECTORS(x) ((x) >> SECTOR_SHIFT) ++#define SECTORS_TO_BYTES(x) ((x) << SECTOR_SHIFT) ++ ++#define MTK_TIMEOUT (500) ++#define MTK_RESET_TIMEOUT (1 * HZ) ++ ++#define MTK_ECC_PARITY_BITS (14) ++#define MTK_NAND_MAX_CHIP (2) ++ ++#define MTK_OOB_ON (1) ++#define MTK_OOB_OFF (0) ++ ++/* raw accesses do not use ECC (ecc = !raw) */ ++#define MTK_ECC_OFF (1) ++#define MTK_ECC_ON (0) ++ ++struct mtk_nfc_clk { ++ struct clk *nfiecc_clk; ++ struct clk *nfi_clk; ++ struct clk *pad_clk; ++}; ++ ++struct mtk_nfc_saved_reg { ++ struct { ++ u32 enccnfg; ++ u32 deccnfg; ++ } ecc; ++ struct { ++ u32 emp_thresh; ++ u16 pagefmt; ++ u32 acccon; ++ u16 cnrnb; ++ u16 csel; ++ } nfi; ++}; ++ ++struct mtk_nfc_host { ++ struct mtk_nfc_clk clk; ++ struct nand_chip chip; ++ struct device *dev; ++ ++ struct { ++ struct completion complete; ++ void __iomem *base; ++ } nfi; ++ ++ struct { ++ struct completion complete; ++ void __iomem *base; ++ u32 dec_sec; ++ } ecc; ++ ++ u32 fdm_reg[MTKSDG1_NFI_FDM_REG_SIZE / sizeof(u32)]; ++ bool switch_oob; ++ u32 row_nob; ++ u8 *buffer; ++ ++#ifdef CONFIG_PM_SLEEP ++ struct mtk_nfc_saved_reg saved_reg; ++#endif ++}; ++ ++static struct nand_ecclayout nand_2k_64 = { ++ .oobfree = { {0, 16} }, ++}; ++ ++static struct nand_ecclayout nand_4k_128 = { ++ .oobfree = { {0, 32} }, ++}; ++ ++/* NFI register access */ ++static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg) ++{ ++ writel(val, host->nfi.base + reg); ++} ++static inline void mtk_nfi_writew(struct mtk_nfc_host *host, u16 val, u32 reg) ++{ ++ writew(val, host->nfi.base + reg); ++} ++static inline u32 mtk_nfi_readl(struct mtk_nfc_host *host, u32 reg) ++{ ++ return readl_relaxed(host->nfi.base + reg); ++} ++static inline u16 mtk_nfi_readw(struct mtk_nfc_host *host, u32 reg) ++{ ++ return readw_relaxed(host->nfi.base + reg); ++} ++static inline u8 mtk_nfi_readb(struct mtk_nfc_host *host, u32 reg) ++{ ++ return readb_relaxed(host->nfi.base + reg); ++} ++ ++/* ECC register access */ ++static inline void mtk_ecc_writel(struct mtk_nfc_host *host, u32 val, u32 reg) ++{ ++ writel(val, host->ecc.base + reg); ++} ++static inline void mtk_ecc_writew(struct mtk_nfc_host *host, u16 val, u32 reg) ++{ ++ writew(val, host->ecc.base + reg); ++} ++static inline u32 mtk_ecc_readl(struct mtk_nfc_host *host, u32 reg) ++{ ++ return readl_relaxed(host->ecc.base + reg); ++} ++static inline u16 mtk_ecc_readw(struct mtk_nfc_host *host, u32 reg) ++{ ++ return readw_relaxed(host->ecc.base + reg); ++} ++ ++static void mtk_nfc_hw_reset(struct mtk_nfc_host *host) ++{ ++ unsigned long timeout = MTK_RESET_TIMEOUT; ++ struct device *dev = host->dev; ++ u32 val; ++ ++ /* reset the state machine, data fifo and fdm data */ ++ mtk_nfi_writel(host, CON_FIFO_FLUSH | CON_NFI_RST, MTKSDG1_NFI_CON); ++ timeout += jiffies; ++ do { ++ val = mtk_nfi_readl(host, MTKSDG1_NFI_MASTER_STA); ++ val &= MASTER_STA_MASK; ++ if (!val) ++ return; ++ usleep_range(50, 100); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ dev_warn(dev, "nfi master active after in reset [0x%x] = 0x%x\n", ++ MTKSDG1_NFI_MASTER_STA, val); ++}; ++ ++static int mtk_nfc_set_command(struct mtk_nfc_host *host, u8 command) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct device *dev = host->dev; ++ u32 val; ++ ++ mtk_nfi_writel(host, command, MTKSDG1_NFI_CMD); ++ ++ /* wait for the NFI core to enter command mode */ ++ timeout += jiffies; ++ do { ++ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA); ++ val &= STA_CMD; ++ if (!val) ++ return 0; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ dev_warn(dev, "nfi core timed out entering command mode\n"); ++ ++ return -EIO; ++} ++ ++static int mtk_nfc_set_address(struct mtk_nfc_host *host, u32 column, u32 row, ++ u8 colnob, u8 row_nob) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct device *dev = host->dev; ++ u32 addr_nob, val; ++ ++ addr_nob = colnob | (row_nob << ADDR_ROW_NOB_SHIFT); ++ mtk_nfi_writel(host, column, MTKSDG1_NFI_COLADDR); ++ mtk_nfi_writel(host, row, MTKSDG1_NFI_ROWADDR); ++ mtk_nfi_writel(host, addr_nob, MTKSDG1_NFI_ADDRNOB); ++ ++ /* wait for the NFI core to enter address mode */ ++ timeout += jiffies; ++ do { ++ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA); ++ val &= STA_ADDR; ++ if (!val) ++ return 0; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ dev_warn(dev, "nfi core timed out entering address mode\n"); ++ ++ return -EIO; ++} ++ ++static inline void mtk_ecc_encoder_idle(struct mtk_nfc_host *host) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct device *dev = host->dev; ++ u32 val; ++ ++ timeout += jiffies; ++ do { ++ val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIDLE); ++ val &= ENC_IDLE; ++ if (val) ++ return; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ dev_warn(dev, "hw init ecc encoder not idle\n"); ++} ++ ++static inline void mtk_ecc_decoder_idle(struct mtk_nfc_host *host) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct device *dev = host->dev; ++ u32 val; ++ ++ timeout += jiffies; ++ do { ++ val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIDLE); ++ val &= DEC_IDLE; ++ if (val) ++ return; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ dev_warn(dev, "hw init ecc decoder not idle\n"); ++} ++ ++static int mtk_nfc_transfer_done(struct mtk_nfc_host *host, u32 sectors) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ u32 cnt; ++ ++ /* wait for the sector count */ ++ timeout += jiffies; ++ do { ++ cnt = mtk_nfi_readl(host, MTKSDG1_NFI_ADDRCNTR); ++ cnt &= CNTR_MASK; ++ if (cnt >= sectors) ++ return 0; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ return -EIO; ++} ++ ++static int mtk_nfc_subpage_done(struct mtk_nfc_host *host, int sectors) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ u32 val; ++ ++ timeout += jiffies; ++ do { ++ val = mtk_nfi_readl(host, MTKSDG1_NFI_BYTELEN); ++ val &= CNTR_MASK; ++ if (val >= sectors) ++ return 0; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ return -EIO; ++} ++ ++static inline int mtk_nfc_data_ready(struct mtk_nfc_host *host) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ u8 val; ++ ++ timeout += jiffies; ++ do { ++ val = mtk_nfi_readw(host, MTKSDG1_NFI_PIO_DIRDY); ++ val &= PIO_DI_RDY; ++ if (val) ++ return 0; ++ cpu_relax(); ++ ++ } while (time_before(jiffies, timeout)); ++ ++ /* data _MUST_ not be accessed */ ++ return -EIO; ++} ++ ++static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ struct device *dev = host->dev; ++ u32 dec_size, enc_size; ++ u32 ecc_bit, ecc_level; ++ u32 spare, fmt; ++ u32 reg; ++ ++ host->row_nob = 1; ++ if (chip->chipsize > MB(32)) ++ host->row_nob = chip->chipsize > MB(128) ? 3 : 2; ++ ++ spare = mtd->oobsize / BYTES_TO_SECTORS(mtd->writesize); ++ switch (spare) { ++ case 16: ++ ecc_bit = ECC_CNFG_4BIT; ++ ecc_level = 4; ++ break; ++ case 32: ++ ecc_bit = ECC_CNFG_12BIT; ++ ecc_level = 12; ++ break; ++ default: ++ dev_err(dev, "invalid spare size per sector: %d\n", spare); ++ return -EINVAL; ++ } ++ ++ chip->ecc.strength = ecc_level; ++ chip->ecc.size = SECTOR_SIZE; ++ ++ switch (mtd->writesize) { ++ case KB(2): ++ fmt = PAGEFMT_512_2K; ++ chip->ecc.layout = &nand_2k_64; ++ break; ++ case KB(4): ++ fmt = PAGEFMT_2K_4K; ++ chip->ecc.layout = &nand_4k_128; ++ break; ++ case KB(8): ++ fmt = PAGEFMT_4K_8K; ++ break; ++ default: ++ dev_err(dev, "invalid page size: %d\n", mtd->writesize); ++ return -EINVAL; ++ } ++ ++ /* configure PAGE FMT */ ++ reg = fmt; ++ reg |= PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT; ++ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_SHIFT; ++ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_ECC_SHIFT; ++ mtk_nfi_writew(host, reg, MTKSDG1_NFI_PAGEFMT); ++ ++ /* configure ECC encoder (in bits) */ ++ enc_size = (SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE) << 3; ++ reg = ecc_bit | ECC_NFI_MODE | (enc_size << ECC_MS_SHIFT); ++ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); ++ ++ /* configure ECC decoder (inbits) */ ++ dec_size = enc_size + ecc_level * MTK_ECC_PARITY_BITS; ++ reg = ecc_bit | ECC_NFI_MODE | (dec_size << ECC_MS_SHIFT); ++ reg |= (DEC_CNFG_CORRECT | DEC_EMPTY_EN); ++ mtk_ecc_writel(host, reg, MTKSDG1_ECC_DECCNFG); ++ ++ return 0; ++} ++ ++static void mtk_nfc_device_reset(struct mtk_nfc_host *host) ++{ ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct device *dev = host->dev; ++ u16 chip; ++ int rc; ++ ++ mtk_nfc_hw_reset(host); ++ ++ /* enable reset done interrupt */ ++ mtk_nfi_writew(host, INTR_RST_DONE_EN, MTKSDG1_NFI_INTR_EN); ++ ++ /* configure FSM for reset operation */ ++ mtk_nfi_writew(host, CNFG_OP_RESET, MTKSDG1_NFI_CNFG); ++ ++ init_completion(&host->nfi.complete); ++ ++ mtk_nfc_set_command(host, NAND_CMD_RESET); ++ rc = wait_for_completion_timeout(&host->nfi.complete, timeout); ++ if (!rc) { ++ chip = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL); ++ dev_err(dev, "device(%d) reset timeout\n", chip); ++ } ++} ++ ++static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip) ++{ ++ struct nand_chip *nand = mtd_to_nand(mtd); ++ struct mtk_nfc_host *host = nand_get_controller_data(nand); ++ ++ if (chip < 0) ++ return; ++ ++ mtk_nfi_writel(host, chip, MTKSDG1_NFI_CSEL); ++} ++ ++static inline bool mtk_nfc_cmd_supported(unsigned command) ++{ ++ switch (command) { ++ case NAND_CMD_RESET: ++ case NAND_CMD_READID: ++ case NAND_CMD_STATUS: ++ case NAND_CMD_READOOB: ++ case NAND_CMD_ERASE1: ++ case NAND_CMD_ERASE2: ++ case NAND_CMD_SEQIN: ++ case NAND_CMD_PAGEPROG: ++ case NAND_CMD_CACHEDPROG: ++ case NAND_CMD_READ0: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static void mtk_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column, ++ int page_addr) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(mtd_to_nand(mtd)); ++ unsigned long const cmd_timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ struct completion *p = &host->nfi.complete; ++ u32 val; ++ int rc; ++ ++ if (mtk_nfc_cmd_supported(command)) ++ mtk_nfc_hw_reset(host); ++ ++ switch (command) { ++ case NAND_CMD_RESET: ++ mtk_nfc_device_reset(host); ++ break; ++ case NAND_CMD_READID: ++ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD; ++ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_READID); ++ mtk_nfc_set_address(host, column, 0, 1, 0); ++ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON); ++ break; ++ case NAND_CMD_STATUS: ++ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD; ++ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_STATUS); ++ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON); ++ break; ++ case NAND_CMD_READOOB: ++ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_READ; ++ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_READ0); ++ column += mtd->writesize; ++ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob); ++ val = CON_BRD | (1 << CON_SEC_SHIFT); ++ mtk_nfi_writel(host, val, MTKSDG1_NFI_CON); ++ break; ++ case NAND_CMD_ERASE1: ++ mtk_nfi_writew(host, INTR_ERS_DONE_EN, MTKSDG1_NFI_INTR_EN); ++ mtk_nfi_writew(host, CNFG_OP_ERASE, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_ERASE1); ++ mtk_nfc_set_address(host, 0, page_addr, 0, host->row_nob); ++ break; ++ case NAND_CMD_ERASE2: ++ init_completion(p); ++ mtk_nfc_set_command(host, NAND_CMD_ERASE2); ++ rc = wait_for_completion_timeout(p, cmd_timeout); ++ if (!rc) ++ dev_err(host->dev, "erase command timeout\n"); ++ break; ++ case NAND_CMD_SEQIN: ++ mtk_nfi_writew(host, CNFG_OP_PRGM, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_SEQIN); ++ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob); ++ break; ++ case NAND_CMD_PAGEPROG: ++ case NAND_CMD_CACHEDPROG: ++ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN); ++ init_completion(p); ++ mtk_nfc_set_command(host, command); ++ rc = wait_for_completion_timeout(p, cmd_timeout); ++ if (!rc) ++ dev_err(host->dev, "pageprogr command timeout\n"); ++ break; ++ case NAND_CMD_READ0: ++ val = CNFG_OP_READ | CNFG_READ_EN; ++ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); ++ mtk_nfc_set_command(host, NAND_CMD_READ0); ++ break; ++ default: ++ dev_warn(host->dev, "command 0x%x not supported\n", command); ++ break; ++ } ++} ++ ++static uint8_t mtk_nfc_read_byte(struct mtd_info *mtd) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ int rc; ++ ++ rc = mtk_nfc_data_ready(host); ++ if (rc < 0) { ++ dev_err(host->dev, "data not ready\n"); ++ return NAND_STATUS_FAIL; ++ } ++ ++ return mtk_nfi_readb(host, MTKSDG1_NFI_DATAR); ++} ++ ++static void mtk_nfc_write_fdm(struct nand_chip *chip, u32 sectors) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ u8 *src, *dst; ++ int i, j, reg; ++ ++ for (i = 0; i < sectors ; i++) { ++ /* read FDM from OOB into private area */ ++ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ dst = (u8 *)host->fdm_reg; ++ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); ++ ++ /* write FDM to registers */ ++ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) { ++ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ reg += j * sizeof(host->fdm_reg[0]); ++ mtk_nfi_writel(host, host->fdm_reg[j], reg); ++ } ++ } ++} ++ ++static int mtk_nfc_write_page(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf, ++ int oob_on, int page, int raw) ++{ ++ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ struct completion *nfi = &host->nfi.complete; ++ struct device *dev = host->dev; ++ const bool use_ecc = !raw; ++ void *q = (void *) buf; ++ dma_addr_t dma_addr; ++ size_t dmasize; ++ u32 reg; ++ int ret; ++ ++ dmasize = mtd->writesize + (raw ? mtd->oobsize : 0); ++ ++ dma_addr = dma_map_single(dev, q, dmasize, DMA_TO_DEVICE); ++ if (dma_mapping_error(host->dev, dma_addr)) { ++ dev_err(host->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG); ++ reg |= CNFG_AHB | CNFG_DMA_BURST_EN; ++ if (use_ecc) { ++ /** ++ * OOB will be generated ++ * - FDM: from register ++ * - ECC: from HW ++ */ ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); ++ ++ mtk_ecc_encoder_idle(host); ++ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON); ++ ++ /* write OOB into the FDM registers (OOB area in MTK NAND) */ ++ if (oob_on) ++ mtk_nfc_write_fdm(chip, chip->ecc.steps); ++ } else { ++ /* OOB is part of the DMA transfer */ ++ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); ++ } ++ ++ mtk_nfi_writel(host, chip->ecc.steps << CON_SEC_SHIFT, MTKSDG1_NFI_CON); ++ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR); ++ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN); ++ ++ init_completion(nfi); ++ ++ /* start DMA */ ++ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BWR; ++ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON); ++ ++ ret = wait_for_completion_timeout(nfi, msecs_to_jiffies(MTK_TIMEOUT)); ++ if (!ret) { ++ dev_err(dev, "program ahb done timeout\n"); ++ mtk_nfi_writew(host, 0, MTKSDG1_NFI_INTR_EN); ++ ret = -ETIMEDOUT; ++ goto timeout; ++ } ++ ++ ret = mtk_nfc_transfer_done(host, chip->ecc.steps); ++ if (ret < 0) ++ dev_err(dev, "hwecc write timeout\n"); ++timeout: ++ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE); ++ ++ if (use_ecc) { ++ mtk_ecc_encoder_idle(host); ++ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON); ++ } ++ ++ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON); ++ ++ return ret; ++} ++ ++static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd, ++ struct nand_chip *chip, const uint8_t *buf, ++ int oob_on, int page) ++{ ++ return mtk_nfc_write_page(mtd, chip, buf, oob_on, page, MTK_ECC_ON); ++} ++ ++static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ++ const uint8_t *buf, int oob_on, int pg) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ uint8_t *src, *dst; ++ size_t len; ++ u32 i; ++ ++ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize); ++ ++ /* MTK internal 4KB page data layout: ++ * ---------------------------------- ++ * PAGE = 4KB, SECTOR = 1KB, OOB=128B ++ * page = sector_oob1 + sector_oob2 + sector_oob3 + sector_oob4 ++ * sector_oob = data (1KB) + FDM (8B) + ECC parity (21B) + free (3B) ++ * ++ */ ++ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; ++ ++ for (i = 0; i < chip->ecc.steps; i++) { ++ ++ if (buf) { ++ src = (uint8_t *) buf + i * SECTOR_SIZE; ++ dst = host->buffer + i * len; ++ memcpy(dst, src, SECTOR_SIZE); ++ } ++ ++ if (oob_on) { ++ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ dst = host->buffer + i * len + SECTOR_SIZE; ++ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); ++ } ++ } ++ ++ return mtk_nfc_write_page(mtd, chip, host->buffer, MTK_OOB_OFF, pg, ++ MTK_ECC_OFF); ++} ++ ++static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ struct completion *ecc = &host->ecc.complete; ++ u32 reg, parity_bytes, i; ++ dma_addr_t dma_addr; ++ u32 *parity_region; ++ int rc, ret = 0; ++ size_t dmasize; ++ ++ dmasize = SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE; ++ dma_addr = dma_map_single(host->dev, data, dmasize, DMA_TO_DEVICE); ++ if (dma_mapping_error(host->dev, dma_addr)) { ++ dev_err(host->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* enable the encoder in DMA mode to calculate the ECC bytes */ ++ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); ++ reg &= (~ECC_ENC_MODE_MASK); ++ reg |= ECC_DMA_MODE; ++ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); ++ ++ mtk_ecc_writel(host, ENC_IRQEN, MTKSDG1_ECC_ENCIRQ_EN); ++ mtk_ecc_writel(host, lower_32_bits(dma_addr), MTKSDG1_ECC_ENCDIADDR); ++ ++ init_completion(ecc); ++ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON); ++ ++ rc = wait_for_completion_timeout(ecc, msecs_to_jiffies(MTK_TIMEOUT)); ++ if (!rc) { ++ dev_err(host->dev, "ecc encode done timeout\n"); ++ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN); ++ ret = -ETIMEDOUT; ++ goto timeout; ++ } ++ ++ mtk_ecc_encoder_idle(host); ++ ++ /** ++ * Program ECC bytes to OOB ++ * per sector oob = FDM + ECC + SPARE ++ */ ++ ++ parity_region = (u32 *) (data + SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE); ++ parity_bytes = (chip->ecc.strength * MTK_ECC_PARITY_BITS + 7) >> 3; ++ ++ /* write the parity bytes generated by the ECC back to the OOB region */ ++ for (i = 0; i < parity_bytes; i += sizeof(u32)) ++ *parity_region++ = mtk_ecc_readl(host, MTKSDG1_ECC_ENCPAR0 + i); ++ ++timeout: ++ ++ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE); ++ ++ mtk_ecc_writew(host, 0, MTKSDG1_ECC_ENCCON); ++ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); ++ reg &= (~ECC_ENC_MODE_MASK); ++ reg |= ECC_NFI_MODE; ++ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); ++ ++ return ret; ++} ++ ++static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, ++ struct nand_chip *chip, uint32_t offset, uint32_t data_len, ++ const uint8_t *buf, int oob_on, int pg) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ uint8_t *src, *dst; ++ u32 start, end; ++ size_t len; ++ int i, ret; ++ ++ start = BYTES_TO_SECTORS(offset); ++ end = BYTES_TO_SECTORS(offset + data_len + SECTOR_SIZE - 1); ++ ++ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; ++ ++ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize); ++ for (i = 0; i < chip->ecc.steps; i++) { ++ ++ /* write data */ ++ src = (uint8_t *) buf + i * SECTOR_SIZE; ++ dst = host->buffer + i * len; ++ memcpy(dst, src, SECTOR_SIZE); ++ ++ if (i < start) ++ continue; ++ ++ if (i >= end) ++ continue; ++ ++ /* write fdm */ ++ if (oob_on) { ++ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ dst = host->buffer + i * len + SECTOR_SIZE; ++ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); ++ } ++ ++ /* point to the start of data */ ++ src = host->buffer + i * len; ++ ++ /* program the CRC back to the OOB */ ++ ret = mtk_nfc_sector_encode(chip, src); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* use the data in the private buffer (now with FDM and CRC) to perform ++ * a raw write ++ */ ++ src = host->buffer; ++ return mtk_nfc_write_page(mtd, chip, src, MTK_OOB_OFF, pg, MTK_ECC_OFF); ++} ++ ++static int mtk_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, ++ int page) ++{ ++ u8 *buf = chip->buffers->databuf; ++ int ret; ++ ++ memset(buf, 0xff, mtd->writesize); ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ++ ret = mtk_nfc_write_page_hwecc(mtd, chip, buf, MTK_OOB_ON, page); ++ if (ret < 0) ++ return -EIO; ++ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ ret = chip->waitfunc(mtd, chip); ++ ++ return ret & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++static int mtk_nfc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, ++ int page) ++{ ++ int ret; ++ ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); ++ ret = mtk_nfc_write_page_raw(mtd, chip, NULL, MTK_OOB_ON, page); ++ if (ret < 0) ++ return -EIO; ++ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ ret = chip->waitfunc(mtd, chip); ++ ++ return ret & NAND_STATUS_FAIL ? -EIO : 0; ++} ++ ++static int mtk_nfc_ecc_check(struct mtd_info *mtd, struct nand_chip *chip, ++ u32 sectors) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ u32 offset, i, err, max_bitflip; ++ ++ max_bitflip = 0; ++ ++ for (i = 0; i < sectors; i++) { ++ offset = (i >> 2) << 2; ++ err = mtk_ecc_readl(host, MTKSDG1_ECC_DECENUM0 + offset); ++ err = err >> ((i % 4) * 8); ++ err &= ERR_MASK; ++ if (err == ERR_MASK) { ++ /* uncorrectable errors */ ++ mtd->ecc_stats.failed++; ++ continue; ++ } ++ ++ mtd->ecc_stats.corrected += err; ++ max_bitflip = max_t(u32, max_bitflip, err); ++ } ++ ++ return max_bitflip; ++} ++ ++static void mtk_nfc_read_fdm(struct nand_chip *chip, u32 sectors) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ int i, j, reg; ++ u8 *dst, *src; ++ ++ for (i = 0; i < sectors; i++) { ++ /* read FDM register into host memory */ ++ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) { ++ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ reg += j * sizeof(host->fdm_reg[0]); ++ host->fdm_reg[j] = mtk_nfi_readl(host, reg); ++ } ++ ++ /* copy FDM register from host to OOB */ ++ src = (u8 *)host->fdm_reg; ++ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); ++ } ++} ++ ++static int mtk_nfc_update_oob(struct mtd_info *mtd, struct nand_chip *chip, ++ u8 *buf, u32 sectors) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ int i, bitflips = 0; ++ ++ /* if the page is empty, no bitflips and clear data and oob */ ++ if (mtk_nfi_readl(host, MTKSDG1_NFI_STA) & STA_EMP_PAGE) { ++ memset(buf, 0xff, SECTORS_TO_BYTES(sectors)); ++ ++ /* empty page: update OOB with 0xFF */ ++ for (i = 0; i < sectors; i++) { ++ memset(chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE, ++ 0xff, MTKSDG1_NFI_FDM_REG_SIZE); ++ } ++ } else { ++ /* update OOB with HW info */ ++ mtk_nfc_read_fdm(chip, sectors); ++ ++ /* return the bitflips */ ++ bitflips = mtk_nfc_ecc_check(mtd, chip, sectors); ++ } ++ ++ return bitflips; ++} ++ ++static int mtk_nfc_block_markbad(struct mtd_info *mtd, loff_t ofs) ++{ ++ struct nand_chip *chip = mtd_to_nand(mtd); ++ u8 *buf = chip->buffers->databuf; ++ int rc, i, pg; ++ ++ /* block_markbad writes 0x00 at data and OOB */ ++ memset(buf, 0x00, mtd->writesize + mtd->oobsize); ++ ++ /* Write to first/last page(s) if necessary */ ++ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ++ ofs += mtd->erasesize - mtd->writesize; ++ ++ i = 0; ++ do { ++ pg = (int)(ofs >> chip->page_shift); ++ ++ /** ++ * write 0x00 to DATA & OOB in flash ++ * No need to reorganize the page since it is all 0x00 ++ */ ++ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, pg); ++ rc = mtk_nfc_write_page(mtd, chip, buf, MTK_OOB_OFF, pg, ++ MTK_ECC_OFF); ++ if (rc < 0) ++ return rc; ++ ++ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ++ rc = chip->waitfunc(mtd, chip); ++ rc = rc & NAND_STATUS_FAIL ? -EIO : 0; ++ if (rc < 0) ++ return rc; ++ ++ ofs += mtd->writesize; ++ i++; ++ ++ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); ++ ++ return 0; ++} ++ ++static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, ++ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, ++ int page, int raw) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); ++ u32 reg, column, spare, sectors, start, end; ++ struct completion *nfi, *ecc; ++ const bool use_ecc = !raw; ++ int bitflips = -EIO; ++ dma_addr_t dma_addr; ++ size_t len; ++ u8 *buf; ++ int rc; ++ ++ nfi = &host->nfi.complete; ++ ecc = &host->ecc.complete; ++ ++ start = BYTES_TO_SECTORS(data_offs); ++ end = BYTES_TO_SECTORS(data_offs + readlen + SECTOR_SIZE - 1); ++ sectors = end - start; ++ ++ spare = mtd->oobsize / chip->ecc.steps; ++ column = start * (SECTOR_SIZE + spare); ++ ++ len = SECTORS_TO_BYTES(sectors) + (raw ? sectors * spare : 0); ++ buf = bufpoi + SECTORS_TO_BYTES(start); ++ ++ /* map the device memory */ ++ dma_addr = dma_map_single(host->dev, buf, len, DMA_FROM_DEVICE); ++ if (dma_mapping_error(host->dev, dma_addr)) { ++ dev_err(host->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* configure the transfer */ ++ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG); ++ reg |= CNFG_DMA_BURST_EN | CNFG_AHB; ++ if (use_ecc) { ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); ++ ++ /* enable encoder */ ++ mtk_ecc_decoder_idle(host); ++ mtk_ecc_writel(host, DEC_EN, MTKSDG1_ECC_DECCON); ++ } else ++ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); ++ ++ mtk_nfi_writel(host, sectors << CON_SEC_SHIFT, MTKSDG1_NFI_CON); ++ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN); ++ ++ init_completion(nfi); ++ ++ mtk_nfc_set_address(host, column, page, 2, host->row_nob); ++ mtk_nfc_set_command(host, NAND_CMD_READSTART); ++ rc = wait_for_completion_timeout(nfi, timeout); ++ if (!rc) { ++ dev_err(host->dev, "read busy return timeout\n"); ++ goto error; ++ } ++ ++ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN); ++ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR); ++ ++ if (use_ecc) { ++ /* program ECC with sector count */ ++ host->ecc.dec_sec = sectors; ++ init_completion(ecc); ++ mtk_ecc_writew(host, DEC_IRQEN, MTKSDG1_ECC_DECIRQ_EN); ++ } ++ ++ init_completion(nfi); ++ ++ /* start DMA */ ++ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BRD; ++ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON); ++ ++ rc = wait_for_completion_timeout(nfi, timeout); ++ if (!rc) ++ dev_warn(host->dev, "read ahb/dma done timeout\n"); ++ ++ /* DMA interrupt didn't trigger, check page done just in case */ ++ rc = mtk_nfc_subpage_done(host, sectors); ++ if (rc < 0) { ++ dev_err(host->dev, "subpage done timeout\n"); ++ goto error; ++ } ++ ++ /* raw transfer successful */ ++ bitflips = 0; ++ ++ if (use_ecc) { ++ rc = wait_for_completion_timeout(ecc, timeout); ++ if (!rc) { ++ dev_err(host->dev, "ecc decode timeout\n"); ++ host->ecc.dec_sec = 0; ++ bitflips = -ETIMEDOUT; ++ goto error; ++ } ++ bitflips = mtk_nfc_update_oob(mtd, chip, buf, sectors); ++ } ++ ++error: ++ dma_unmap_single(host->dev, dma_addr, len, DMA_FROM_DEVICE); ++ ++ if (use_ecc) { ++ /* make sure the ECC dec irq is disabled */ ++ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN); ++ mtk_ecc_decoder_idle(host); ++ ++ /* disable ECC dec */ ++ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECCON); ++ } ++ ++ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON); ++ ++ return bitflips; ++} ++ ++static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd, ++ struct nand_chip *chip, uint32_t data_offs, ++ uint32_t readlen, uint8_t *bufpoi, int page) ++{ ++ return mtk_nfc_read_subpage(mtd, chip, data_offs, readlen, ++ bufpoi, page, MTK_ECC_ON); ++} ++ ++static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf, int oob_on, int page) ++{ ++ return mtk_nfc_read_subpage_hwecc(mtd, chip, 0, mtd->writesize, ++ buf, page); ++} ++ ++static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf, int oob_on, int page) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ uint8_t *src, *dst; ++ int i, ret; ++ size_t len; ++ ++ dst = host->buffer; ++ memset(dst, 0xff, mtd->writesize + mtd->oobsize); ++ ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, dst, page, 1); ++ if (ret < 0) ++ return ret; ++ ++ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; ++ ++ /* copy to the output buffer */ ++ for (i = 0; i < chip->ecc.steps; i++) { ++ ++ /* copy sector data */ ++ if (buf) { ++ src = host->buffer + i * len; ++ dst = buf + i * SECTOR_SIZE; ++ memcpy(dst, src, SECTOR_SIZE); ++ } ++ ++ /* copy FDM data to OOB */ ++ if (oob_on) { ++ src = host->buffer + i * len + SECTOR_SIZE; ++ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; ++ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); ++ } ++ } ++ ++ return ret; ++} ++ ++static void mtk_nfc_switch_oob(struct mtd_info *mtd, struct nand_chip *chip, ++ uint8_t *buf) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ size_t spare; ++ u32 sectors; ++ u8 *bufpoi; ++ int len; ++ ++ spare = mtd->oobsize / chip->ecc.steps; ++ sectors = mtd->writesize / (SECTOR_SIZE + spare); ++ ++ /** ++ * MTK: DATA+oob1, DATA+oob2, DATA+oob3 ... ++ * LNX: DATA+OOB ++ */ ++ /* point to the last oob_i from the NAND device*/ ++ bufpoi = buf + mtd->writesize - (sectors * spare); ++ len = sizeof(host->fdm_reg); ++ ++ /* copy NAND oob to private area */ ++ memcpy(host->fdm_reg, bufpoi, len); ++ ++ /* copy oob_poi to NAND */ ++ memcpy(bufpoi, chip->oob_poi, len); ++ ++ /* copy NAND oob to oob_poi */ ++ memcpy(chip->oob_poi, host->fdm_reg, sizeof(host->fdm_reg)); ++ memset(host->fdm_reg, 0x00, len); ++} ++ ++static int mtk_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, ++ int page) ++{ ++ struct mtk_nfc_host *host = nand_get_controller_data(chip); ++ u8 *buf = chip->buffers->databuf; ++ struct mtd_ecc_stats stats; ++ int ret; ++ ++ stats = mtd->ecc_stats; ++ ++ memset(buf, 0xff, mtd->writesize); ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); ++ ++ ret = mtk_nfc_read_page_hwecc(mtd, chip, buf, 1, page); ++ ++ if (host->switch_oob) ++ mtk_nfc_switch_oob(mtd, chip, buf); ++ ++ if (ret < mtd->bitflip_threshold) ++ mtd->ecc_stats.corrected = stats.corrected; ++ ++ return ret; ++} ++ ++static int mtk_nfc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, ++ int page) ++{ ++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); ++ ++ return mtk_nfc_read_page_raw(mtd, chip, NULL, MTK_OOB_ON, page); ++} ++ ++static inline void mtk_nfc_hw_init(struct mtk_nfc_host *host) ++{ ++ mtk_nfi_writel(host, 0x10804211, MTKSDG1_NFI_ACCCON); ++ mtk_nfi_writew(host, 0xf1, MTKSDG1_NFI_CNRNB); ++ mtk_nfc_hw_reset(host); ++ ++ /* clear interrupt */ ++ mtk_nfi_readl(host, MTKSDG1_NFI_INTR_STA); ++ mtk_nfi_writel(host, 0, MTKSDG1_NFI_INTR_EN); ++ ++ /* ECC encoder init */ ++ mtk_ecc_encoder_idle(host); ++ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON); ++ ++ /* ECC decoder init */ ++ mtk_ecc_decoder_idle(host); ++ mtk_ecc_writel(host, DEC_DE, MTKSDG1_ECC_DECCON); ++} ++ ++static irqreturn_t mtk_nfi_irq(int irq, void *devid) ++{ ++ struct mtk_nfc_host *host = devid; ++ u16 sta, ien; ++ ++ sta = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_STA); ++ ien = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_EN); ++ ++ if (!(sta & ien)) ++ return IRQ_NONE; ++ ++ mtk_nfi_writew(host, ~sta & ien, MTKSDG1_NFI_INTR_EN); ++ complete(&host->nfi.complete); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t mtk_ecc_irq(int irq, void *devid) ++{ ++ struct mtk_nfc_host *host = devid; ++ u32 reg_val, mask; ++ ++ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIRQ_STA); ++ if (reg_val & DEC_IRQEN) { ++ if (host->ecc.dec_sec) { ++ mask = 1 << (host->ecc.dec_sec - 1); ++ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECDONE); ++ if (mask & reg_val) { ++ host->ecc.dec_sec = 0; ++ complete(&host->ecc.complete); ++ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN); ++ } ++ } else ++ dev_warn(host->dev, "spurious DEC_IRQ\n"); ++ ++ return IRQ_HANDLED; ++ } ++ ++ reg_val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIRQ_STA); ++ if (reg_val & ENC_IRQEN) { ++ complete(&host->ecc.complete); ++ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk) ++{ ++ int ret; ++ ++ ret = clk_prepare_enable(clk->nfi_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable nfi clk\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(clk->nfiecc_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable nfiecc clk\n"); ++ goto out_nfiecc_clk_disable; ++ } ++ ++ ret = clk_prepare_enable(clk->pad_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable pad clk\n"); ++ goto out_pad_clk_disable; ++ } ++ ++ return 0; ++ ++out_pad_clk_disable: ++ clk_disable_unprepare(clk->nfiecc_clk); ++ ++out_nfiecc_clk_disable: ++ clk_disable_unprepare(clk->nfi_clk); ++ ++ return ret; ++} ++ ++static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk) ++{ ++ clk_disable_unprepare(clk->nfi_clk); ++ clk_disable_unprepare(clk->nfiecc_clk); ++ clk_disable_unprepare(clk->pad_clk); ++} ++ ++static int mtk_nfc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct mtk_nfc_host *host; ++ struct nand_chip *chip; ++ struct mtd_info *mtd; ++ struct resource *res; ++ int ret, irq; ++ size_t len; ++ ++ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); ++ if (!host) ++ return -ENOMEM; ++ ++ chip = &host->chip; ++ mtd = nand_to_mtd(chip); ++ host->dev = dev; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ host->nfi.base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(host->nfi.base)) { ++ ret = PTR_ERR(host->nfi.base); ++ dev_err(dev, "no nfi base\n"); ++ return ret; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ host->ecc.base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(host->ecc.base)) { ++ ret = PTR_ERR(host->ecc.base); ++ dev_err(dev, "no ecc base\n"); ++ return ret; ++ } ++ ++ host->clk.nfi_clk = devm_clk_get(dev, "nfi_clk"); ++ if (IS_ERR(host->clk.nfi_clk)) { ++ dev_err(dev, "no clk\n"); ++ ret = PTR_ERR(host->clk.nfi_clk); ++ return ret; ++ } ++ ++ host->clk.nfiecc_clk = devm_clk_get(dev, "nfiecc_clk"); ++ if (IS_ERR(host->clk.nfiecc_clk)) { ++ dev_err(dev, "no ecc clk\n"); ++ ret = PTR_ERR(host->clk.nfiecc_clk); ++ return ret; ++ } ++ ++ host->clk.pad_clk = devm_clk_get(dev, "pad_clk"); ++ if (IS_ERR(host->clk.pad_clk)) { ++ dev_err(dev, "no pad clk\n"); ++ ret = PTR_ERR(host->clk.pad_clk); ++ return ret; ++ } ++ ++ ret = mtk_nfc_enable_clk(dev, &host->clk); ++ if (ret) ++ return ret; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no nfi irq resource\n"); ++ ret = -EINVAL; ++ goto clk_disable; ++ } ++ ++ ret = devm_request_irq(dev, irq, mtk_nfi_irq, 0x0, MTK_IRQ_NFI, host); ++ if (ret) { ++ dev_err(dev, "failed to request nfi irq\n"); ++ goto clk_disable; ++ } ++ ++ irq = platform_get_irq(pdev, 1); ++ if (irq < 0) { ++ dev_err(dev, "no ecc irq resource\n"); ++ ret = -EINVAL; ++ goto clk_disable; ++ } ++ ++ ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, MTK_IRQ_ECC, host); ++ if (ret) { ++ dev_err(dev, "failed to request ecc irq\n"); ++ goto clk_disable; ++ } ++ ++ ret = dma_set_mask(dev, DMA_BIT_MASK(32)); ++ if (ret) { ++ dev_err(dev, "failed to set dma mask\n"); ++ goto clk_disable; ++ } ++ ++ platform_set_drvdata(pdev, host); ++ ++ mtd_set_of_node(mtd, np); ++ mtd->owner = THIS_MODULE; ++ mtd->dev.parent = dev; ++ mtd->name = MTK_NAME; ++ ++ nand_set_controller_data(chip, host); ++ chip->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ; ++ chip->block_markbad = mtk_nfc_block_markbad; ++ chip->select_chip = mtk_nfc_select_chip; ++ chip->read_byte = mtk_nfc_read_byte; ++ chip->cmdfunc = mtk_nfc_cmdfunc; ++ chip->ecc.mode = NAND_ECC_HW; ++ chip->ecc.write_subpage = mtk_nfc_write_subpage_hwecc; ++ chip->ecc.write_page_raw = mtk_nfc_write_page_raw; ++ chip->ecc.write_page = mtk_nfc_write_page_hwecc; ++ chip->ecc.write_oob_raw = mtk_nfc_write_oob_raw; ++ chip->ecc.write_oob = mtk_nfc_write_oob; ++ chip->ecc.read_subpage = mtk_nfc_read_subpage_hwecc; ++ chip->ecc.read_page_raw = mtk_nfc_read_page_raw; ++ chip->ecc.read_oob_raw = mtk_nfc_read_oob_raw; ++ chip->ecc.read_page = mtk_nfc_read_page_hwecc; ++ chip->ecc.read_oob = mtk_nfc_read_oob; ++ ++ mtk_nfc_hw_init(host); ++ ++ ret = nand_scan_ident(mtd, MTK_NAND_MAX_CHIP, NULL); ++ if (ret) { ++ ret = -ENODEV; ++ goto clk_disable; ++ } ++ ++ ret = mtk_nfc_hw_runtime_config(mtd); ++ if (ret < 0) { ++ dev_err(dev, "nand device not supported\n"); ++ goto clk_disable; ++ } ++ ++ len = mtd->writesize + mtd->oobsize; ++ host->buffer = devm_kzalloc(dev, len, GFP_KERNEL); ++ if (!host->buffer) { ++ ret = -ENOMEM; ++ goto clk_disable; ++ } ++ ++ /* required to create bbt table if not present */ ++ host->switch_oob = true; ++ ret = nand_scan_tail(mtd); ++ if (ret) { ++ ret = -ENODEV; ++ goto clk_disable; ++ } ++ host->switch_oob = false; ++ ++ ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); ++ if (ret) { ++ dev_err(dev, "mtd parse partition error\n"); ++ goto nand_free; ++ } ++ ++ return 0; ++ ++nand_free: ++ nand_release(mtd); ++ ++clk_disable: ++ mtk_nfc_disable_clk(&host->clk); ++ ++ return ret; ++} ++ ++static int mtk_nfc_remove(struct platform_device *pdev) ++{ ++ struct mtk_nfc_host *host = platform_get_drvdata(pdev); ++ struct mtd_info *mtd = nand_to_mtd(&host->chip); ++ ++ nand_release(mtd); ++ mtk_nfc_disable_clk(&host->clk); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int mtk_nfc_suspend(struct device *dev) ++{ ++ struct mtk_nfc_host *host = dev_get_drvdata(dev); ++ struct mtk_nfc_saved_reg *reg = &host->saved_reg; ++ ++ reg->nfi.emp_thresh = mtk_nfi_readl(host, MTKSDG1_NFI_EMPTY_THRESH); ++ reg->ecc.enccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); ++ reg->ecc.deccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_DECCNFG); ++ reg->nfi.pagefmt = mtk_nfi_readw(host, MTKSDG1_NFI_PAGEFMT); ++ reg->nfi.acccon = mtk_nfi_readl(host, MTKSDG1_NFI_ACCCON); ++ reg->nfi.cnrnb = mtk_nfi_readw(host, MTKSDG1_NFI_CNRNB); ++ reg->nfi.csel = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL); ++ ++ mtk_nfc_disable_clk(&host->clk); ++ ++ return 0; ++} ++ ++static int mtk_nfc_resume(struct device *dev) ++{ ++ struct mtk_nfc_host *host = dev_get_drvdata(dev); ++ struct mtk_nfc_saved_reg *reg = &host->saved_reg; ++ struct nand_chip *chip = &host->chip; ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ int ret; ++ u32 i; ++ ++ udelay(200); ++ ++ ret = mtk_nfc_enable_clk(dev, &host->clk); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < chip->numchips; i++) { ++ chip->select_chip(mtd, i); ++ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); ++ } ++ ++ mtk_nfi_writel(host, reg->nfi.emp_thresh, MTKSDG1_NFI_EMPTY_THRESH); ++ mtk_nfi_writew(host, reg->nfi.pagefmt, MTKSDG1_NFI_PAGEFMT); ++ mtk_ecc_writel(host, reg->ecc.enccnfg, MTKSDG1_ECC_ENCCNFG); ++ mtk_ecc_writel(host, reg->ecc.deccnfg, MTKSDG1_ECC_DECCNFG); ++ mtk_nfi_writel(host, reg->nfi.acccon, MTKSDG1_NFI_ACCCON); ++ mtk_nfi_writew(host, reg->nfi.cnrnb, MTKSDG1_NFI_CNRNB); ++ mtk_nfi_writew(host, reg->nfi.csel, MTKSDG1_NFI_CSEL); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume); ++#endif ++ ++static const struct of_device_id mtk_nfc_id_table[] = { ++ { .compatible = "mediatek,mt2701-nfc" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, mtk_nfc_id_table); ++ ++static struct platform_driver mtk_nfc_driver = { ++ .probe = mtk_nfc_probe, ++ .remove = mtk_nfc_remove, ++ .driver = { ++ .name = MTK_NAME, ++ .of_match_table = mtk_nfc_id_table, ++#ifdef CONFIG_PM_SLEEP ++ .pm = &mtk_nfc_pm_ops, ++#endif ++ }, ++}; ++ ++module_platform_driver(mtk_nfc_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Xiaolei Li "); ++MODULE_DESCRIPTION("MTK Nand Flash Controller Driver"); ++ +diff --git a/drivers/mtd/nand/mtksdg1_nand_ecc.h b/drivers/mtd/nand/mtksdg1_nand_ecc.h +new file mode 100644 +index 0000000..d90b196 +--- /dev/null ++++ b/drivers/mtd/nand/mtksdg1_nand_ecc.h +@@ -0,0 +1,75 @@ ++/* ++ * MTK smart device ECC engine register. ++ * Copyright (C) 2015-2016 MediaTek Inc. ++ * Author: Xiaolei.Li ++ * ++ * 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 MTKSDG1_NAND_ECC_H ++#define MTKSDG1_NAND_ECC_H ++ ++/* ECC engine register definition */ ++#define MTKSDG1_ECC_ENCCON (0x00) ++#define ENC_EN (1) ++#define ENC_DE (0) ++ ++#define MTKSDG1_ECC_ENCCNFG (0x04) ++#define ECC_CNFG_4BIT (0) ++#define ECC_CNFG_12BIT (4) ++#define ECC_NFI_MODE BIT(5) ++#define ECC_DMA_MODE (0) ++#define ECC_ENC_MODE_MASK (0x3 << 5) ++#define ECC_MS_SHIFT (16) ++ ++#define MTKSDG1_ECC_ENCDIADDR (0x08) ++ ++#define MTKSDG1_ECC_ENCIDLE (0x0C) ++#define ENC_IDLE BIT(0) ++ ++#define MTKSDG1_ECC_ENCPAR0 (0x10) ++#define MTKSDG1_ECC_ENCSTA (0x7C) ++ ++#define MTKSDG1_ECC_ENCIRQ_EN (0x80) ++#define ENC_IRQEN BIT(0) ++ ++#define MTKSDG1_ECC_ENCIRQ_STA (0x84) ++ ++#define MTKSDG1_ECC_DECCON (0x100) ++#define DEC_EN (1) ++#define DEC_DE (0) ++ ++#define MTKSDG1_ECC_DECCNFG (0x104) ++#define DEC_EMPTY_EN BIT(31) ++#define DEC_CNFG_FER (0x1 << 12) ++#define DEC_CNFG_EL (0x2 << 12) ++#define DEC_CNFG_CORRECT (0x3 << 12) ++ ++#define MTKSDG1_ECC_DECIDLE (0x10C) ++#define DEC_IDLE BIT(0) ++ ++#define MTKSDG1_ECC_DECFER (0x110) ++ ++#define MTKSDG1_ECC_DECENUM0 (0x114) ++#define ERR_MASK (0x3f) ++ ++#define MTKSDG1_ECC_DECDONE (0x124) ++ ++#define MTKSDG1_ECC_DECEL0 (0x128) ++ ++#define MTKSDG1_ECC_DECIRQ_EN (0x200) ++#define DEC_IRQEN BIT(0) ++ ++#define MTKSDG1_ECC_DECIRQ_STA (0x204) ++ ++#define MTKSDG1_ECC_DECFSM (0x208) ++#define DECFSM_MASK (0x7f0f0f0f) ++#define DECFSM_IDLE (0x01010101) ++#endif +diff --git a/drivers/mtd/nand/mtksdg1_nand_nfi.h b/drivers/mtd/nand/mtksdg1_nand_nfi.h +new file mode 100644 +index 0000000..a9aa6f6 +--- /dev/null ++++ b/drivers/mtd/nand/mtksdg1_nand_nfi.h +@@ -0,0 +1,119 @@ ++/* ++ * MTK smart device NAND Flash controller register. ++ * Copyright (C) 2015-2016 MediaTek Inc. ++ * Author: Xiaolei.Li ++ * ++ * 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 MTKSDG1_NAND_NFI_H ++#define MTKSDG1_NAND_NFI_H ++ ++/* NAND controller register definition */ ++#define MTKSDG1_NFI_CNFG (0x00) ++#define CNFG_AHB BIT(0) ++#define CNFG_READ_EN BIT(1) ++#define CNFG_DMA_BURST_EN BIT(2) ++#define CNFG_BYTE_RW BIT(6) ++#define CNFG_HW_ECC_EN BIT(8) ++#define CNFG_AUTO_FMT_EN BIT(9) ++#define CNFG_OP_IDLE (0 << 12) ++#define CNFG_OP_READ (1 << 12) ++#define CNFG_OP_SRD (2 << 12) ++#define CNFG_OP_PRGM (3 << 12) ++#define CNFG_OP_ERASE (4 << 12) ++#define CNFG_OP_RESET (5 << 12) ++#define CNFG_OP_CUST (6 << 12) ++ ++#define MTKSDG1_NFI_PAGEFMT (0x04) ++#define PAGEFMT_FDM_ECC_SHIFT (12) ++#define PAGEFMT_FDM_SHIFT (8) ++#define PAGEFMT_SPARE_16 (0) ++#define PAGEFMT_SPARE_32 (4) ++#define PAGEFMT_SPARE_SHIFT (4) ++#define PAGEFMT_SEC_SEL_512 BIT(2) ++#define PAGEFMT_512_2K (0) ++#define PAGEFMT_2K_4K (1) ++#define PAGEFMT_4K_8K (2) ++ ++/* NFI control */ ++#define MTKSDG1_NFI_CON (0x08) ++#define CON_FIFO_FLUSH BIT(0) ++#define CON_NFI_RST BIT(1) ++#define CON_SRD BIT(4) /* single read */ ++#define CON_BRD BIT(8) /* burst read */ ++#define CON_BWR BIT(9) /* burst write */ ++#define CON_SEC_SHIFT (12) ++ ++/* Timming control register */ ++#define MTKSDG1_NFI_ACCCON (0x0C) ++ ++#define MTKSDG1_NFI_INTR_EN (0x10) ++#define INTR_RD_DONE_EN BIT(0) ++#define INTR_WR_DONE_EN BIT(1) ++#define INTR_RST_DONE_EN BIT(2) ++#define INTR_ERS_DONE_EN BIT(3) ++#define INTR_BUSY_RT_EN BIT(4) ++#define INTR_AHB_DONE_EN BIT(6) ++ ++#define MTKSDG1_NFI_INTR_STA (0x14) ++ ++#define MTKSDG1_NFI_CMD (0x20) ++ ++#define MTKSDG1_NFI_ADDRNOB (0x30) ++#define ADDR_ROW_NOB_SHIFT (4) ++ ++#define MTKSDG1_NFI_COLADDR (0x34) ++#define MTKSDG1_NFI_ROWADDR (0x38) ++#define MTKSDG1_NFI_STRDATA (0x40) ++#define MTKSDG1_NFI_CNRNB (0x44) ++#define MTKSDG1_NFI_DATAW (0x50) ++#define MTKSDG1_NFI_DATAR (0x54) ++#define MTKSDG1_NFI_PIO_DIRDY (0x58) ++#define PIO_DI_RDY (0x01) ++ ++/* NFI state*/ ++#define MTKSDG1_NFI_STA (0x60) ++#define STA_CMD BIT(0) ++#define STA_ADDR BIT(1) ++#define STA_DATAR BIT(2) ++#define STA_DATAW BIT(3) ++#define STA_EMP_PAGE BIT(12) ++ ++#define MTKSDG1_NFI_FIFOSTA (0x64) ++ ++#define MTKSDG1_NFI_ADDRCNTR (0x70) ++#define CNTR_MASK GENMASK(16, 12) ++ ++#define MTKSDG1_NFI_STRADDR (0x80) ++#define MTKSDG1_NFI_BYTELEN (0x84) ++#define MTKSDG1_NFI_CSEL (0x90) ++#define MTKSDG1_NFI_IOCON (0x94) ++ ++/* FDM data for sector: FDM0[L,H] - FDMF[L,H] */ ++#define MTKSDG1_NFI_FDM_MAX_SEC (0x10) ++#define MTKSDG1_NFI_FDM_REG_SIZE (8) ++#define MTKSDG1_NFI_FDM0L (0xA0) ++#define MTKSDG1_NFI_FDM0M (0xA4) ++ ++ ++#define MTKSDG1_NFI_FIFODATA0 (0x190) ++#define MTKSDG1_NFI_DEBUG_CON1 (0x220) ++#define MTKSDG1_NFI_MASTER_STA (0x224) ++#define MASTER_STA_MASK (0x0FFF) ++ ++#define MTKSDG1_NFI_RANDOM_CNFG (0x238) ++#define MTKSDG1_NFI_EMPTY_THRESH (0x23C) ++#define MTKSDG1_NFI_NAND_TYPE (0x240) ++#define MTKSDG1_NFI_ACCCON1 (0x244) ++#define MTKSDG1_NFI_DELAY_CTRL (0x248) ++ ++#endif ++ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0059-mtd-nand-add-an-mtd_to_nand-helper.patch b/target/linux/mediatek/patches-4.4/0059-mtd-nand-add-an-mtd_to_nand-helper.patch deleted file mode 100644 index 636575ef7e..0000000000 --- a/target/linux/mediatek/patches-4.4/0059-mtd-nand-add-an-mtd_to_nand-helper.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 179937ef20beb9d4af4807f3540d4dfc4d48516a Mon Sep 17 00:00:00 2001 -From: Boris BREZILLON -Date: Mon, 16 Nov 2015 14:37:35 +0100 -Subject: [PATCH 59/66] mtd: nand: add an mtd_to_nand() helper - -Some drivers are retrieving the nand_chip pointer using the container_of -macro on a struct wrapping both the nand_chip and the mtd_info struct while -the standard way of retrieving this pointer is through mtd->priv. -Provide an helper to do that. - -Signed-off-by: Boris Brezillon -Signed-off-by: Brian Norris ---- - include/linux/mtd/nand.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h -index 5a9d1d4..a4839b3 100644 ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -719,6 +719,11 @@ struct nand_chip { - void *priv; - }; - -+static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) -+{ -+ return mtd->priv; -+} -+ - /* - * NAND Flash Manufacturer ID Codes - */ --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch b/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch new file mode 100644 index 0000000000..392dea3ecc --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch @@ -0,0 +1,46 @@ +From 96ec6b2ee8a19799835209d0a6753519b96277f8 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 02:28:08 +0200 +Subject: [PATCH 59/78] mtd: nand: backport fixes + +--- + drivers/mtd/nand/mtksdg1_nand.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c +index 55dd17d..f92b949 100644 +--- a/drivers/mtd/nand/mtksdg1_nand.c ++++ b/drivers/mtd/nand/mtksdg1_nand.c +@@ -107,6 +107,9 @@ static struct nand_ecclayout nand_4k_128 = { + .oobfree = { {0, 32} }, + }; + ++static const char * const part_probes[] = { ++ "cmdlinepart", "RedBoot", "ofpart", NULL }; ++ + /* NFI register access */ + static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg) + { +@@ -1298,6 +1301,7 @@ static int mtk_nfc_probe(struct platform_device *pdev) + + chip = &host->chip; + mtd = nand_to_mtd(chip); ++ mtd->priv = chip; + host->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -1428,7 +1432,10 @@ static int mtk_nfc_probe(struct platform_device *pdev) + } + host->switch_oob = false; + +- ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); ++ ret = mtd_device_parse_register(mtd, part_probes, ++ &(struct mtd_part_parser_data) { ++ .of_node = pdev->dev.of_node, ++ }, NULL, 0); + if (ret) { + dev_err(dev, "mtd parse partition error\n"); + goto nand_free; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0060-mtd-nand-add-nand_to_mtd-helper.patch b/target/linux/mediatek/patches-4.4/0060-mtd-nand-add-nand_to_mtd-helper.patch deleted file mode 100644 index d68a2feaa5..0000000000 --- a/target/linux/mediatek/patches-4.4/0060-mtd-nand-add-nand_to_mtd-helper.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 8c32f64172fbf43d23c99dc4d32f5a1cb5eb08ae Mon Sep 17 00:00:00 2001 -From: Boris BREZILLON -Date: Tue, 1 Dec 2015 12:03:07 +0100 -Subject: [PATCH 60/66] mtd: nand: add nand_to_mtd() helper - -Add a new helper to retrieve the MTD device attached to a NAND chip. - -Signed-off-by: Boris Brezillon -Signed-off-by: Brian Norris ---- - include/linux/mtd/nand.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h -index a4839b3..c75424f 100644 ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -724,6 +724,11 @@ static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) - return mtd->priv; - } - -+static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) -+{ -+ return &chip->mtd; -+} -+ - /* - * NAND Flash Manufacturer ID Codes - */ --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0060-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch b/target/linux/mediatek/patches-4.4/0060-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch new file mode 100644 index 0000000000..a0e4f9ee5f --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0060-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch @@ -0,0 +1,32 @@ +From c657573d75d71076fef8294f9d4f7f9a0e6f7a9e Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Tue, 15 Mar 2016 10:18:49 +0300 +Subject: [PATCH 60/78] net: mediatek: checking for IS_ERR() instead of NULL + +of_phy_connect() returns NULL on error, it never returns error pointers. + +Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet') +Signed-off-by: Dan Carpenter +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index ba3afa5..9759fe5 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -186,9 +186,9 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, + + phydev = of_phy_connect(eth->netdev[mac->id], phy_node, + mtk_phy_link_adjust, 0, phy_mode); +- if (IS_ERR(phydev)) { ++ if (!phydev) { + dev_err(eth->dev, "could not connect to PHY\n"); +- return PTR_ERR(phydev); ++ return -ENODEV; + } + + dev_info(eth->dev, +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0061-mtd-nand-add-helpers-to-access-priv.patch b/target/linux/mediatek/patches-4.4/0061-mtd-nand-add-helpers-to-access-priv.patch deleted file mode 100644 index 49fbcbcc70..0000000000 --- a/target/linux/mediatek/patches-4.4/0061-mtd-nand-add-helpers-to-access-priv.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 738a76df006dedd1feb87c596867438b7d59027a Mon Sep 17 00:00:00 2001 -From: Boris BREZILLON -Date: Thu, 10 Dec 2015 09:00:39 +0100 -Subject: [PATCH 61/66] mtd: nand: add helpers to access ->priv - -Add two helpers to access the field reserved for private controller data. -This makes it clearer what this field is reserved for and ease future -refactoring. - -Signed-off-by: Boris Brezillon -Signed-off-by: Brian Norris ---- - include/linux/mtd/nand.h | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h -index c75424f..345f864 100644 ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -729,6 +729,16 @@ static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) - return &chip->mtd; - } - -+static inline void *nand_get_controller_data(struct nand_chip *chip) -+{ -+ return chip->priv; -+} -+ -+static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) -+{ -+ chip->priv = priv; -+} -+ - /* - * NAND Flash Manufacturer ID Codes - */ --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0061-net-mediatek-unlock-on-error-in-mtk_tx_map.patch b/target/linux/mediatek/patches-4.4/0061-net-mediatek-unlock-on-error-in-mtk_tx_map.patch new file mode 100644 index 0000000000..effb45fade --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0061-net-mediatek-unlock-on-error-in-mtk_tx_map.patch @@ -0,0 +1,29 @@ +From d8261ad9e408adfa5d1758a0f655c7726f0f831b Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Tue, 15 Mar 2016 10:19:04 +0300 +Subject: [PATCH 61/78] net: mediatek: unlock on error in mtk_tx_map() + +There was a missing unlock on the error path. + +Fixes: 656e705243fd ('net-next: mediatek: add support for MT7623 ethernet') +Signed-off-by: Dan Carpenter +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 9759fe5..c2c2e206 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -661,6 +661,8 @@ err_dma: + itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); + } while (itxd != txd); + ++ spin_unlock_irqrestore(ð->page_lock, flags); ++ + return -ENOMEM; + } + +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0062-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch b/target/linux/mediatek/patches-4.4/0062-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch deleted file mode 100644 index 598f879f59..0000000000 --- a/target/linux/mediatek/patches-4.4/0062-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 088bf341472e8da8595d49f15af9becf3a4b52e7 Mon Sep 17 00:00:00 2001 -From: Boris BREZILLON -Date: Tue, 1 Dec 2015 12:03:06 +0100 -Subject: [PATCH 62/66] mtd: nand: embed an mtd_info structure into nand_chip - -Currently all NAND controller drivers are providing both the mtd_info and -nand_chip struct and then let the NAND subsystem to initialize a few -things before registering the mtd instance to the MTD layer. -Embed an mtd_info field into nand_chip to add some consistency to all NAND -controller drivers. -This change will also help factorizing boilerplate code copied in all NAND -drivers. - -Signed-off-by: Boris Brezillon -Signed-off-by: Brian Norris ---- - include/linux/mtd/nand.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h -index 345f864..1ded588 100644 ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -540,6 +540,7 @@ struct nand_buffers { - - /** - * struct nand_chip - NAND Private Flash Chip Data -+ * @mtd: MTD device registered to the MTD framework - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the - * flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the -@@ -640,6 +641,7 @@ struct nand_buffers { - */ - - struct nand_chip { -+ struct mtd_info mtd; - void __iomem *IO_ADDR_R; - void __iomem *IO_ADDR_W; - --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0062-net-mediatek-use-dma_addr_t-correctly.patch b/target/linux/mediatek/patches-4.4/0062-net-mediatek-use-dma_addr_t-correctly.patch new file mode 100644 index 0000000000..c44813068f --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0062-net-mediatek-use-dma_addr_t-correctly.patch @@ -0,0 +1,35 @@ +From 26c749e825e87e8be46498be7ac425e83b0f22c6 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Mon, 14 Mar 2016 15:07:10 +0100 +Subject: [PATCH 62/78] net: mediatek: use dma_addr_t correctly + +dma_alloc_coherent() expects a dma_addr_t pointer as its argument, +not an 'unsigned int', and gcc correctly warns about broken +code in the mtk_init_fq_dma function: + +drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_init_fq_dma': +drivers/net/ethernet/mediatek/mtk_eth_soc.c:463:13: error: passing argument 3 of 'dma_alloc_coherent' from incompatible pointer type [-Werror=incompatible-pointer-types] + +This changes the type of the local variable to dma_addr_t. + +Signed-off-by: Arnd Bergmann +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c2c2e206..a005bc4 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -453,7 +453,7 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd, + /* the qdma core needs scratch memory to be setup */ + static int mtk_init_fq_dma(struct mtk_eth *eth) + { +- unsigned int phy_ring_head, phy_ring_tail; ++ dma_addr_t phy_ring_head, phy_ring_tail; + int cnt = MTK_DMA_SIZE; + dma_addr_t dma_addr; + int i; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0063-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/mediatek/patches-4.4/0063-mtd-add-get-set-of_node-flash_node-helpers.patch deleted file mode 100644 index b72ecfdc8a..0000000000 --- a/target/linux/mediatek/patches-4.4/0063-mtd-add-get-set-of_node-flash_node-helpers.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 63c8331b826ad5f21cb0175308099f18d5fe526a Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 22 Mar 2016 03:52:07 +0100 -Subject: [PATCH 63/66] mtd: add get/set of_node/flash_node helpers - -We are going to begin using the mtd->dev.of_node field for MTD device -nodes, so let's add helpers for it. Also, we'll be making some -conversions on spi_nor (and nand_chip eventually) too, so get that ready -with their own helpers. - -Signed-off-by: Brian Norris -Reviewed-by: Boris Brezillon ---- - include/linux/mtd/mtd.h | 11 +++++++++++ - include/linux/mtd/nand.h | 11 +++++++++++ - include/linux/mtd/spi-nor.h | 11 +++++++++++ - 3 files changed, 33 insertions(+) - -diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h -index f17fa75..cc84923 100644 ---- a/include/linux/mtd/mtd.h -+++ b/include/linux/mtd/mtd.h -@@ -254,6 +254,17 @@ struct mtd_info { - int usecount; - }; - -+static inline void mtd_set_of_node(struct mtd_info *mtd, -+ struct device_node *np) -+{ -+ mtd->dev.of_node = np; -+} -+ -+static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd) -+{ -+ return mtd->dev.of_node; -+} -+ - int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); - int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, - void **virt, resource_size_t *phys); -diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h -index 1ded588..3c34ca4 100644 ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -741,6 +741,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) - chip->priv = priv; - } - -+static inline void nand_set_flash_node(struct nand_chip *chip, -+ struct device_node *np) -+{ -+ chip->flash_node = np; -+} -+ -+static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) -+{ -+ return chip->flash_node; -+} -+ - /* - * NAND Flash Manufacturer ID Codes - */ -diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h -index c8723b6..6d991df 100644 ---- a/include/linux/mtd/spi-nor.h -+++ b/include/linux/mtd/spi-nor.h -@@ -185,6 +185,17 @@ struct spi_nor { - void *priv; - }; - -+static inline void spi_nor_set_flash_node(struct spi_nor *nor, -+ struct device_node *np) -+{ -+ nor->flash_node = np; -+} -+ -+static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor) -+{ -+ return nor->flash_node; -+} -+ - /** - * spi_nor_scan() - scan the SPI NOR - * @nor: the spi_nor structure --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0063-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0063-net-mediatek-remove-incorrect-dma_mask-assignment.patch new file mode 100644 index 0000000000..021f8b43da --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0063-net-mediatek-remove-incorrect-dma_mask-assignment.patch @@ -0,0 +1,36 @@ +From 21f52c7a0ec569ae9dd72bfc619a7161e40a2e9d Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Mon, 14 Mar 2016 15:07:11 +0100 +Subject: [PATCH 63/78] net: mediatek: remove incorrect dma_mask assignment + +Device drivers should not mess with the DMA mask directly, +but instead call dma_set_mask() etc if needed. + +In case of the mtk_eth_soc driver, the mask already gets set +correctly when the device is created, and setting it again +is against the documented API. + +This removes the incorrect setting. + +Signed-off-by: Arnd Bergmann +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index a005bc4..fcd4ed7 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1678,9 +1678,6 @@ static int mtk_probe(struct platform_device *pdev) + struct mtk_eth *eth; + int err; + +- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; +- + device_reset(&pdev->dev); + + match = of_match_device(of_mtk_match, &pdev->dev); +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0064-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0064-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch deleted file mode 100644 index 533ff56877..0000000000 --- a/target/linux/mediatek/patches-4.4/0064-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 91f978e8a8f27eb9988d33904eaba55309b6c0b9 Mon Sep 17 00:00:00 2001 -From: Jorge Ramirez-Ortiz -Date: Wed, 2 Mar 2016 12:00:11 -0500 -Subject: [PATCH 64/66] mtd: mediatek: device tree docs for MTK Smart Device - Gen1 NAND - -This patch adds documentation support for Smart Device Gen1 type of -NAND controllers. - -Mediatek's SoC 2701 is one of the SoCs that implements this controller. - -Signed-off-by: Jorge Ramirez-Ortiz ---- - .../devicetree/bindings/mtd/mtksdg1-nand.txt | 38 ++++++++++++++++++++ - 1 file changed, 38 insertions(+) - create mode 100644 Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt - -diff --git a/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt -new file mode 100644 -index 0000000..129d17b ---- /dev/null -+++ b/Documentation/devicetree/bindings/mtd/mtksdg1-nand.txt -@@ -0,0 +1,38 @@ -+MTK Smart Device SoCs NAND controller DT binding -+ -+Required properties: -+- compatible: Should be "mediatek,mt2701-nfc". -+- reg: The first contains base physical address and size of -+ NAND controller's registers. The second contains base -+ physical address and size of NAND ECC engine. -+- interrupts: the NFC NFI interrupt, and the NFC ECC interrupt -+- clocks: NAND controller clocks. -+- clock-names: NAND controller clocks internal name. -+- vmch-supply: NAND power supply. -+- #address-cells: Partition address, should be set 1. -+- #size-cells: Partition size, should be set 1. -+ -+Optional properties: -+ -+nand-on-flash-bbt: Use a flash based bad block table. -+ -+Optional subnodes: -+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt -+ -+Example: -+ -+ nand: nand@1100d000 { -+ compatible = "mediatek,mt2701-nfc"; -+ reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>; -+ interrupts = , -+ ; -+ clocks = <&pericfg CLK_PERI_NFI>, <&pericfg CLK_PERI_NFI_ECC>, -+ <&pericfg CLK_PERI_NFI_PAD>; -+ clock-names = "nfi_ck", "nfi_ecc_ck", "nfi_pad_ck"; -+ vmch-supply = <&mt6323_vmch_reg>; -+ status = "disabled"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ ... -+ }; --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0064-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0064-net-mediatek-check-device_reset-return-code.patch new file mode 100644 index 0000000000..06aab2b205 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0064-net-mediatek-check-device_reset-return-code.patch @@ -0,0 +1,38 @@ +From e1e7d841480b3a0febdb999fd1c6c4213ee18ea7 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Mon, 14 Mar 2016 15:07:12 +0100 +Subject: [PATCH 64/78] net: mediatek: check device_reset return code + +The device_reset() function may fail, so we have to check +its return value, e.g. to make deferred probing work correctly. +gcc warns about it because of the warn_unused_result attribute: + +drivers/net/ethernet/mediatek/mtk_eth_soc.c: In function 'mtk_probe': +drivers/net/ethernet/mediatek/mtk_eth_soc.c:1679:2: error: ignoring return value of 'device_reset', declared with attribute warn_unused_result [-Werror=unused-result] + +This adds the trivial error check to propagate the return value +to the generic platform device probe code. + +Signed-off-by: Arnd Bergmann +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index fcd4ed7..7f2126b 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1678,7 +1678,9 @@ static int mtk_probe(struct platform_device *pdev) + struct mtk_eth *eth; + int err; + +- device_reset(&pdev->dev); ++ err = device_reset(&pdev->dev); ++ if (err) ++ return err; + + match = of_match_device(of_mtk_match, &pdev->dev); + soc = (struct mtk_soc_data *)match->data; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0065-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0065-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch deleted file mode 100644 index c21ca1db93..0000000000 --- a/target/linux/mediatek/patches-4.4/0065-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch +++ /dev/null @@ -1,1798 +0,0 @@ -From 7a9d3c8c4084fd37fa14c0e8db2830623f5da8cc Mon Sep 17 00:00:00 2001 -From: Jorge Ramirez-Ortiz -Date: Wed, 2 Mar 2016 12:00:12 -0500 -Subject: [PATCH 65/66] mtd: mediatek: driver for MTK Smart Device Gen1 NAND - -This patch adds support for mediatek's SDG1 NFC nand controller -embedded in SoC 2701. - -UBIFS support has been successfully tested. - -Signed-off-by: Jorge Ramirez-Ortiz ---- - drivers/mtd/nand/Kconfig | 6 + - drivers/mtd/nand/Makefile | 1 + - drivers/mtd/nand/mtksdg1_nand.c | 1535 +++++++++++++++++++++++++++++++++++ - drivers/mtd/nand/mtksdg1_nand_ecc.h | 75 ++ - drivers/mtd/nand/mtksdg1_nand_nfi.h | 119 +++ - 5 files changed, 1736 insertions(+) - create mode 100644 drivers/mtd/nand/mtksdg1_nand.c - create mode 100644 drivers/mtd/nand/mtksdg1_nand_ecc.h - create mode 100644 drivers/mtd/nand/mtksdg1_nand_nfi.h - -diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig -index 2896640..5ec072a 100644 ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -546,4 +546,10 @@ config MTD_NAND_HISI504 - help - Enables support for NAND controller on Hisilicon SoC Hip04. - -+config MTD_NAND_MTKSDG1 -+ tristate "Support for NAND controller on MTK Smart Device SoCs" -+ depends on HAS_DMA -+ help -+ Enables support for NAND controller on MTK Smart Device SoCs. -+ - endif # MTD_NAND -diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile -index 2c7f014..2a2620c 100644 ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -55,5 +55,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ - obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o - obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o - obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ -+obj-$(CONFIG_MTD_NAND_MTKSDG1) += mtksdg1_nand.o - - nand-objs := nand_base.o nand_bbt.o nand_timings.o -diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c -new file mode 100644 -index 0000000..55dd17d ---- /dev/null -+++ b/drivers/mtd/nand/mtksdg1_nand.c -@@ -0,0 +1,1535 @@ -+/* -+ * MTK smart device NAND Flash controller driver. -+ * Copyright (C) 2015-2016 MediaTek Inc. -+ * Authors: Xiaolei Li -+ * Jorge Ramirez-Ortiz -+ * -+ * 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 "mtksdg1_nand_nfi.h" -+#include "mtksdg1_nand_ecc.h" -+ -+#define MTK_IRQ_ECC "mtksdg1-nand-ecc" -+#define MTK_IRQ_NFI "mtksdg1-nand-nfi" -+#define MTK_NAME "mtksdg1-nand" -+ -+#define KB(x) ((x) * 1024UL) -+#define MB(x) (KB(x) * 1024UL) -+ -+#define SECTOR_SHIFT (10) -+#define SECTOR_SIZE (1UL << SECTOR_SHIFT) -+#define BYTES_TO_SECTORS(x) ((x) >> SECTOR_SHIFT) -+#define SECTORS_TO_BYTES(x) ((x) << SECTOR_SHIFT) -+ -+#define MTK_TIMEOUT (500) -+#define MTK_RESET_TIMEOUT (1 * HZ) -+ -+#define MTK_ECC_PARITY_BITS (14) -+#define MTK_NAND_MAX_CHIP (2) -+ -+#define MTK_OOB_ON (1) -+#define MTK_OOB_OFF (0) -+ -+/* raw accesses do not use ECC (ecc = !raw) */ -+#define MTK_ECC_OFF (1) -+#define MTK_ECC_ON (0) -+ -+struct mtk_nfc_clk { -+ struct clk *nfiecc_clk; -+ struct clk *nfi_clk; -+ struct clk *pad_clk; -+}; -+ -+struct mtk_nfc_saved_reg { -+ struct { -+ u32 enccnfg; -+ u32 deccnfg; -+ } ecc; -+ struct { -+ u32 emp_thresh; -+ u16 pagefmt; -+ u32 acccon; -+ u16 cnrnb; -+ u16 csel; -+ } nfi; -+}; -+ -+struct mtk_nfc_host { -+ struct mtk_nfc_clk clk; -+ struct nand_chip chip; -+ struct device *dev; -+ -+ struct { -+ struct completion complete; -+ void __iomem *base; -+ } nfi; -+ -+ struct { -+ struct completion complete; -+ void __iomem *base; -+ u32 dec_sec; -+ } ecc; -+ -+ u32 fdm_reg[MTKSDG1_NFI_FDM_REG_SIZE / sizeof(u32)]; -+ bool switch_oob; -+ u32 row_nob; -+ u8 *buffer; -+ -+#ifdef CONFIG_PM_SLEEP -+ struct mtk_nfc_saved_reg saved_reg; -+#endif -+}; -+ -+static struct nand_ecclayout nand_2k_64 = { -+ .oobfree = { {0, 16} }, -+}; -+ -+static struct nand_ecclayout nand_4k_128 = { -+ .oobfree = { {0, 32} }, -+}; -+ -+/* NFI register access */ -+static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg) -+{ -+ writel(val, host->nfi.base + reg); -+} -+static inline void mtk_nfi_writew(struct mtk_nfc_host *host, u16 val, u32 reg) -+{ -+ writew(val, host->nfi.base + reg); -+} -+static inline u32 mtk_nfi_readl(struct mtk_nfc_host *host, u32 reg) -+{ -+ return readl_relaxed(host->nfi.base + reg); -+} -+static inline u16 mtk_nfi_readw(struct mtk_nfc_host *host, u32 reg) -+{ -+ return readw_relaxed(host->nfi.base + reg); -+} -+static inline u8 mtk_nfi_readb(struct mtk_nfc_host *host, u32 reg) -+{ -+ return readb_relaxed(host->nfi.base + reg); -+} -+ -+/* ECC register access */ -+static inline void mtk_ecc_writel(struct mtk_nfc_host *host, u32 val, u32 reg) -+{ -+ writel(val, host->ecc.base + reg); -+} -+static inline void mtk_ecc_writew(struct mtk_nfc_host *host, u16 val, u32 reg) -+{ -+ writew(val, host->ecc.base + reg); -+} -+static inline u32 mtk_ecc_readl(struct mtk_nfc_host *host, u32 reg) -+{ -+ return readl_relaxed(host->ecc.base + reg); -+} -+static inline u16 mtk_ecc_readw(struct mtk_nfc_host *host, u32 reg) -+{ -+ return readw_relaxed(host->ecc.base + reg); -+} -+ -+static void mtk_nfc_hw_reset(struct mtk_nfc_host *host) -+{ -+ unsigned long timeout = MTK_RESET_TIMEOUT; -+ struct device *dev = host->dev; -+ u32 val; -+ -+ /* reset the state machine, data fifo and fdm data */ -+ mtk_nfi_writel(host, CON_FIFO_FLUSH | CON_NFI_RST, MTKSDG1_NFI_CON); -+ timeout += jiffies; -+ do { -+ val = mtk_nfi_readl(host, MTKSDG1_NFI_MASTER_STA); -+ val &= MASTER_STA_MASK; -+ if (!val) -+ return; -+ usleep_range(50, 100); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ dev_warn(dev, "nfi master active after in reset [0x%x] = 0x%x\n", -+ MTKSDG1_NFI_MASTER_STA, val); -+}; -+ -+static int mtk_nfc_set_command(struct mtk_nfc_host *host, u8 command) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct device *dev = host->dev; -+ u32 val; -+ -+ mtk_nfi_writel(host, command, MTKSDG1_NFI_CMD); -+ -+ /* wait for the NFI core to enter command mode */ -+ timeout += jiffies; -+ do { -+ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA); -+ val &= STA_CMD; -+ if (!val) -+ return 0; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ dev_warn(dev, "nfi core timed out entering command mode\n"); -+ -+ return -EIO; -+} -+ -+static int mtk_nfc_set_address(struct mtk_nfc_host *host, u32 column, u32 row, -+ u8 colnob, u8 row_nob) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct device *dev = host->dev; -+ u32 addr_nob, val; -+ -+ addr_nob = colnob | (row_nob << ADDR_ROW_NOB_SHIFT); -+ mtk_nfi_writel(host, column, MTKSDG1_NFI_COLADDR); -+ mtk_nfi_writel(host, row, MTKSDG1_NFI_ROWADDR); -+ mtk_nfi_writel(host, addr_nob, MTKSDG1_NFI_ADDRNOB); -+ -+ /* wait for the NFI core to enter address mode */ -+ timeout += jiffies; -+ do { -+ val = mtk_nfi_readl(host, MTKSDG1_NFI_STA); -+ val &= STA_ADDR; -+ if (!val) -+ return 0; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ dev_warn(dev, "nfi core timed out entering address mode\n"); -+ -+ return -EIO; -+} -+ -+static inline void mtk_ecc_encoder_idle(struct mtk_nfc_host *host) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct device *dev = host->dev; -+ u32 val; -+ -+ timeout += jiffies; -+ do { -+ val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIDLE); -+ val &= ENC_IDLE; -+ if (val) -+ return; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ dev_warn(dev, "hw init ecc encoder not idle\n"); -+} -+ -+static inline void mtk_ecc_decoder_idle(struct mtk_nfc_host *host) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct device *dev = host->dev; -+ u32 val; -+ -+ timeout += jiffies; -+ do { -+ val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIDLE); -+ val &= DEC_IDLE; -+ if (val) -+ return; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ dev_warn(dev, "hw init ecc decoder not idle\n"); -+} -+ -+static int mtk_nfc_transfer_done(struct mtk_nfc_host *host, u32 sectors) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ u32 cnt; -+ -+ /* wait for the sector count */ -+ timeout += jiffies; -+ do { -+ cnt = mtk_nfi_readl(host, MTKSDG1_NFI_ADDRCNTR); -+ cnt &= CNTR_MASK; -+ if (cnt >= sectors) -+ return 0; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ return -EIO; -+} -+ -+static int mtk_nfc_subpage_done(struct mtk_nfc_host *host, int sectors) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ u32 val; -+ -+ timeout += jiffies; -+ do { -+ val = mtk_nfi_readl(host, MTKSDG1_NFI_BYTELEN); -+ val &= CNTR_MASK; -+ if (val >= sectors) -+ return 0; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ return -EIO; -+} -+ -+static inline int mtk_nfc_data_ready(struct mtk_nfc_host *host) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ u8 val; -+ -+ timeout += jiffies; -+ do { -+ val = mtk_nfi_readw(host, MTKSDG1_NFI_PIO_DIRDY); -+ val &= PIO_DI_RDY; -+ if (val) -+ return 0; -+ cpu_relax(); -+ -+ } while (time_before(jiffies, timeout)); -+ -+ /* data _MUST_ not be accessed */ -+ return -EIO; -+} -+ -+static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd_to_nand(mtd); -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ struct device *dev = host->dev; -+ u32 dec_size, enc_size; -+ u32 ecc_bit, ecc_level; -+ u32 spare, fmt; -+ u32 reg; -+ -+ host->row_nob = 1; -+ if (chip->chipsize > MB(32)) -+ host->row_nob = chip->chipsize > MB(128) ? 3 : 2; -+ -+ spare = mtd->oobsize / BYTES_TO_SECTORS(mtd->writesize); -+ switch (spare) { -+ case 16: -+ ecc_bit = ECC_CNFG_4BIT; -+ ecc_level = 4; -+ break; -+ case 32: -+ ecc_bit = ECC_CNFG_12BIT; -+ ecc_level = 12; -+ break; -+ default: -+ dev_err(dev, "invalid spare size per sector: %d\n", spare); -+ return -EINVAL; -+ } -+ -+ chip->ecc.strength = ecc_level; -+ chip->ecc.size = SECTOR_SIZE; -+ -+ switch (mtd->writesize) { -+ case KB(2): -+ fmt = PAGEFMT_512_2K; -+ chip->ecc.layout = &nand_2k_64; -+ break; -+ case KB(4): -+ fmt = PAGEFMT_2K_4K; -+ chip->ecc.layout = &nand_4k_128; -+ break; -+ case KB(8): -+ fmt = PAGEFMT_4K_8K; -+ break; -+ default: -+ dev_err(dev, "invalid page size: %d\n", mtd->writesize); -+ return -EINVAL; -+ } -+ -+ /* configure PAGE FMT */ -+ reg = fmt; -+ reg |= PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT; -+ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_SHIFT; -+ reg |= MTKSDG1_NFI_FDM_REG_SIZE << PAGEFMT_FDM_ECC_SHIFT; -+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_PAGEFMT); -+ -+ /* configure ECC encoder (in bits) */ -+ enc_size = (SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE) << 3; -+ reg = ecc_bit | ECC_NFI_MODE | (enc_size << ECC_MS_SHIFT); -+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); -+ -+ /* configure ECC decoder (inbits) */ -+ dec_size = enc_size + ecc_level * MTK_ECC_PARITY_BITS; -+ reg = ecc_bit | ECC_NFI_MODE | (dec_size << ECC_MS_SHIFT); -+ reg |= (DEC_CNFG_CORRECT | DEC_EMPTY_EN); -+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_DECCNFG); -+ -+ return 0; -+} -+ -+static void mtk_nfc_device_reset(struct mtk_nfc_host *host) -+{ -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct device *dev = host->dev; -+ u16 chip; -+ int rc; -+ -+ mtk_nfc_hw_reset(host); -+ -+ /* enable reset done interrupt */ -+ mtk_nfi_writew(host, INTR_RST_DONE_EN, MTKSDG1_NFI_INTR_EN); -+ -+ /* configure FSM for reset operation */ -+ mtk_nfi_writew(host, CNFG_OP_RESET, MTKSDG1_NFI_CNFG); -+ -+ init_completion(&host->nfi.complete); -+ -+ mtk_nfc_set_command(host, NAND_CMD_RESET); -+ rc = wait_for_completion_timeout(&host->nfi.complete, timeout); -+ if (!rc) { -+ chip = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL); -+ dev_err(dev, "device(%d) reset timeout\n", chip); -+ } -+} -+ -+static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip) -+{ -+ struct nand_chip *nand = mtd_to_nand(mtd); -+ struct mtk_nfc_host *host = nand_get_controller_data(nand); -+ -+ if (chip < 0) -+ return; -+ -+ mtk_nfi_writel(host, chip, MTKSDG1_NFI_CSEL); -+} -+ -+static inline bool mtk_nfc_cmd_supported(unsigned command) -+{ -+ switch (command) { -+ case NAND_CMD_RESET: -+ case NAND_CMD_READID: -+ case NAND_CMD_STATUS: -+ case NAND_CMD_READOOB: -+ case NAND_CMD_ERASE1: -+ case NAND_CMD_ERASE2: -+ case NAND_CMD_SEQIN: -+ case NAND_CMD_PAGEPROG: -+ case NAND_CMD_CACHEDPROG: -+ case NAND_CMD_READ0: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static void mtk_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column, -+ int page_addr) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(mtd_to_nand(mtd)); -+ unsigned long const cmd_timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ struct completion *p = &host->nfi.complete; -+ u32 val; -+ int rc; -+ -+ if (mtk_nfc_cmd_supported(command)) -+ mtk_nfc_hw_reset(host); -+ -+ switch (command) { -+ case NAND_CMD_RESET: -+ mtk_nfc_device_reset(host); -+ break; -+ case NAND_CMD_READID: -+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD; -+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_READID); -+ mtk_nfc_set_address(host, column, 0, 1, 0); -+ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON); -+ break; -+ case NAND_CMD_STATUS: -+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_SRD; -+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_STATUS); -+ mtk_nfi_writel(host, CON_SRD, MTKSDG1_NFI_CON); -+ break; -+ case NAND_CMD_READOOB: -+ val = CNFG_READ_EN | CNFG_BYTE_RW | CNFG_OP_READ; -+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_READ0); -+ column += mtd->writesize; -+ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob); -+ val = CON_BRD | (1 << CON_SEC_SHIFT); -+ mtk_nfi_writel(host, val, MTKSDG1_NFI_CON); -+ break; -+ case NAND_CMD_ERASE1: -+ mtk_nfi_writew(host, INTR_ERS_DONE_EN, MTKSDG1_NFI_INTR_EN); -+ mtk_nfi_writew(host, CNFG_OP_ERASE, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_ERASE1); -+ mtk_nfc_set_address(host, 0, page_addr, 0, host->row_nob); -+ break; -+ case NAND_CMD_ERASE2: -+ init_completion(p); -+ mtk_nfc_set_command(host, NAND_CMD_ERASE2); -+ rc = wait_for_completion_timeout(p, cmd_timeout); -+ if (!rc) -+ dev_err(host->dev, "erase command timeout\n"); -+ break; -+ case NAND_CMD_SEQIN: -+ mtk_nfi_writew(host, CNFG_OP_PRGM, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_SEQIN); -+ mtk_nfc_set_address(host, column, page_addr, 2, host->row_nob); -+ break; -+ case NAND_CMD_PAGEPROG: -+ case NAND_CMD_CACHEDPROG: -+ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN); -+ init_completion(p); -+ mtk_nfc_set_command(host, command); -+ rc = wait_for_completion_timeout(p, cmd_timeout); -+ if (!rc) -+ dev_err(host->dev, "pageprogr command timeout\n"); -+ break; -+ case NAND_CMD_READ0: -+ val = CNFG_OP_READ | CNFG_READ_EN; -+ mtk_nfi_writew(host, val, MTKSDG1_NFI_CNFG); -+ mtk_nfc_set_command(host, NAND_CMD_READ0); -+ break; -+ default: -+ dev_warn(host->dev, "command 0x%x not supported\n", command); -+ break; -+ } -+} -+ -+static uint8_t mtk_nfc_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd_to_nand(mtd); -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ int rc; -+ -+ rc = mtk_nfc_data_ready(host); -+ if (rc < 0) { -+ dev_err(host->dev, "data not ready\n"); -+ return NAND_STATUS_FAIL; -+ } -+ -+ return mtk_nfi_readb(host, MTKSDG1_NFI_DATAR); -+} -+ -+static void mtk_nfc_write_fdm(struct nand_chip *chip, u32 sectors) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ u8 *src, *dst; -+ int i, j, reg; -+ -+ for (i = 0; i < sectors ; i++) { -+ /* read FDM from OOB into private area */ -+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ dst = (u8 *)host->fdm_reg; -+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); -+ -+ /* write FDM to registers */ -+ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) { -+ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ reg += j * sizeof(host->fdm_reg[0]); -+ mtk_nfi_writel(host, host->fdm_reg[j], reg); -+ } -+ } -+} -+ -+static int mtk_nfc_write_page(struct mtd_info *mtd, -+ struct nand_chip *chip, const uint8_t *buf, -+ int oob_on, int page, int raw) -+{ -+ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ struct completion *nfi = &host->nfi.complete; -+ struct device *dev = host->dev; -+ const bool use_ecc = !raw; -+ void *q = (void *) buf; -+ dma_addr_t dma_addr; -+ size_t dmasize; -+ u32 reg; -+ int ret; -+ -+ dmasize = mtd->writesize + (raw ? mtd->oobsize : 0); -+ -+ dma_addr = dma_map_single(dev, q, dmasize, DMA_TO_DEVICE); -+ if (dma_mapping_error(host->dev, dma_addr)) { -+ dev_err(host->dev, "dma mapping error\n"); -+ return -EINVAL; -+ } -+ -+ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG); -+ reg |= CNFG_AHB | CNFG_DMA_BURST_EN; -+ if (use_ecc) { -+ /** -+ * OOB will be generated -+ * - FDM: from register -+ * - ECC: from HW -+ */ -+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; -+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); -+ -+ mtk_ecc_encoder_idle(host); -+ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON); -+ -+ /* write OOB into the FDM registers (OOB area in MTK NAND) */ -+ if (oob_on) -+ mtk_nfc_write_fdm(chip, chip->ecc.steps); -+ } else { -+ /* OOB is part of the DMA transfer */ -+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); -+ } -+ -+ mtk_nfi_writel(host, chip->ecc.steps << CON_SEC_SHIFT, MTKSDG1_NFI_CON); -+ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR); -+ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN); -+ -+ init_completion(nfi); -+ -+ /* start DMA */ -+ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BWR; -+ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON); -+ -+ ret = wait_for_completion_timeout(nfi, msecs_to_jiffies(MTK_TIMEOUT)); -+ if (!ret) { -+ dev_err(dev, "program ahb done timeout\n"); -+ mtk_nfi_writew(host, 0, MTKSDG1_NFI_INTR_EN); -+ ret = -ETIMEDOUT; -+ goto timeout; -+ } -+ -+ ret = mtk_nfc_transfer_done(host, chip->ecc.steps); -+ if (ret < 0) -+ dev_err(dev, "hwecc write timeout\n"); -+timeout: -+ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE); -+ -+ if (use_ecc) { -+ mtk_ecc_encoder_idle(host); -+ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON); -+ } -+ -+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON); -+ -+ return ret; -+} -+ -+static int mtk_nfc_write_page_hwecc(struct mtd_info *mtd, -+ struct nand_chip *chip, const uint8_t *buf, -+ int oob_on, int page) -+{ -+ return mtk_nfc_write_page(mtd, chip, buf, oob_on, page, MTK_ECC_ON); -+} -+ -+static int mtk_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, -+ const uint8_t *buf, int oob_on, int pg) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ uint8_t *src, *dst; -+ size_t len; -+ u32 i; -+ -+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize); -+ -+ /* MTK internal 4KB page data layout: -+ * ---------------------------------- -+ * PAGE = 4KB, SECTOR = 1KB, OOB=128B -+ * page = sector_oob1 + sector_oob2 + sector_oob3 + sector_oob4 -+ * sector_oob = data (1KB) + FDM (8B) + ECC parity (21B) + free (3B) -+ * -+ */ -+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; -+ -+ for (i = 0; i < chip->ecc.steps; i++) { -+ -+ if (buf) { -+ src = (uint8_t *) buf + i * SECTOR_SIZE; -+ dst = host->buffer + i * len; -+ memcpy(dst, src, SECTOR_SIZE); -+ } -+ -+ if (oob_on) { -+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ dst = host->buffer + i * len + SECTOR_SIZE; -+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); -+ } -+ } -+ -+ return mtk_nfc_write_page(mtd, chip, host->buffer, MTK_OOB_OFF, pg, -+ MTK_ECC_OFF); -+} -+ -+static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ struct completion *ecc = &host->ecc.complete; -+ u32 reg, parity_bytes, i; -+ dma_addr_t dma_addr; -+ u32 *parity_region; -+ int rc, ret = 0; -+ size_t dmasize; -+ -+ dmasize = SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE; -+ dma_addr = dma_map_single(host->dev, data, dmasize, DMA_TO_DEVICE); -+ if (dma_mapping_error(host->dev, dma_addr)) { -+ dev_err(host->dev, "dma mapping error\n"); -+ return -EINVAL; -+ } -+ -+ /* enable the encoder in DMA mode to calculate the ECC bytes */ -+ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); -+ reg &= (~ECC_ENC_MODE_MASK); -+ reg |= ECC_DMA_MODE; -+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); -+ -+ mtk_ecc_writel(host, ENC_IRQEN, MTKSDG1_ECC_ENCIRQ_EN); -+ mtk_ecc_writel(host, lower_32_bits(dma_addr), MTKSDG1_ECC_ENCDIADDR); -+ -+ init_completion(ecc); -+ mtk_ecc_writew(host, ENC_EN, MTKSDG1_ECC_ENCCON); -+ -+ rc = wait_for_completion_timeout(ecc, msecs_to_jiffies(MTK_TIMEOUT)); -+ if (!rc) { -+ dev_err(host->dev, "ecc encode done timeout\n"); -+ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN); -+ ret = -ETIMEDOUT; -+ goto timeout; -+ } -+ -+ mtk_ecc_encoder_idle(host); -+ -+ /** -+ * Program ECC bytes to OOB -+ * per sector oob = FDM + ECC + SPARE -+ */ -+ -+ parity_region = (u32 *) (data + SECTOR_SIZE + MTKSDG1_NFI_FDM_REG_SIZE); -+ parity_bytes = (chip->ecc.strength * MTK_ECC_PARITY_BITS + 7) >> 3; -+ -+ /* write the parity bytes generated by the ECC back to the OOB region */ -+ for (i = 0; i < parity_bytes; i += sizeof(u32)) -+ *parity_region++ = mtk_ecc_readl(host, MTKSDG1_ECC_ENCPAR0 + i); -+ -+timeout: -+ -+ dma_unmap_single(host->dev, dma_addr, dmasize, DMA_TO_DEVICE); -+ -+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_ENCCON); -+ reg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); -+ reg &= (~ECC_ENC_MODE_MASK); -+ reg |= ECC_NFI_MODE; -+ mtk_ecc_writel(host, reg, MTKSDG1_ECC_ENCCNFG); -+ -+ return ret; -+} -+ -+static int mtk_nfc_write_subpage_hwecc(struct mtd_info *mtd, -+ struct nand_chip *chip, uint32_t offset, uint32_t data_len, -+ const uint8_t *buf, int oob_on, int pg) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ uint8_t *src, *dst; -+ u32 start, end; -+ size_t len; -+ int i, ret; -+ -+ start = BYTES_TO_SECTORS(offset); -+ end = BYTES_TO_SECTORS(offset + data_len + SECTOR_SIZE - 1); -+ -+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; -+ -+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize); -+ for (i = 0; i < chip->ecc.steps; i++) { -+ -+ /* write data */ -+ src = (uint8_t *) buf + i * SECTOR_SIZE; -+ dst = host->buffer + i * len; -+ memcpy(dst, src, SECTOR_SIZE); -+ -+ if (i < start) -+ continue; -+ -+ if (i >= end) -+ continue; -+ -+ /* write fdm */ -+ if (oob_on) { -+ src = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ dst = host->buffer + i * len + SECTOR_SIZE; -+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); -+ } -+ -+ /* point to the start of data */ -+ src = host->buffer + i * len; -+ -+ /* program the CRC back to the OOB */ -+ ret = mtk_nfc_sector_encode(chip, src); -+ if (ret < 0) -+ return ret; -+ } -+ -+ /* use the data in the private buffer (now with FDM and CRC) to perform -+ * a raw write -+ */ -+ src = host->buffer; -+ return mtk_nfc_write_page(mtd, chip, src, MTK_OOB_OFF, pg, MTK_ECC_OFF); -+} -+ -+static int mtk_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ u8 *buf = chip->buffers->databuf; -+ int ret; -+ -+ memset(buf, 0xff, mtd->writesize); -+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -+ ret = mtk_nfc_write_page_hwecc(mtd, chip, buf, MTK_OOB_ON, page); -+ if (ret < 0) -+ return -EIO; -+ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ ret = chip->waitfunc(mtd, chip); -+ -+ return ret & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+static int mtk_nfc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ int ret; -+ -+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); -+ ret = mtk_nfc_write_page_raw(mtd, chip, NULL, MTK_OOB_ON, page); -+ if (ret < 0) -+ return -EIO; -+ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ ret = chip->waitfunc(mtd, chip); -+ -+ return ret & NAND_STATUS_FAIL ? -EIO : 0; -+} -+ -+static int mtk_nfc_ecc_check(struct mtd_info *mtd, struct nand_chip *chip, -+ u32 sectors) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ u32 offset, i, err, max_bitflip; -+ -+ max_bitflip = 0; -+ -+ for (i = 0; i < sectors; i++) { -+ offset = (i >> 2) << 2; -+ err = mtk_ecc_readl(host, MTKSDG1_ECC_DECENUM0 + offset); -+ err = err >> ((i % 4) * 8); -+ err &= ERR_MASK; -+ if (err == ERR_MASK) { -+ /* uncorrectable errors */ -+ mtd->ecc_stats.failed++; -+ continue; -+ } -+ -+ mtd->ecc_stats.corrected += err; -+ max_bitflip = max_t(u32, max_bitflip, err); -+ } -+ -+ return max_bitflip; -+} -+ -+static void mtk_nfc_read_fdm(struct nand_chip *chip, u32 sectors) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ int i, j, reg; -+ u8 *dst, *src; -+ -+ for (i = 0; i < sectors; i++) { -+ /* read FDM register into host memory */ -+ for (j = 0; j < ARRAY_SIZE(host->fdm_reg); j++) { -+ reg = MTKSDG1_NFI_FDM0L + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ reg += j * sizeof(host->fdm_reg[0]); -+ host->fdm_reg[j] = mtk_nfi_readl(host, reg); -+ } -+ -+ /* copy FDM register from host to OOB */ -+ src = (u8 *)host->fdm_reg; -+ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); -+ } -+} -+ -+static int mtk_nfc_update_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ u8 *buf, u32 sectors) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ int i, bitflips = 0; -+ -+ /* if the page is empty, no bitflips and clear data and oob */ -+ if (mtk_nfi_readl(host, MTKSDG1_NFI_STA) & STA_EMP_PAGE) { -+ memset(buf, 0xff, SECTORS_TO_BYTES(sectors)); -+ -+ /* empty page: update OOB with 0xFF */ -+ for (i = 0; i < sectors; i++) { -+ memset(chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE, -+ 0xff, MTKSDG1_NFI_FDM_REG_SIZE); -+ } -+ } else { -+ /* update OOB with HW info */ -+ mtk_nfc_read_fdm(chip, sectors); -+ -+ /* return the bitflips */ -+ bitflips = mtk_nfc_ecc_check(mtd, chip, sectors); -+ } -+ -+ return bitflips; -+} -+ -+static int mtk_nfc_block_markbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_chip *chip = mtd_to_nand(mtd); -+ u8 *buf = chip->buffers->databuf; -+ int rc, i, pg; -+ -+ /* block_markbad writes 0x00 at data and OOB */ -+ memset(buf, 0x00, mtd->writesize + mtd->oobsize); -+ -+ /* Write to first/last page(s) if necessary */ -+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) -+ ofs += mtd->erasesize - mtd->writesize; -+ -+ i = 0; -+ do { -+ pg = (int)(ofs >> chip->page_shift); -+ -+ /** -+ * write 0x00 to DATA & OOB in flash -+ * No need to reorganize the page since it is all 0x00 -+ */ -+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, pg); -+ rc = mtk_nfc_write_page(mtd, chip, buf, MTK_OOB_OFF, pg, -+ MTK_ECC_OFF); -+ if (rc < 0) -+ return rc; -+ -+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); -+ rc = chip->waitfunc(mtd, chip); -+ rc = rc & NAND_STATUS_FAIL ? -EIO : 0; -+ if (rc < 0) -+ return rc; -+ -+ ofs += mtd->writesize; -+ i++; -+ -+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); -+ -+ return 0; -+} -+ -+static int mtk_nfc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, -+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, -+ int page, int raw) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ unsigned long timeout = msecs_to_jiffies(MTK_TIMEOUT); -+ u32 reg, column, spare, sectors, start, end; -+ struct completion *nfi, *ecc; -+ const bool use_ecc = !raw; -+ int bitflips = -EIO; -+ dma_addr_t dma_addr; -+ size_t len; -+ u8 *buf; -+ int rc; -+ -+ nfi = &host->nfi.complete; -+ ecc = &host->ecc.complete; -+ -+ start = BYTES_TO_SECTORS(data_offs); -+ end = BYTES_TO_SECTORS(data_offs + readlen + SECTOR_SIZE - 1); -+ sectors = end - start; -+ -+ spare = mtd->oobsize / chip->ecc.steps; -+ column = start * (SECTOR_SIZE + spare); -+ -+ len = SECTORS_TO_BYTES(sectors) + (raw ? sectors * spare : 0); -+ buf = bufpoi + SECTORS_TO_BYTES(start); -+ -+ /* map the device memory */ -+ dma_addr = dma_map_single(host->dev, buf, len, DMA_FROM_DEVICE); -+ if (dma_mapping_error(host->dev, dma_addr)) { -+ dev_err(host->dev, "dma mapping error\n"); -+ return -EINVAL; -+ } -+ -+ /* configure the transfer */ -+ reg = mtk_nfi_readw(host, MTKSDG1_NFI_CNFG); -+ reg |= CNFG_DMA_BURST_EN | CNFG_AHB; -+ if (use_ecc) { -+ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; -+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); -+ -+ /* enable encoder */ -+ mtk_ecc_decoder_idle(host); -+ mtk_ecc_writel(host, DEC_EN, MTKSDG1_ECC_DECCON); -+ } else -+ mtk_nfi_writew(host, reg, MTKSDG1_NFI_CNFG); -+ -+ mtk_nfi_writel(host, sectors << CON_SEC_SHIFT, MTKSDG1_NFI_CON); -+ mtk_nfi_writew(host, INTR_BUSY_RT_EN, MTKSDG1_NFI_INTR_EN); -+ -+ init_completion(nfi); -+ -+ mtk_nfc_set_address(host, column, page, 2, host->row_nob); -+ mtk_nfc_set_command(host, NAND_CMD_READSTART); -+ rc = wait_for_completion_timeout(nfi, timeout); -+ if (!rc) { -+ dev_err(host->dev, "read busy return timeout\n"); -+ goto error; -+ } -+ -+ mtk_nfi_writew(host, INTR_AHB_DONE_EN, MTKSDG1_NFI_INTR_EN); -+ mtk_nfi_writel(host, lower_32_bits(dma_addr), MTKSDG1_NFI_STRADDR); -+ -+ if (use_ecc) { -+ /* program ECC with sector count */ -+ host->ecc.dec_sec = sectors; -+ init_completion(ecc); -+ mtk_ecc_writew(host, DEC_IRQEN, MTKSDG1_ECC_DECIRQ_EN); -+ } -+ -+ init_completion(nfi); -+ -+ /* start DMA */ -+ reg = mtk_nfi_readl(host, MTKSDG1_NFI_CON) | CON_BRD; -+ mtk_nfi_writel(host, reg, MTKSDG1_NFI_CON); -+ -+ rc = wait_for_completion_timeout(nfi, timeout); -+ if (!rc) -+ dev_warn(host->dev, "read ahb/dma done timeout\n"); -+ -+ /* DMA interrupt didn't trigger, check page done just in case */ -+ rc = mtk_nfc_subpage_done(host, sectors); -+ if (rc < 0) { -+ dev_err(host->dev, "subpage done timeout\n"); -+ goto error; -+ } -+ -+ /* raw transfer successful */ -+ bitflips = 0; -+ -+ if (use_ecc) { -+ rc = wait_for_completion_timeout(ecc, timeout); -+ if (!rc) { -+ dev_err(host->dev, "ecc decode timeout\n"); -+ host->ecc.dec_sec = 0; -+ bitflips = -ETIMEDOUT; -+ goto error; -+ } -+ bitflips = mtk_nfc_update_oob(mtd, chip, buf, sectors); -+ } -+ -+error: -+ dma_unmap_single(host->dev, dma_addr, len, DMA_FROM_DEVICE); -+ -+ if (use_ecc) { -+ /* make sure the ECC dec irq is disabled */ -+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN); -+ mtk_ecc_decoder_idle(host); -+ -+ /* disable ECC dec */ -+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECCON); -+ } -+ -+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_CON); -+ -+ return bitflips; -+} -+ -+static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd, -+ struct nand_chip *chip, uint32_t data_offs, -+ uint32_t readlen, uint8_t *bufpoi, int page) -+{ -+ return mtk_nfc_read_subpage(mtd, chip, data_offs, readlen, -+ bufpoi, page, MTK_ECC_ON); -+} -+ -+static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf, int oob_on, int page) -+{ -+ return mtk_nfc_read_subpage_hwecc(mtd, chip, 0, mtd->writesize, -+ buf, page); -+} -+ -+static int mtk_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf, int oob_on, int page) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ uint8_t *src, *dst; -+ int i, ret; -+ size_t len; -+ -+ dst = host->buffer; -+ memset(dst, 0xff, mtd->writesize + mtd->oobsize); -+ ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, dst, page, 1); -+ if (ret < 0) -+ return ret; -+ -+ len = SECTOR_SIZE + mtd->oobsize / chip->ecc.steps; -+ -+ /* copy to the output buffer */ -+ for (i = 0; i < chip->ecc.steps; i++) { -+ -+ /* copy sector data */ -+ if (buf) { -+ src = host->buffer + i * len; -+ dst = buf + i * SECTOR_SIZE; -+ memcpy(dst, src, SECTOR_SIZE); -+ } -+ -+ /* copy FDM data to OOB */ -+ if (oob_on) { -+ src = host->buffer + i * len + SECTOR_SIZE; -+ dst = chip->oob_poi + i * MTKSDG1_NFI_FDM_REG_SIZE; -+ memcpy(dst, src, MTKSDG1_NFI_FDM_REG_SIZE); -+ } -+ } -+ -+ return ret; -+} -+ -+static void mtk_nfc_switch_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ uint8_t *buf) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ size_t spare; -+ u32 sectors; -+ u8 *bufpoi; -+ int len; -+ -+ spare = mtd->oobsize / chip->ecc.steps; -+ sectors = mtd->writesize / (SECTOR_SIZE + spare); -+ -+ /** -+ * MTK: DATA+oob1, DATA+oob2, DATA+oob3 ... -+ * LNX: DATA+OOB -+ */ -+ /* point to the last oob_i from the NAND device*/ -+ bufpoi = buf + mtd->writesize - (sectors * spare); -+ len = sizeof(host->fdm_reg); -+ -+ /* copy NAND oob to private area */ -+ memcpy(host->fdm_reg, bufpoi, len); -+ -+ /* copy oob_poi to NAND */ -+ memcpy(bufpoi, chip->oob_poi, len); -+ -+ /* copy NAND oob to oob_poi */ -+ memcpy(chip->oob_poi, host->fdm_reg, sizeof(host->fdm_reg)); -+ memset(host->fdm_reg, 0x00, len); -+} -+ -+static int mtk_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ struct mtk_nfc_host *host = nand_get_controller_data(chip); -+ u8 *buf = chip->buffers->databuf; -+ struct mtd_ecc_stats stats; -+ int ret; -+ -+ stats = mtd->ecc_stats; -+ -+ memset(buf, 0xff, mtd->writesize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ -+ ret = mtk_nfc_read_page_hwecc(mtd, chip, buf, 1, page); -+ -+ if (host->switch_oob) -+ mtk_nfc_switch_oob(mtd, chip, buf); -+ -+ if (ret < mtd->bitflip_threshold) -+ mtd->ecc_stats.corrected = stats.corrected; -+ -+ return ret; -+} -+ -+static int mtk_nfc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, -+ int page) -+{ -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ -+ return mtk_nfc_read_page_raw(mtd, chip, NULL, MTK_OOB_ON, page); -+} -+ -+static inline void mtk_nfc_hw_init(struct mtk_nfc_host *host) -+{ -+ mtk_nfi_writel(host, 0x10804211, MTKSDG1_NFI_ACCCON); -+ mtk_nfi_writew(host, 0xf1, MTKSDG1_NFI_CNRNB); -+ mtk_nfc_hw_reset(host); -+ -+ /* clear interrupt */ -+ mtk_nfi_readl(host, MTKSDG1_NFI_INTR_STA); -+ mtk_nfi_writel(host, 0, MTKSDG1_NFI_INTR_EN); -+ -+ /* ECC encoder init */ -+ mtk_ecc_encoder_idle(host); -+ mtk_ecc_writew(host, ENC_DE, MTKSDG1_ECC_ENCCON); -+ -+ /* ECC decoder init */ -+ mtk_ecc_decoder_idle(host); -+ mtk_ecc_writel(host, DEC_DE, MTKSDG1_ECC_DECCON); -+} -+ -+static irqreturn_t mtk_nfi_irq(int irq, void *devid) -+{ -+ struct mtk_nfc_host *host = devid; -+ u16 sta, ien; -+ -+ sta = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_STA); -+ ien = mtk_nfi_readw(host, MTKSDG1_NFI_INTR_EN); -+ -+ if (!(sta & ien)) -+ return IRQ_NONE; -+ -+ mtk_nfi_writew(host, ~sta & ien, MTKSDG1_NFI_INTR_EN); -+ complete(&host->nfi.complete); -+ -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t mtk_ecc_irq(int irq, void *devid) -+{ -+ struct mtk_nfc_host *host = devid; -+ u32 reg_val, mask; -+ -+ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECIRQ_STA); -+ if (reg_val & DEC_IRQEN) { -+ if (host->ecc.dec_sec) { -+ mask = 1 << (host->ecc.dec_sec - 1); -+ reg_val = mtk_ecc_readw(host, MTKSDG1_ECC_DECDONE); -+ if (mask & reg_val) { -+ host->ecc.dec_sec = 0; -+ complete(&host->ecc.complete); -+ mtk_ecc_writew(host, 0, MTKSDG1_ECC_DECIRQ_EN); -+ } -+ } else -+ dev_warn(host->dev, "spurious DEC_IRQ\n"); -+ -+ return IRQ_HANDLED; -+ } -+ -+ reg_val = mtk_ecc_readl(host, MTKSDG1_ECC_ENCIRQ_STA); -+ if (reg_val & ENC_IRQEN) { -+ complete(&host->ecc.complete); -+ mtk_ecc_writel(host, 0, MTKSDG1_ECC_ENCIRQ_EN); -+ -+ return IRQ_HANDLED; -+ } -+ -+ return IRQ_NONE; -+} -+ -+static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk) -+{ -+ int ret; -+ -+ ret = clk_prepare_enable(clk->nfi_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable nfi clk\n"); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clk->nfiecc_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable nfiecc clk\n"); -+ goto out_nfiecc_clk_disable; -+ } -+ -+ ret = clk_prepare_enable(clk->pad_clk); -+ if (ret) { -+ dev_err(dev, "failed to enable pad clk\n"); -+ goto out_pad_clk_disable; -+ } -+ -+ return 0; -+ -+out_pad_clk_disable: -+ clk_disable_unprepare(clk->nfiecc_clk); -+ -+out_nfiecc_clk_disable: -+ clk_disable_unprepare(clk->nfi_clk); -+ -+ return ret; -+} -+ -+static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk) -+{ -+ clk_disable_unprepare(clk->nfi_clk); -+ clk_disable_unprepare(clk->nfiecc_clk); -+ clk_disable_unprepare(clk->pad_clk); -+} -+ -+static int mtk_nfc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct mtk_nfc_host *host; -+ struct nand_chip *chip; -+ struct mtd_info *mtd; -+ struct resource *res; -+ int ret, irq; -+ size_t len; -+ -+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); -+ if (!host) -+ return -ENOMEM; -+ -+ chip = &host->chip; -+ mtd = nand_to_mtd(chip); -+ host->dev = dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ host->nfi.base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(host->nfi.base)) { -+ ret = PTR_ERR(host->nfi.base); -+ dev_err(dev, "no nfi base\n"); -+ return ret; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ host->ecc.base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(host->ecc.base)) { -+ ret = PTR_ERR(host->ecc.base); -+ dev_err(dev, "no ecc base\n"); -+ return ret; -+ } -+ -+ host->clk.nfi_clk = devm_clk_get(dev, "nfi_clk"); -+ if (IS_ERR(host->clk.nfi_clk)) { -+ dev_err(dev, "no clk\n"); -+ ret = PTR_ERR(host->clk.nfi_clk); -+ return ret; -+ } -+ -+ host->clk.nfiecc_clk = devm_clk_get(dev, "nfiecc_clk"); -+ if (IS_ERR(host->clk.nfiecc_clk)) { -+ dev_err(dev, "no ecc clk\n"); -+ ret = PTR_ERR(host->clk.nfiecc_clk); -+ return ret; -+ } -+ -+ host->clk.pad_clk = devm_clk_get(dev, "pad_clk"); -+ if (IS_ERR(host->clk.pad_clk)) { -+ dev_err(dev, "no pad clk\n"); -+ ret = PTR_ERR(host->clk.pad_clk); -+ return ret; -+ } -+ -+ ret = mtk_nfc_enable_clk(dev, &host->clk); -+ if (ret) -+ return ret; -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ dev_err(dev, "no nfi irq resource\n"); -+ ret = -EINVAL; -+ goto clk_disable; -+ } -+ -+ ret = devm_request_irq(dev, irq, mtk_nfi_irq, 0x0, MTK_IRQ_NFI, host); -+ if (ret) { -+ dev_err(dev, "failed to request nfi irq\n"); -+ goto clk_disable; -+ } -+ -+ irq = platform_get_irq(pdev, 1); -+ if (irq < 0) { -+ dev_err(dev, "no ecc irq resource\n"); -+ ret = -EINVAL; -+ goto clk_disable; -+ } -+ -+ ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, MTK_IRQ_ECC, host); -+ if (ret) { -+ dev_err(dev, "failed to request ecc irq\n"); -+ goto clk_disable; -+ } -+ -+ ret = dma_set_mask(dev, DMA_BIT_MASK(32)); -+ if (ret) { -+ dev_err(dev, "failed to set dma mask\n"); -+ goto clk_disable; -+ } -+ -+ platform_set_drvdata(pdev, host); -+ -+ mtd_set_of_node(mtd, np); -+ mtd->owner = THIS_MODULE; -+ mtd->dev.parent = dev; -+ mtd->name = MTK_NAME; -+ -+ nand_set_controller_data(chip, host); -+ chip->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ; -+ chip->block_markbad = mtk_nfc_block_markbad; -+ chip->select_chip = mtk_nfc_select_chip; -+ chip->read_byte = mtk_nfc_read_byte; -+ chip->cmdfunc = mtk_nfc_cmdfunc; -+ chip->ecc.mode = NAND_ECC_HW; -+ chip->ecc.write_subpage = mtk_nfc_write_subpage_hwecc; -+ chip->ecc.write_page_raw = mtk_nfc_write_page_raw; -+ chip->ecc.write_page = mtk_nfc_write_page_hwecc; -+ chip->ecc.write_oob_raw = mtk_nfc_write_oob_raw; -+ chip->ecc.write_oob = mtk_nfc_write_oob; -+ chip->ecc.read_subpage = mtk_nfc_read_subpage_hwecc; -+ chip->ecc.read_page_raw = mtk_nfc_read_page_raw; -+ chip->ecc.read_oob_raw = mtk_nfc_read_oob_raw; -+ chip->ecc.read_page = mtk_nfc_read_page_hwecc; -+ chip->ecc.read_oob = mtk_nfc_read_oob; -+ -+ mtk_nfc_hw_init(host); -+ -+ ret = nand_scan_ident(mtd, MTK_NAND_MAX_CHIP, NULL); -+ if (ret) { -+ ret = -ENODEV; -+ goto clk_disable; -+ } -+ -+ ret = mtk_nfc_hw_runtime_config(mtd); -+ if (ret < 0) { -+ dev_err(dev, "nand device not supported\n"); -+ goto clk_disable; -+ } -+ -+ len = mtd->writesize + mtd->oobsize; -+ host->buffer = devm_kzalloc(dev, len, GFP_KERNEL); -+ if (!host->buffer) { -+ ret = -ENOMEM; -+ goto clk_disable; -+ } -+ -+ /* required to create bbt table if not present */ -+ host->switch_oob = true; -+ ret = nand_scan_tail(mtd); -+ if (ret) { -+ ret = -ENODEV; -+ goto clk_disable; -+ } -+ host->switch_oob = false; -+ -+ ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); -+ if (ret) { -+ dev_err(dev, "mtd parse partition error\n"); -+ goto nand_free; -+ } -+ -+ return 0; -+ -+nand_free: -+ nand_release(mtd); -+ -+clk_disable: -+ mtk_nfc_disable_clk(&host->clk); -+ -+ return ret; -+} -+ -+static int mtk_nfc_remove(struct platform_device *pdev) -+{ -+ struct mtk_nfc_host *host = platform_get_drvdata(pdev); -+ struct mtd_info *mtd = nand_to_mtd(&host->chip); -+ -+ nand_release(mtd); -+ mtk_nfc_disable_clk(&host->clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int mtk_nfc_suspend(struct device *dev) -+{ -+ struct mtk_nfc_host *host = dev_get_drvdata(dev); -+ struct mtk_nfc_saved_reg *reg = &host->saved_reg; -+ -+ reg->nfi.emp_thresh = mtk_nfi_readl(host, MTKSDG1_NFI_EMPTY_THRESH); -+ reg->ecc.enccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_ENCCNFG); -+ reg->ecc.deccnfg = mtk_ecc_readl(host, MTKSDG1_ECC_DECCNFG); -+ reg->nfi.pagefmt = mtk_nfi_readw(host, MTKSDG1_NFI_PAGEFMT); -+ reg->nfi.acccon = mtk_nfi_readl(host, MTKSDG1_NFI_ACCCON); -+ reg->nfi.cnrnb = mtk_nfi_readw(host, MTKSDG1_NFI_CNRNB); -+ reg->nfi.csel = mtk_nfi_readw(host, MTKSDG1_NFI_CSEL); -+ -+ mtk_nfc_disable_clk(&host->clk); -+ -+ return 0; -+} -+ -+static int mtk_nfc_resume(struct device *dev) -+{ -+ struct mtk_nfc_host *host = dev_get_drvdata(dev); -+ struct mtk_nfc_saved_reg *reg = &host->saved_reg; -+ struct nand_chip *chip = &host->chip; -+ struct mtd_info *mtd = nand_to_mtd(chip); -+ int ret; -+ u32 i; -+ -+ udelay(200); -+ -+ ret = mtk_nfc_enable_clk(dev, &host->clk); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < chip->numchips; i++) { -+ chip->select_chip(mtd, i); -+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ } -+ -+ mtk_nfi_writel(host, reg->nfi.emp_thresh, MTKSDG1_NFI_EMPTY_THRESH); -+ mtk_nfi_writew(host, reg->nfi.pagefmt, MTKSDG1_NFI_PAGEFMT); -+ mtk_ecc_writel(host, reg->ecc.enccnfg, MTKSDG1_ECC_ENCCNFG); -+ mtk_ecc_writel(host, reg->ecc.deccnfg, MTKSDG1_ECC_DECCNFG); -+ mtk_nfi_writel(host, reg->nfi.acccon, MTKSDG1_NFI_ACCCON); -+ mtk_nfi_writew(host, reg->nfi.cnrnb, MTKSDG1_NFI_CNRNB); -+ mtk_nfi_writew(host, reg->nfi.csel, MTKSDG1_NFI_CSEL); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume); -+#endif -+ -+static const struct of_device_id mtk_nfc_id_table[] = { -+ { .compatible = "mediatek,mt2701-nfc" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, mtk_nfc_id_table); -+ -+static struct platform_driver mtk_nfc_driver = { -+ .probe = mtk_nfc_probe, -+ .remove = mtk_nfc_remove, -+ .driver = { -+ .name = MTK_NAME, -+ .of_match_table = mtk_nfc_id_table, -+#ifdef CONFIG_PM_SLEEP -+ .pm = &mtk_nfc_pm_ops, -+#endif -+ }, -+}; -+ -+module_platform_driver(mtk_nfc_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Xiaolei Li "); -+MODULE_DESCRIPTION("MTK Nand Flash Controller Driver"); -+ -diff --git a/drivers/mtd/nand/mtksdg1_nand_ecc.h b/drivers/mtd/nand/mtksdg1_nand_ecc.h -new file mode 100644 -index 0000000..d90b196 ---- /dev/null -+++ b/drivers/mtd/nand/mtksdg1_nand_ecc.h -@@ -0,0 +1,75 @@ -+/* -+ * MTK smart device ECC engine register. -+ * Copyright (C) 2015-2016 MediaTek Inc. -+ * Author: Xiaolei.Li -+ * -+ * 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 MTKSDG1_NAND_ECC_H -+#define MTKSDG1_NAND_ECC_H -+ -+/* ECC engine register definition */ -+#define MTKSDG1_ECC_ENCCON (0x00) -+#define ENC_EN (1) -+#define ENC_DE (0) -+ -+#define MTKSDG1_ECC_ENCCNFG (0x04) -+#define ECC_CNFG_4BIT (0) -+#define ECC_CNFG_12BIT (4) -+#define ECC_NFI_MODE BIT(5) -+#define ECC_DMA_MODE (0) -+#define ECC_ENC_MODE_MASK (0x3 << 5) -+#define ECC_MS_SHIFT (16) -+ -+#define MTKSDG1_ECC_ENCDIADDR (0x08) -+ -+#define MTKSDG1_ECC_ENCIDLE (0x0C) -+#define ENC_IDLE BIT(0) -+ -+#define MTKSDG1_ECC_ENCPAR0 (0x10) -+#define MTKSDG1_ECC_ENCSTA (0x7C) -+ -+#define MTKSDG1_ECC_ENCIRQ_EN (0x80) -+#define ENC_IRQEN BIT(0) -+ -+#define MTKSDG1_ECC_ENCIRQ_STA (0x84) -+ -+#define MTKSDG1_ECC_DECCON (0x100) -+#define DEC_EN (1) -+#define DEC_DE (0) -+ -+#define MTKSDG1_ECC_DECCNFG (0x104) -+#define DEC_EMPTY_EN BIT(31) -+#define DEC_CNFG_FER (0x1 << 12) -+#define DEC_CNFG_EL (0x2 << 12) -+#define DEC_CNFG_CORRECT (0x3 << 12) -+ -+#define MTKSDG1_ECC_DECIDLE (0x10C) -+#define DEC_IDLE BIT(0) -+ -+#define MTKSDG1_ECC_DECFER (0x110) -+ -+#define MTKSDG1_ECC_DECENUM0 (0x114) -+#define ERR_MASK (0x3f) -+ -+#define MTKSDG1_ECC_DECDONE (0x124) -+ -+#define MTKSDG1_ECC_DECEL0 (0x128) -+ -+#define MTKSDG1_ECC_DECIRQ_EN (0x200) -+#define DEC_IRQEN BIT(0) -+ -+#define MTKSDG1_ECC_DECIRQ_STA (0x204) -+ -+#define MTKSDG1_ECC_DECFSM (0x208) -+#define DECFSM_MASK (0x7f0f0f0f) -+#define DECFSM_IDLE (0x01010101) -+#endif -diff --git a/drivers/mtd/nand/mtksdg1_nand_nfi.h b/drivers/mtd/nand/mtksdg1_nand_nfi.h -new file mode 100644 -index 0000000..a9aa6f6 ---- /dev/null -+++ b/drivers/mtd/nand/mtksdg1_nand_nfi.h -@@ -0,0 +1,119 @@ -+/* -+ * MTK smart device NAND Flash controller register. -+ * Copyright (C) 2015-2016 MediaTek Inc. -+ * Author: Xiaolei.Li -+ * -+ * 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 MTKSDG1_NAND_NFI_H -+#define MTKSDG1_NAND_NFI_H -+ -+/* NAND controller register definition */ -+#define MTKSDG1_NFI_CNFG (0x00) -+#define CNFG_AHB BIT(0) -+#define CNFG_READ_EN BIT(1) -+#define CNFG_DMA_BURST_EN BIT(2) -+#define CNFG_BYTE_RW BIT(6) -+#define CNFG_HW_ECC_EN BIT(8) -+#define CNFG_AUTO_FMT_EN BIT(9) -+#define CNFG_OP_IDLE (0 << 12) -+#define CNFG_OP_READ (1 << 12) -+#define CNFG_OP_SRD (2 << 12) -+#define CNFG_OP_PRGM (3 << 12) -+#define CNFG_OP_ERASE (4 << 12) -+#define CNFG_OP_RESET (5 << 12) -+#define CNFG_OP_CUST (6 << 12) -+ -+#define MTKSDG1_NFI_PAGEFMT (0x04) -+#define PAGEFMT_FDM_ECC_SHIFT (12) -+#define PAGEFMT_FDM_SHIFT (8) -+#define PAGEFMT_SPARE_16 (0) -+#define PAGEFMT_SPARE_32 (4) -+#define PAGEFMT_SPARE_SHIFT (4) -+#define PAGEFMT_SEC_SEL_512 BIT(2) -+#define PAGEFMT_512_2K (0) -+#define PAGEFMT_2K_4K (1) -+#define PAGEFMT_4K_8K (2) -+ -+/* NFI control */ -+#define MTKSDG1_NFI_CON (0x08) -+#define CON_FIFO_FLUSH BIT(0) -+#define CON_NFI_RST BIT(1) -+#define CON_SRD BIT(4) /* single read */ -+#define CON_BRD BIT(8) /* burst read */ -+#define CON_BWR BIT(9) /* burst write */ -+#define CON_SEC_SHIFT (12) -+ -+/* Timming control register */ -+#define MTKSDG1_NFI_ACCCON (0x0C) -+ -+#define MTKSDG1_NFI_INTR_EN (0x10) -+#define INTR_RD_DONE_EN BIT(0) -+#define INTR_WR_DONE_EN BIT(1) -+#define INTR_RST_DONE_EN BIT(2) -+#define INTR_ERS_DONE_EN BIT(3) -+#define INTR_BUSY_RT_EN BIT(4) -+#define INTR_AHB_DONE_EN BIT(6) -+ -+#define MTKSDG1_NFI_INTR_STA (0x14) -+ -+#define MTKSDG1_NFI_CMD (0x20) -+ -+#define MTKSDG1_NFI_ADDRNOB (0x30) -+#define ADDR_ROW_NOB_SHIFT (4) -+ -+#define MTKSDG1_NFI_COLADDR (0x34) -+#define MTKSDG1_NFI_ROWADDR (0x38) -+#define MTKSDG1_NFI_STRDATA (0x40) -+#define MTKSDG1_NFI_CNRNB (0x44) -+#define MTKSDG1_NFI_DATAW (0x50) -+#define MTKSDG1_NFI_DATAR (0x54) -+#define MTKSDG1_NFI_PIO_DIRDY (0x58) -+#define PIO_DI_RDY (0x01) -+ -+/* NFI state*/ -+#define MTKSDG1_NFI_STA (0x60) -+#define STA_CMD BIT(0) -+#define STA_ADDR BIT(1) -+#define STA_DATAR BIT(2) -+#define STA_DATAW BIT(3) -+#define STA_EMP_PAGE BIT(12) -+ -+#define MTKSDG1_NFI_FIFOSTA (0x64) -+ -+#define MTKSDG1_NFI_ADDRCNTR (0x70) -+#define CNTR_MASK GENMASK(16, 12) -+ -+#define MTKSDG1_NFI_STRADDR (0x80) -+#define MTKSDG1_NFI_BYTELEN (0x84) -+#define MTKSDG1_NFI_CSEL (0x90) -+#define MTKSDG1_NFI_IOCON (0x94) -+ -+/* FDM data for sector: FDM0[L,H] - FDMF[L,H] */ -+#define MTKSDG1_NFI_FDM_MAX_SEC (0x10) -+#define MTKSDG1_NFI_FDM_REG_SIZE (8) -+#define MTKSDG1_NFI_FDM0L (0xA0) -+#define MTKSDG1_NFI_FDM0M (0xA4) -+ -+ -+#define MTKSDG1_NFI_FIFODATA0 (0x190) -+#define MTKSDG1_NFI_DEBUG_CON1 (0x220) -+#define MTKSDG1_NFI_MASTER_STA (0x224) -+#define MASTER_STA_MASK (0x0FFF) -+ -+#define MTKSDG1_NFI_RANDOM_CNFG (0x238) -+#define MTKSDG1_NFI_EMPTY_THRESH (0x23C) -+#define MTKSDG1_NFI_NAND_TYPE (0x240) -+#define MTKSDG1_NFI_ACCCON1 (0x244) -+#define MTKSDG1_NFI_DELAY_CTRL (0x248) -+ -+#endif -+ --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0065-net-mediatek-watchdog_timeo-was-not-set.patch b/target/linux/mediatek/patches-4.4/0065-net-mediatek-watchdog_timeo-was-not-set.patch new file mode 100644 index 0000000000..0a7c61566f --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0065-net-mediatek-watchdog_timeo-was-not-set.patch @@ -0,0 +1,28 @@ +From 103d950e6201ab54a8b64402bb0b32a35831b028 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 30 Mar 2016 03:18:17 +0200 +Subject: [PATCH 65/78] net: mediatek: watchdog_timeo was not set + +The original commit failed to set watchdog_timeo. This patch sets +watchdog_timeo to HZ. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 7f2126b..7e6d2e2 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1645,6 +1645,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; + + SET_NETDEV_DEV(eth->netdev[id], eth->dev); ++ eth->netdev[id]->watchdog_timeo = HZ; + eth->netdev[id]->netdev_ops = &mtk_netdev_ops; + eth->netdev[id]->base_addr = (unsigned long)eth->base; + eth->netdev[id]->vlan_features = MTK_HW_FEATURES & +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0066-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch b/target/linux/mediatek/patches-4.4/0066-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch new file mode 100644 index 0000000000..fbb744440b --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0066-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch @@ -0,0 +1,30 @@ +From 1212704e8270f0e673e10a49960318ade0096cf9 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 22 Mar 2016 04:42:27 +0100 +Subject: [PATCH 66/78] net: mediatek: mtk_cal_txd_req() returns bad value + +The code used to also support the PDMA engine, which had 2 packet pointers +per descriptor. Because of this we have to divide the result by 2 and round +it up. This is no longer needed as the code only supports QDMA. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 7e6d2e2..4d8d0a3 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -681,7 +681,7 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb) + nfrags += skb_shinfo(skb)->nr_frags; + } + +- return DIV_ROUND_UP(nfrags, 2); ++ return nfrags; + } + + static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0066-net-next-mediatek-mtk_cal_txd_req-returns-bad-value.patch b/target/linux/mediatek/patches-4.4/0066-net-next-mediatek-mtk_cal_txd_req-returns-bad-value.patch deleted file mode 100644 index 28899c46da..0000000000 --- a/target/linux/mediatek/patches-4.4/0066-net-next-mediatek-mtk_cal_txd_req-returns-bad-value.patch +++ /dev/null @@ -1,31 +0,0 @@ -From a160c7846e1f81b5cd6c5d0fbe5c1f8757e8884b Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Tue, 22 Mar 2016 04:42:27 +0100 -Subject: [PATCH 66/66] net-next: mediatek: mtk_cal_txd_req() returns bad - value - -The code used to also support the PDMA engine, which had 2 packet pointers -per descriptor. Because of this we have to divide the result by 2 and round -it up. This is no longer needed as the code only supports QDMA. - -Signed-off-by: John Crispin ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -index dd7f6e3..da9968ae 100644 ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -693,7 +693,7 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb) - nfrags += skb_shinfo(skb)->nr_frags; - } - -- return DIV_ROUND_UP(nfrags, 2); -+ return nfrags; - } - - static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) --- -1.7.10.4 - diff --git a/target/linux/mediatek/patches-4.4/0067-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch b/target/linux/mediatek/patches-4.4/0067-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch new file mode 100644 index 0000000000..5f02dd5820 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0067-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch @@ -0,0 +1,45 @@ +From 429b5becfb1e4aacf392c4b246a17b83faad3072 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 29 Mar 2016 14:32:07 +0200 +Subject: [PATCH 67/78] net: mediatek: update the IRQ part of the binding + document + +The current binding document only describes a single interrupt. Update the +document by adding the 2 other interrupts. + +The driver currently only uses a single interrupt. The HW is however able +to using IRQ grouping to split TX and RX onto separate GIC irqs. + +Signed-off-by: John Crispin + Acked-by: Rob Herring +--- + Documentation/devicetree/bindings/net/mediatek-net.txt | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt +index 5ca7929..2f142be 100644 +--- a/Documentation/devicetree/bindings/net/mediatek-net.txt ++++ b/Documentation/devicetree/bindings/net/mediatek-net.txt +@@ -9,7 +9,7 @@ have dual GMAC each represented by a child node.. + Required properties: + - compatible: Should be "mediatek,mt7623-eth" + - reg: Address and length of the register set for the device +-- interrupts: Should contain the frame engines interrupt ++- interrupts: Should contain the three frame engines interrupts + - clocks: the clock used by the core + - clock-names: the names of the clock listed in the clocks property. These are + "ethif", "esw", "gp2", "gp1" +@@ -42,7 +42,9 @@ eth: ethernet@1b100000 { + <ðsys CLK_ETHSYS_GP2>, + <ðsys CLK_ETHSYS_GP1>; + clock-names = "ethif", "esw", "gp2", "gp1"; +- interrupts = ; ++ interrupts = ; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + resets = <ðsys MT2701_ETHSYS_ETH_RST>; + reset-names = "eth"; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-superflous-reset-call.patch b/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-superflous-reset-call.patch new file mode 100644 index 0000000000..2f940d34fc --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-superflous-reset-call.patch @@ -0,0 +1,31 @@ +From 3c8781211140cc23750544a52b7310edb3b57f00 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 25 Mar 2016 04:24:27 +0100 +Subject: [PATCH 68/78] net: mediatek: remove superflous reset call + +HW reset is triggered int he mtk_hw_init() function. There is no need to +reset the core during probe. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 4d8d0a3..293ea59 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1679,10 +1679,6 @@ static int mtk_probe(struct platform_device *pdev) + struct mtk_eth *eth; + int err; + +- err = device_reset(&pdev->dev); +- if (err) +- return err; +- + match = of_match_device(of_mtk_match, &pdev->dev); + soc = (struct mtk_soc_data *)match->data; + +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0069-net-mediatek-fix-stop-and-wakeup-of-queue.patch b/target/linux/mediatek/patches-4.4/0069-net-mediatek-fix-stop-and-wakeup-of-queue.patch new file mode 100644 index 0000000000..170266227c --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0069-net-mediatek-fix-stop-and-wakeup-of-queue.patch @@ -0,0 +1,89 @@ +From 6f8bfdfe2984467177d2a88982517659ec09ab5d Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 29 Mar 2016 16:41:07 +0200 +Subject: [PATCH 69/78] net: mediatek: fix stop and wakeup of queue + +The driver supports 2 MACs. Both run on the same DMA ring. If we go +above/below the TX rings thershold value, we always need to wake/stop +the queu of both devices. Not doing to can cause TX stalls and packet +drops on one of the devices. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++-------- + 1 file changed, 27 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 293ea59..04bdb9d 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -684,6 +684,28 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb) + return nfrags; + } + ++static void mtk_wake_queue(struct mtk_eth *eth) ++{ ++ int i; ++ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ netif_wake_queue(eth->netdev[i]); ++ } ++} ++ ++static void mtk_stop_queue(struct mtk_eth *eth) ++{ ++ int i; ++ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ netif_stop_queue(eth->netdev[i]); ++ } ++} ++ + static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); +@@ -695,7 +717,7 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + + tx_num = mtk_cal_txd_req(skb); + if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { +- netif_stop_queue(dev); ++ mtk_stop_queue(eth); + netif_err(eth, tx_queued, dev, + "Tx Ring full when queue awake!\n"); + return NETDEV_TX_BUSY; +@@ -720,10 +742,10 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + goto drop; + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) { +- netif_stop_queue(dev); ++ mtk_stop_queue(eth); + if (unlikely(atomic_read(&ring->free_count) > + ring->thresh)) +- netif_wake_queue(dev); ++ mtk_wake_queue(eth); + } + + return NETDEV_TX_OK; +@@ -897,13 +919,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) + if (!total) + return 0; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i] || +- unlikely(!netif_queue_stopped(eth->netdev[i]))) +- continue; +- if (atomic_read(&ring->free_count) > ring->thresh) +- netif_wake_queue(eth->netdev[i]); +- } ++ if (atomic_read(&ring->free_count) > ring->thresh) ++ mtk_wake_queue(eth); + + return total; + } +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0070-net-mediatek-fix-mtk_pending_work.patch b/target/linux/mediatek/patches-4.4/0070-net-mediatek-fix-mtk_pending_work.patch new file mode 100644 index 0000000000..27f282b393 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0070-net-mediatek-fix-mtk_pending_work.patch @@ -0,0 +1,63 @@ +From a2dfb33c8a0dc03fe2ec2121490df2b9352febef Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 29 Mar 2016 17:00:47 +0200 +Subject: [PATCH 70/78] net: mediatek: fix mtk_pending_work + +The driver supports 2 MACs. Both run on the same DMA ring. If we hit a TX +timeout we need to stop both netdevs before retarting them again. If we +dont do thsi, mtk_stop() wont shutdown DMA and the consecutive call to +mtk_open() wont restart DMA and enable IRQs. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 04bdb9d..26eeb1a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1430,19 +1430,31 @@ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + + static void mtk_pending_work(struct work_struct *work) + { +- struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work); +- struct mtk_eth *eth = mac->hw; +- struct net_device *dev = eth->netdev[mac->id]; +- int err; ++ struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work); ++ int err, i; ++ unsigned long restart = 0; + + rtnl_lock(); +- mtk_stop(dev); + +- err = mtk_open(dev); +- if (err) { +- netif_alert(eth, ifup, dev, ++ /* stop all devices to make sure that dma is properly shut down */ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!netif_oper_up(eth->netdev[i])) ++ continue; ++ mtk_stop(eth->netdev[i]); ++ __set_bit(i, &restart); ++ } ++ ++ ++ /* restart DMA and enable IRQs */ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!test_bit(i, &restart)) ++ continue; ++ err = mtk_open(eth->netdev[i]); ++ if (err) { ++ netif_alert(eth, ifup, eth->netdev[i], + "Driver up/down cycle failed, closing device.\n"); +- dev_close(dev); ++ dev_close(eth->netdev[i]); ++ } + } + rtnl_unlock(); + } +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0071-net-mediatek-fix-TX-locking.patch b/target/linux/mediatek/patches-4.4/0071-net-mediatek-fix-TX-locking.patch new file mode 100644 index 0000000000..011fad2e61 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0071-net-mediatek-fix-TX-locking.patch @@ -0,0 +1,98 @@ +From b9df14f712866925856c0ffb2d899511c21e1b8a Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 29 Mar 2016 17:20:01 +0200 +Subject: [PATCH 71/78] net: mediatek: fix TX locking + +Inside the TX path there is a lock inside the tx_map function. This is +however too late. The patch moves the lock to the start of the xmit +function right before the free count check of the DMA ring happens. +If we do not do this, the code becomes racy leading to TX stalls and +dropped packets. This happens as there are 2 netdevs running on the +same physical DMA ring. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 26eeb1a..67b18f9 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -536,7 +536,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + struct mtk_eth *eth = mac->hw; + struct mtk_tx_dma *itxd, *txd; + struct mtk_tx_buf *tx_buf; +- unsigned long flags; + dma_addr_t mapped_addr; + unsigned int nr_frags; + int i, n_desc = 1; +@@ -568,11 +567,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + if (unlikely(dma_mapping_error(&dev->dev, mapped_addr))) + return -ENOMEM; + +- /* normally we can rely on the stack not calling this more than once, +- * however we have 2 queues running ont he same ring so we need to lock +- * the ring access +- */ +- spin_lock_irqsave(ð->page_lock, flags); + WRITE_ONCE(itxd->txd1, mapped_addr); + tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); +@@ -632,8 +626,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- spin_unlock_irqrestore(ð->page_lock, flags); +- + netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + +@@ -661,8 +653,6 @@ err_dma: + itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); + } while (itxd != txd); + +- spin_unlock_irqrestore(ð->page_lock, flags); +- + return -ENOMEM; + } + +@@ -712,14 +702,22 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; ++ unsigned long flags; + bool gso = false; + int tx_num; + ++ /* normally we can rely on the stack not calling this more than once, ++ * however we have 2 queues running ont he same ring so we need to lock ++ * the ring access ++ */ ++ spin_lock_irqsave(ð->page_lock, flags); ++ + tx_num = mtk_cal_txd_req(skb); + if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { + mtk_stop_queue(eth); + netif_err(eth, tx_queued, dev, + "Tx Ring full when queue awake!\n"); ++ spin_unlock_irqrestore(ð->page_lock, flags); + return NETDEV_TX_BUSY; + } + +@@ -747,10 +745,12 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + ring->thresh)) + mtk_wake_queue(eth); + } ++ spin_unlock_irqrestore(ð->page_lock, flags); + + return NETDEV_TX_OK; + + drop: ++ spin_unlock_irqrestore(ð->page_lock, flags); + stats->tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0072-net-mediatek-move-the-pending_work-struct-to-the-dev.patch b/target/linux/mediatek/patches-4.4/0072-net-mediatek-move-the-pending_work-struct-to-the-dev.patch new file mode 100644 index 0000000000..1b9f221588 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0072-net-mediatek-move-the-pending_work-struct-to-the-dev.patch @@ -0,0 +1,109 @@ +From 147dab4408adcccf702f8c5143e9c6b91f746790 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 29 Mar 2016 17:24:24 +0200 +Subject: [PATCH 72/78] net: mediatek: move the pending_work struct to the + device generic struct + +The worker always touches both netdevs. It is ethernet core and not MAC +specific. We only need one worker, which belongs into the ethernets core struct. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 ++++------ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++-- + 2 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 67b18f9..bbcd607 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1193,7 +1193,7 @@ static void mtk_tx_timeout(struct net_device *dev) + eth->netdev[mac->id]->stats.tx_errors++; + netif_err(eth, tx_err, dev, + "transmit timed out\n"); +- schedule_work(&mac->pending_work); ++ schedule_work(ð->pending_work); + } + + static irqreturn_t mtk_handle_irq(int irq, void *_eth) +@@ -1438,7 +1438,7 @@ static void mtk_pending_work(struct work_struct *work) + + /* stop all devices to make sure that dma is properly shut down */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!netif_oper_up(eth->netdev[i])) ++ if (!eth->netdev[i]) + continue; + mtk_stop(eth->netdev[i]); + __set_bit(i, &restart); +@@ -1464,15 +1464,13 @@ static int mtk_cleanup(struct mtk_eth *eth) + int i; + + for (i = 0; i < MTK_MAC_COUNT; i++) { +- struct mtk_mac *mac = netdev_priv(eth->netdev[i]); +- + if (!eth->netdev[i]) + continue; + + unregister_netdev(eth->netdev[i]); + free_netdev(eth->netdev[i]); +- cancel_work_sync(&mac->pending_work); + } ++ cancel_work_sync(ð->pending_work); + + return 0; + } +@@ -1660,7 +1658,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->id = id; + mac->hw = eth; + mac->of_node = np; +- INIT_WORK(&mac->pending_work, mtk_pending_work); + + mac->hw_stats = devm_kzalloc(eth->dev, + sizeof(*mac->hw_stats), +@@ -1762,6 +1759,7 @@ static int mtk_probe(struct platform_device *pdev) + + eth->dev = &pdev->dev; + eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); ++ INIT_WORK(ð->pending_work, mtk_pending_work); + + err = mtk_hw_init(eth); + if (err) +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 48a5292..eed626d 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -363,6 +363,7 @@ struct mtk_rx_ring { + * @clk_gp1: The gmac1 clock + * @clk_gp2: The gmac2 clock + * @mii_bus: If there is a bus we need to create an instance for it ++ * @pending_work: The workqueue used to reset the dma ring + */ + + struct mtk_eth { +@@ -389,6 +390,7 @@ struct mtk_eth { + struct clk *clk_gp1; + struct clk *clk_gp2; + struct mii_bus *mii_bus; ++ struct work_struct pending_work; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +@@ -398,7 +400,6 @@ struct mtk_eth { + * @hw: Backpointer to our main datastruture + * @hw_stats: Packet statistics counter + * @phy_dev: The attached PHY if available +- * @pending_work: The workqueue used to reset the dma ring + */ + struct mtk_mac { + int id; +@@ -406,7 +407,6 @@ struct mtk_mac { + struct mtk_eth *hw; + struct mtk_hw_stats *hw_stats; + struct phy_device *phy_dev; +- struct work_struct pending_work; + }; + + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0073-net-next-mediatek-add-support-for-IRQ-grouping.patch b/target/linux/mediatek/patches-4.4/0073-net-next-mediatek-add-support-for-IRQ-grouping.patch new file mode 100644 index 0000000000..6457deba0a --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0073-net-next-mediatek-add-support-for-IRQ-grouping.patch @@ -0,0 +1,314 @@ +From e301da64a9fd2ebc24d4c9b2d184681ec833fd72 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 23 Mar 2016 18:31:48 +0100 +Subject: [PATCH 73/78] net-next: mediatek: add support for IRQ grouping + +The ethernet core has 3 IRQs. using the IRQ grouping registers we are able +to separate TX and RX IRQs, which allows us to service them on separate +cores. This patch splits the irq handler into 2 separate functiosn, one for +TX and another for RX. The TX housekeeping is split out of the NAPI handler. +Instead we use a tasklet to handle housekeeping. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 115 +++++++++++++++++---------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 12 ++- + 2 files changed, 86 insertions(+), 41 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index bbcd607..2097ae1 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -757,7 +757,7 @@ drop: + } + + static int mtk_poll_rx(struct napi_struct *napi, int budget, +- struct mtk_eth *eth, u32 rx_intr) ++ struct mtk_eth *eth) + { + struct mtk_rx_ring *ring = ð->rx_ring; + int idx = ring->calc_idx; +@@ -843,12 +843,12 @@ release_desc: + } + + if (done < budget) +- mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS); ++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS); + + return done; + } + +-static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) ++static int mtk_poll_tx(struct mtk_eth *eth, int budget) + { + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma *desc; +@@ -911,9 +911,7 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) + } + + /* read hw index again make sure no new tx packet */ +- if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR)) +- *tx_again = true; +- else ++ if (cpu == dma && cpu == mtk_r32(eth, MTK_QTX_DRX_PTR)) + mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS); + + if (!total) +@@ -925,27 +923,27 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again) + return total; + } + ++static void mtk_clean_tx_tasklet(unsigned long arg) ++{ ++ struct mtk_eth *eth = (struct mtk_eth *)arg; ++ ++ if (mtk_poll_tx(eth, MTK_NAPI_WEIGHT) > 0) ++ tasklet_schedule(ð->tx_clean_tasklet); ++ else ++ mtk_irq_enable(eth, MTK_TX_DONE_INT); ++} ++ + static int mtk_poll(struct napi_struct *napi, int budget) + { + struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); +- u32 status, status2, mask, tx_intr, rx_intr, status_intr; +- int tx_done, rx_done; +- bool tx_again = false; ++ u32 status, status2, mask, status_intr; ++ int rx_done = 0; + + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); + status2 = mtk_r32(eth, MTK_INT_STATUS2); +- tx_intr = MTK_TX_DONE_INT; +- rx_intr = MTK_RX_DONE_INT; + status_intr = (MTK_GDM1_AF | MTK_GDM2_AF); +- tx_done = 0; +- rx_done = 0; +- tx_again = 0; + +- if (status & tx_intr) +- tx_done = mtk_poll_tx(eth, budget, &tx_again); +- +- if (status & rx_intr) +- rx_done = mtk_poll_rx(napi, budget, eth, rx_intr); ++ rx_done = mtk_poll_rx(napi, budget, eth); + + if (unlikely(status2 & status_intr)) { + mtk_stats_update(eth); +@@ -954,20 +952,20 @@ static int mtk_poll(struct napi_struct *napi, int budget) + + if (unlikely(netif_msg_intr(eth))) { + mask = mtk_r32(eth, MTK_QDMA_INT_MASK); +- netdev_info(eth->netdev[0], +- "done tx %d, rx %d, intr 0x%08x/0x%x\n", +- tx_done, rx_done, status, mask); ++ dev_info(eth->dev, ++ "done rx %d, intr 0x%08x/0x%x\n", ++ rx_done, status, mask); + } + +- if (tx_again || rx_done == budget) ++ if (rx_done == budget) + return budget; + + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); +- if (status & (tx_intr | rx_intr)) ++ if (status & MTK_RX_DONE_INT) + return budget; + + napi_complete(napi); +- mtk_irq_enable(eth, tx_intr | rx_intr); ++ mtk_irq_enable(eth, MTK_RX_DONE_INT); + + return rx_done; + } +@@ -1196,22 +1194,43 @@ static void mtk_tx_timeout(struct net_device *dev) + schedule_work(ð->pending_work); + } + +-static irqreturn_t mtk_handle_irq(int irq, void *_eth) ++static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth) + { + struct mtk_eth *eth = _eth; + u32 status; + + status = mtk_r32(eth, MTK_QMTK_INT_STATUS); ++ status &= ~MTK_TX_DONE_INT; ++ + if (unlikely(!status)) + return IRQ_NONE; + +- if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) { ++ if (status & MTK_RX_DONE_INT) { + if (likely(napi_schedule_prep(ð->rx_napi))) + __napi_schedule(ð->rx_napi); +- } else { +- mtk_w32(eth, status, MTK_QMTK_INT_STATUS); ++ mtk_irq_disable(eth, MTK_RX_DONE_INT); + } +- mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT)); ++ mtk_w32(eth, status, MTK_QMTK_INT_STATUS); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth) ++{ ++ struct mtk_eth *eth = _eth; ++ u32 status; ++ ++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS); ++ status &= ~MTK_RX_DONE_INT; ++ ++ if (unlikely(!status)) ++ return IRQ_NONE; ++ ++ if (status & MTK_TX_DONE_INT) { ++ tasklet_schedule(ð->tx_clean_tasklet); ++ mtk_irq_disable(eth, MTK_TX_DONE_INT); ++ } ++ mtk_w32(eth, status, MTK_QMTK_INT_STATUS); + + return IRQ_HANDLED; + } +@@ -1224,7 +1243,7 @@ static void mtk_poll_controller(struct net_device *dev) + u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT; + + mtk_irq_disable(eth, int_mask); +- mtk_handle_irq(dev->irq, dev); ++ mtk_handle_irq(dev->irq[0], dev); + mtk_irq_enable(eth, int_mask); + } + #endif +@@ -1345,7 +1364,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + +- err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0, ++ err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, ++ dev_name(eth->dev), eth); ++ if (err) ++ return err; ++ err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, + dev_name(eth->dev), eth); + if (err) + return err; +@@ -1361,7 +1384,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) + mtk_w32(eth, 0, MTK_RST_GL); + + /* FE int grouping */ +- mtk_w32(eth, 0, MTK_FE_INT_GRP); ++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); ++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); ++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); ++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); ++ mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + + for (i = 0; i < 2; i++) { + u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); +@@ -1409,7 +1436,9 @@ static void mtk_uninit(struct net_device *dev) + phy_disconnect(mac->phy_dev); + mtk_mdio_cleanup(eth); + mtk_irq_disable(eth, ~0); +- free_irq(dev->irq, dev); ++ free_irq(eth->irq[0], dev); ++ free_irq(eth->irq[1], dev); ++ free_irq(eth->irq[2], dev); + } + + static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +@@ -1684,10 +1713,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + dev_err(eth->dev, "error bringing up device\n"); + goto free_netdev; + } +- eth->netdev[id]->irq = eth->irq; ++ eth->netdev[id]->irq = eth->irq[0]; + netif_info(eth, probe, eth->netdev[id], + "mediatek frame engine at 0x%08lx, irq %d\n", +- eth->netdev[id]->base_addr, eth->netdev[id]->irq); ++ eth->netdev[id]->base_addr, eth->irq[0]); + + return 0; + +@@ -1704,6 +1733,7 @@ static int mtk_probe(struct platform_device *pdev) + struct mtk_soc_data *soc; + struct mtk_eth *eth; + int err; ++ int i; + + match = of_match_device(of_mtk_match, &pdev->dev); + soc = (struct mtk_soc_data *)match->data; +@@ -1738,10 +1768,12 @@ static int mtk_probe(struct platform_device *pdev) + return PTR_ERR(eth->rstc); + } + +- eth->irq = platform_get_irq(pdev, 0); +- if (eth->irq < 0) { +- dev_err(&pdev->dev, "no IRQ resource found\n"); +- return -ENXIO; ++ for (i = 0; i < 3; i++) { ++ eth->irq[i] = platform_get_irq(pdev, i); ++ if (eth->irq[i] < 0) { ++ dev_err(&pdev->dev, "no IRQ%d resource found\n", i); ++ return -ENXIO; ++ } + } + + eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif"); +@@ -1785,6 +1817,9 @@ static int mtk_probe(struct platform_device *pdev) + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_poll, + MTK_NAPI_WEIGHT); + ++ tasklet_init(ð->tx_clean_tasklet, ++ mtk_clean_tx_tasklet, (unsigned long)eth); ++ + platform_set_drvdata(pdev, eth); + + return 0; +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index eed626d..4cfb40c 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -68,6 +68,10 @@ + /* Unicast Filter MAC Address Register - High */ + #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) + ++/* PDMA Interrupt grouping registers */ ++#define MTK_PDMA_INT_GRP1 0xa50 ++#define MTK_PDMA_INT_GRP2 0xa54 ++ + /* QDMA TX Queue Configuration Registers */ + #define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) + #define QDMA_RES_THRES 4 +@@ -124,6 +128,11 @@ + #define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ + MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) + ++/* QDMA Interrupt grouping registers */ ++#define MTK_QDMA_INT_GRP1 0x1a20 ++#define MTK_QDMA_INT_GRP2 0x1a24 ++#define MTK_RLS_DONE_INT BIT(0) ++ + /* QDMA Interrupt Status Register */ + #define MTK_QDMA_INT_MASK 0x1A1C + +@@ -374,7 +383,7 @@ struct mtk_eth { + struct net_device dummy_dev; + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; +- int irq; ++ int irq[3]; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +@@ -391,6 +400,7 @@ struct mtk_eth { + struct clk *clk_gp2; + struct mii_bus *mii_bus; + struct work_struct pending_work; ++ struct tasklet_struct tx_clean_tasklet; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0074-net-mediatek-out-of-tree-fixes.patch b/target/linux/mediatek/patches-4.4/0074-net-mediatek-out-of-tree-fixes.patch new file mode 100644 index 0000000000..878def40a9 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0074-net-mediatek-out-of-tree-fixes.patch @@ -0,0 +1,2600 @@ +From 42fa01d00a7d14b4db1ff1e5176469d349e03d8a Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Mon, 21 Mar 2016 16:36:22 +0100 +Subject: [PATCH 74/78] net: mediatek: out of tree fixes + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/mt7623-evb.dts | 1 - + arch/arm/boot/dts/mt7623.dtsi | 40 +- + drivers/net/ethernet/mediatek/Makefile | 2 +- + drivers/net/ethernet/mediatek/gsw_mt7620.h | 250 +++++++ + drivers/net/ethernet/mediatek/gsw_mt7623.c | 1070 +++++++++++++++++++++++++++ + drivers/net/ethernet/mediatek/mt7530.c | 808 ++++++++++++++++++++ + drivers/net/ethernet/mediatek/mt7530.h | 20 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 107 ++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 + + 9 files changed, 2230 insertions(+), 73 deletions(-) + create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h + create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c + create mode 100644 drivers/net/ethernet/mediatek/mt7530.c + create mode 100644 drivers/net/ethernet/mediatek/mt7530.h + +diff --git a/arch/arm/boot/dts/mt7623-evb.dts b/arch/arm/boot/dts/mt7623-evb.dts +index 5e9381d..bc2b3f1 100644 +--- a/arch/arm/boot/dts/mt7623-evb.dts ++++ b/arch/arm/boot/dts/mt7623-evb.dts +@@ -425,7 +425,6 @@ + &usb1 { + vusb33-supply = <&mt6323_vusb_reg>; + vbus-supply = <&usb_p1_vbus>; +-// mediatek,wakeup-src = <1>; + status = "okay"; + }; + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index c8c802d..f405ec7 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -453,25 +453,32 @@ + }; + + ethsys: syscon@1b000000 { +- #address-cells = <1>; +- #size-cells = <1>; + compatible = "mediatek,mt2701-ethsys", "syscon"; + reg = <0 0x1b000000 0 0x1000>; ++ #reset-cells = <1>; + #clock-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7623-eth"; +- reg = <0 0x1b100000 0 0x10000>; ++ reg = <0 0x1b100000 0 0x20000>; + +- clocks = <&topckgen CLK_TOP_ETHIF_SEL>; +- clock-names = "ethif"; ++ clocks = <&topckgen CLK_TOP_ETHIF_SEL>, ++ <ðsys CLK_ETHSYS_ESW>, ++ <ðsys CLK_ETHSYS_GP2>, ++ <ðsys CLK_ETHSYS_GP1>; ++ clock-names = "ethif", "esw", "gp2", "gp1"; + interrupts = ; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + ++ resets = <ðsys 6>; ++ reset-names = "eth"; ++ + mediatek,ethsys = <ðsys>; ++ mediatek,pctl = <&syscfg_pctl_a>; ++ + mediatek,switch = <&gsw>; + + #address-cells = <1>; +@@ -482,7 +489,7 @@ + gmac1: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; +- ++ + status = "disabled"; + }; + +@@ -490,6 +497,7 @@ + compatible = "mediatek,eth-mac"; + reg = <1>; + ++ phy-handle = <&phy5>; + status = "disabled"; + }; + +@@ -497,6 +505,16 @@ + #address-cells = <1>; + #size-cells = <0>; + ++ phy4: ethernet-phy@4 { ++ reg = <4>; ++ phy-mode = "rgmii"; ++ }; ++ ++ phy5: ethernet-phy@5 { ++ reg = <5>; ++ phy-mode = "rgmii"; ++ }; ++ + phy1f: ethernet-phy@1f { + reg = <0x1f>; + phy-mode = "rgmii"; +@@ -506,14 +524,12 @@ + + gsw: switch@1b100000 { + compatible = "mediatek,mt7623-gsw"; +- reg = <0 0x1b110000 0 0x300000>; + interrupt-parent = <&pio>; + interrupts = <168 IRQ_TYPE_EDGE_RISING>; +- clocks = <&apmixedsys CLK_APMIXED_TRGPLL>, +- <ðsys CLK_ETHSYS_ESW>, +- <ðsys CLK_ETHSYS_GP2>, +- <ðsys CLK_ETHSYS_GP1>; +- clock-names = "trgpll", "esw", "gp2", "gp1"; ++ resets = <ðsys 2>; ++ reset-names = "eth"; ++ clocks = <&apmixedsys CLK_APMIXED_TRGPLL>; ++ clock-names = "trgpll"; + mt7530-supply = <&mt6323_vpa_reg>; + mediatek,pctl-regmap = <&syscfg_pctl_a>; + mediatek,ethsys = <ðsys>; +diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile +index aa3f1c8..82001c4 100644 +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -2,4 +2,4 @@ + # Makefile for the Mediatek SoCs built-in ethernet macs + # + +-obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o ++obj-$(CONFIG_NET_MEDIATEK_SOC) += mt7530.o gsw_mt7623.o mtk_eth_soc.o +diff --git a/drivers/net/ethernet/mediatek/gsw_mt7620.h b/drivers/net/ethernet/mediatek/gsw_mt7620.h +new file mode 100644 +index 0000000..7013803 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h +@@ -0,0 +1,250 @@ ++/* 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) 2009-2016 John Crispin ++ * Copyright (C) 2009-2016 Felix Fietkau ++ * Copyright (C) 2013-2016 Michael Lee ++ */ ++ ++#ifndef _RALINK_GSW_MT7620_H__ ++#define _RALINK_GSW_MT7620_H__ ++ ++#define GSW_REG_PHY_TIMEOUT (5 * HZ) ++ ++#define MT7620_GSW_REG_PIAC 0x0004 ++ ++#define GSW_NUM_VLANS 16 ++#define GSW_NUM_VIDS 4096 ++#define GSW_NUM_PORTS 7 ++#define GSW_PORT6 6 ++ ++#define GSW_MDIO_ACCESS BIT(31) ++#define GSW_MDIO_READ BIT(19) ++#define GSW_MDIO_WRITE BIT(18) ++#define GSW_MDIO_START BIT(16) ++#define GSW_MDIO_ADDR_SHIFT 20 ++#define GSW_MDIO_REG_SHIFT 25 ++ ++#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100)) ++#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100)) ++#define GSW_REG_SMACCR0 0x3fE4 ++#define GSW_REG_SMACCR1 0x3fE8 ++#define GSW_REG_CKGCR 0x3ff0 ++ ++#define GSW_REG_IMR 0x7008 ++#define GSW_REG_ISR 0x700c ++#define GSW_REG_GPC1 0x7014 ++ ++#define SYSC_REG_CHIP_REV_ID 0x0c ++#define SYSC_REG_CFG 0x10 ++#define SYSC_REG_CFG1 0x14 ++#define RST_CTRL_MCM BIT(2) ++#define SYSC_PAD_RGMII2_MDIO 0x58 ++#define SYSC_GPIO_MODE 0x60 ++ ++#define PORT_IRQ_ST_CHG 0x7f ++ ++#define MT7621_ESW_PHY_POLLING 0x0000 ++#define MT7620_ESW_PHY_POLLING 0x7000 ++ ++#define PMCR_IPG BIT(18) ++#define PMCR_MAC_MODE BIT(16) ++#define PMCR_FORCE BIT(15) ++#define PMCR_TX_EN BIT(14) ++#define PMCR_RX_EN BIT(13) ++#define PMCR_BACKOFF BIT(9) ++#define PMCR_BACKPRES BIT(8) ++#define PMCR_RX_FC BIT(5) ++#define PMCR_TX_FC BIT(4) ++#define PMCR_SPEED(_x) (_x << 2) ++#define PMCR_DUPLEX BIT(1) ++#define PMCR_LINK BIT(0) ++ ++#define PHY_AN_EN BIT(31) ++#define PHY_PRE_EN BIT(30) ++#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24) ++ ++/* ethernet subsystem config register */ ++#define ETHSYS_SYSCFG0 0x14 ++/* ethernet subsystem clock register */ ++#define ETHSYS_CLKCFG0 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++/* p5 RGMII wrapper TX clock control register */ ++#define MT7530_P5RGMIITXCR 0x7b04 ++/* p5 RGMII wrapper RX clock control register */ ++#define MT7530_P5RGMIIRXCR 0x7b00 ++/* TRGMII TDX ODT registers */ ++#define MT7530_TRGMII_TD0_ODT 0x7a54 ++#define MT7530_TRGMII_TD1_ODT 0x7a5c ++#define MT7530_TRGMII_TD2_ODT 0x7a64 ++#define MT7530_TRGMII_TD3_ODT 0x7a6c ++#define MT7530_TRGMII_TD4_ODT 0x7a74 ++#define MT7530_TRGMII_TD5_ODT 0x7a7c ++/* TRGMII TCK ctrl register */ ++#define MT7530_TRGMII_TCK_CTRL 0x7a78 ++/* TRGMII Tx ctrl register */ ++#define MT7530_TRGMII_TXCTRL 0x7a40 ++/* port 6 extended control register */ ++#define MT7530_P6ECR 0x7830 ++/* IO driver control register */ ++#define MT7530_IO_DRV_CR 0x7810 ++/* top signal control register */ ++#define MT7530_TOP_SIG_CTRL 0x7808 ++/* modified hwtrap register */ ++#define MT7530_MHWTRAP 0x7804 ++/* hwtrap status register */ ++#define MT7530_HWTRAP 0x7800 ++/* status interrupt register */ ++#define MT7530_SYS_INT_STS 0x700c ++/* system nterrupt register */ ++#define MT7530_SYS_INT_EN 0x7008 ++/* system control register */ ++#define MT7530_SYS_CTRL 0x7000 ++/* port MAC status register */ ++#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100)) ++/* port MAC control register */ ++#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100)) ++ ++#define MT7621_XTAL_SHIFT 6 ++#define MT7621_XTAL_MASK 0x7 ++#define MT7621_XTAL_25 6 ++#define MT7621_XTAL_40 3 ++#define MT7621_MDIO_DRV_MASK (3 << 4) ++#define MT7621_GE1_MODE_MASK (3 << 12) ++ ++#define TRGMII_TXCTRL_TXC_INV BIT(30) ++#define P6ECR_INTF_MODE_RGMII BIT(1) ++#define P5RGMIIRXCR_C_ALIGN BIT(8) ++#define P5RGMIIRXCR_DELAY_2 BIT(1) ++#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2)) ++ ++/* TOP_SIG_CTRL bits */ ++#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) ++ ++/* MHWTRAP bits */ ++#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) ++ ++/* HWTRAP bits */ ++#define HWTRAP_XTAL_SHIFT 9 ++#define HWTRAP_XTAL_MASK 0x3 ++ ++/* SYS_CTRL bits */ ++#define SYS_CTRL_SW_RST BIT(1) ++#define SYS_CTRL_REG_RST BIT(0) ++ ++/* PMCR bits */ ++#define PMCR_IFG_XMIT_96 BIT(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_BACK_PRES_EN BIT(9) ++#define PMCR_BACKOFF_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_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \ ++ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \ ++ PMCR_BACK_PRES_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) ++ ++/* TRGMII control registers */ ++#define GSW_INTF_MODE 0x390 ++#define GSW_TRGMII_TD0_ODT 0x354 ++#define GSW_TRGMII_TD1_ODT 0x35c ++#define GSW_TRGMII_TD2_ODT 0x364 ++#define GSW_TRGMII_TD3_ODT 0x36c ++#define GSW_TRGMII_TXCTL_ODT 0x374 ++#define GSW_TRGMII_TCK_ODT 0x37c ++#define GSW_TRGMII_RCK_CTRL 0x300 ++ ++#define INTF_MODE_TRGMII BIT(1) ++#define TRGMII_RCK_CTRL_RX_RST BIT(31) ++ ++ ++/* possible XTAL speed */ ++#define MT7623_XTAL_40 0 ++#define MT7623_XTAL_20 1 ++#define MT7623_XTAL_25 3 ++ ++/* GPIO port control registers */ ++#define GPIO_OD33_CTRL8 0x4c0 ++#define GPIO_BIAS_CTRL 0xed0 ++#define GPIO_DRV_SEL10 0xf00 ++ ++/* on MT7620 the functio of port 4 can be software configured */ ++enum { ++ PORT4_EPHY = 0, ++ PORT4_EXT, ++}; ++ ++/* struct mt7620_gsw - the structure that holds the SoC specific data ++ * @dev: The Device struct ++ * @base: The base address ++ * @piac_offset: The PIAC base may change depending on SoC ++ * @irq: The IRQ we are using ++ * @port4: The port4 mode on MT7620 ++ * @autopoll: Is MDIO autopolling enabled ++ * @ethsys: The ethsys register map ++ * @pctl: The pin control register map ++ * @clk_trgpll: The trgmii pll clock ++ */ ++struct mt7620_gsw { ++ struct mtk_eth *eth; ++ struct device *dev; ++ void __iomem *base; ++ u32 piac_offset; ++ int irq; ++ int port4; ++ unsigned long int autopoll; ++ ++ struct regmap *ethsys; ++ struct regmap *pctl; ++ ++ struct clk *clk_trgpll; ++ ++ int trgmii_force; ++}; ++ ++/* switch register I/O wrappers */ ++void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg); ++u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg); ++ ++/* the callback used by the driver core to bringup the switch */ ++int mtk_gsw_init(struct mtk_eth *eth); ++ ++/* MDIO access wrappers */ ++int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); ++int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); ++void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port); ++int mt7620_has_carrier(struct mtk_eth *eth); ++void mt7620_print_link_state(struct mtk_eth *eth, int port, int link, ++ int speed, int duplex); ++void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val); ++u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg); ++void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg); ++ ++u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, ++ u32 phy_register, u32 write_data); ++u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg); ++void mt7620_handle_carrier(struct mtk_eth *eth); ++ ++#endif +diff --git a/drivers/net/ethernet/mediatek/gsw_mt7623.c b/drivers/net/ethernet/mediatek/gsw_mt7623.c +new file mode 100644 +index 0000000..873a525 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c +@@ -0,0 +1,1070 @@ ++/* 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) 2009-2016 John Crispin ++ * Copyright (C) 2009-2016 Felix Fietkau ++ * Copyright (C) 2013-2016 Michael Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk_eth_soc.h" ++#include "gsw_mt7620.h" ++#include "mt7530.h" ++ ++#define ETHSYS_CLKCFG0 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val) ++{ ++ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); ++ _mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff); ++ _mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16); ++} ++ ++u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg) ++{ ++ u16 high, low; ++ ++ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); ++ low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf); ++ high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10); ++ ++ return (high << 16) | (low & 0xffff); ++} ++ ++void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg) ++{ ++ u32 val = mt7530_mdio_r32(gsw, reg); ++ ++ val &= mask; ++ val |= set; ++ mt7530_mdio_w32(gsw, reg, val); ++} ++ ++void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) ++{ ++ mtk_w32(gsw->eth, val, reg + 0x10000); ++} ++ ++u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) ++{ ++ return mtk_r32(gsw->eth, reg + 0x10000); ++} ++ ++void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg) ++{ ++ u32 val = mtk_switch_r32(gsw, reg); ++ ++ val &= mask; ++ val |= set; ++ ++ mtk_switch_w32(gsw, val, reg); ++} ++ ++int mt7623_gsw_config(struct mtk_eth *eth) ++{ ++ if (eth->mii_bus && eth->mii_bus->phy_map[0x1f]) ++ mt7530_probe(eth->dev, NULL, eth->mii_bus, 1); ++ ++ return 0; ++} ++ ++static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth) ++{ ++ struct mtk_eth *eth = (struct mtk_eth *)_eth; ++ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; ++ u32 reg, i; ++ ++ reg = mt7530_mdio_r32(gsw, 0x700c); ++ ++ for (i = 0; i < 5; i++) ++ if (reg & BIT(i)) { ++ unsigned int link; ++ ++ link = mt7530_mdio_r32(gsw, ++ 0x3008 + (i * 0x100)) & 0x1; ++ ++ if (link) ++ dev_info(gsw->dev, ++ "port %d link up\n", i); ++ else ++ dev_info(gsw->dev, ++ "port %d link down\n", i); ++ } ++ ++// mt7620_handle_carrier(eth); ++ mt7530_mdio_w32(gsw, 0x700c, 0x1f); ++ ++ return IRQ_HANDLED; ++} ++ ++static void wait_loop(struct mt7620_gsw *gsw) ++{ ++ int i; ++ int read_data; ++ ++ for (i = 0; i < 320; i = i + 1) ++ read_data = mtk_switch_r32(gsw, 0x610); ++} ++ ++static void trgmii_calibration_7623(struct mt7620_gsw *gsw) ++{ ++ ++ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; /* minumum delay for all correct */ ++ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; /* maximum delay for all correct */ ++ unsigned int final_tap[5]; ++ unsigned int rxc_step_size; ++ unsigned int rxd_step_size; ++ unsigned int read_data; ++ unsigned int tmp; ++ unsigned int rd_wd; ++ int i; ++ unsigned int err_cnt[5]; ++ unsigned int init_toggle_data; ++ unsigned int err_flag[5]; ++ unsigned int err_total_flag; ++ unsigned int training_word; ++ unsigned int rd_tap; ++ u32 val; ++ ++ u32 TRGMII_7623_base; ++ u32 TRGMII_7623_RD_0; ++ u32 TRGMII_RCK_CTRL; ++ ++ TRGMII_7623_base = 0x300; /* 0xFB110300 */ ++ TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10; ++ TRGMII_RCK_CTRL = TRGMII_7623_base; ++ rxd_step_size = 0x1; ++ rxc_step_size = 0x4; ++ init_toggle_data = 0x00000055; ++ training_word = 0x000000AC; ++ ++ /* RX clock gating in MT7623 */ ++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); ++ ++ /* Assert RX reset in MT7623 */ ++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00); ++ ++ /* Set TX OE edge in MT7623 */ ++ mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78); ++ ++ /* Disable RX clock gating in MT7623 */ ++ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); ++ ++ /* Release RX reset in MT7623 */ ++ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base); ++ ++ for (i = 0; i < 5; i++) ++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); ++ ++ pr_err("Enable Training Mode in MT7530\n"); ++ read_data = mt7530_mdio_r32(gsw, 0x7A40); ++ read_data |= 0xC0000000; ++ mt7530_mdio_w32(gsw, 0x7A40, read_data); /* Enable Training Mode in MT7530 */ ++ err_total_flag = 0; ++ pr_err("Adjust RXC delay in MT7623\n"); ++ read_data = 0x0; ++ while (err_total_flag == 0 && read_data != 0x68) { ++ pr_err("2nd Enable EDGE CHK in MT7623\n"); ++ /* Enable EDGE CHK in MT7623 */ ++ for (i = 0; i < 5; i++) ++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); ++ ++ wait_loop(gsw); ++ err_total_flag = 1; ++ for (i = 0; i < 5; i++) { ++ err_cnt[i] = ++ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8; ++ err_cnt[i] &= 0x0000000f; ++ rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16; ++ rd_wd &= 0x000000ff; ++ val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); ++ pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n", ++ err_cnt[i], rd_wd, val); ++ if (err_cnt[i] != 0) { ++ err_flag[i] = 1; ++ } else if (rd_wd != 0x55) { ++ err_flag[i] = 1; ++ } else { ++ err_flag[i] = 0; ++ } ++ err_total_flag = err_flag[i] & err_total_flag; ++ } ++ ++ pr_err("2nd Disable EDGE CHK in MT7623\n"); ++ /* Disable EDGE CHK in MT7623 */ ++ for (i = 0; i < 5; i++) ++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); ++ wait_loop(gsw); ++ pr_err("2nd Disable EDGE CHK in MT7623\n"); ++ /* Adjust RXC delay */ ++ /* RX clock gating in MT7623 */ ++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); ++ read_data = mtk_switch_r32(gsw, TRGMII_7623_base); ++ if (err_total_flag == 0) { ++ tmp = (read_data & 0x0000007f) + rxc_step_size; ++ pr_err(" RXC delay = %d\n", tmp); ++ read_data >>= 8; ++ read_data &= 0xffffff80; ++ read_data |= tmp; ++ read_data <<= 8; ++ read_data &= 0xffffff80; ++ read_data |= tmp; ++ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); ++ } else { ++ tmp = (read_data & 0x0000007f) + 16; ++ pr_err(" RXC delay = %d\n", tmp); ++ read_data >>= 8; ++ read_data &= 0xffffff80; ++ read_data |= tmp; ++ read_data <<= 8; ++ read_data &= 0xffffff80; ++ read_data |= tmp; ++ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); ++ } ++ read_data &= 0x000000ff; ++ ++ /* Disable RX clock gating in MT7623 */ ++ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); ++ for (i = 0; i < 5; i++) ++ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); ++ } ++ ++ /* Read RD_WD MT7623 */ ++ for (i = 0; i < 5; i++) { ++ rd_tap = 0; ++ while (err_flag[i] != 0 && rd_tap != 128) { ++ /* Enable EDGE CHK in MT7623 */ ++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); ++ wait_loop(gsw); ++ ++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); ++ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ ++ rd_wd = (read_data >> 16) & 0x000000ff; ++ if (err_cnt[i] != 0 || rd_wd != 0x55) { ++ err_flag[i] = 1; ++ } else { ++ err_flag[i] = 0; ++ } ++ /* Disable EDGE CHK in MT7623 */ ++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); ++ wait_loop(gsw); ++ if (err_flag[i] != 0) { ++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mtk_switch_w32(gsw, read_data, ++ TRGMII_7623_RD_0 + i * 8); ++ tap_a[i] = rd_tap; ++ } else { ++ rd_tap = (read_data & 0x0000007f) + 48; ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mtk_switch_w32(gsw, read_data, ++ TRGMII_7623_RD_0 + i * 8); ++ } ++ ++ } ++ pr_err("MT7623 %dth bit Tap_a = %d\n", i, tap_a[i]); ++ } ++ /* pr_err("Last While Loop\n"); */ ++ for (i = 0; i < 5; i++) { ++ while ((err_flag[i] == 0) && (rd_tap != 128)) { ++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); ++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); ++ /* Enable EDGE CHK in MT7623 */ ++ val = ++ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000; ++ val &= 0x4fffffff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8); ++ wait_loop(gsw); ++ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); ++ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ ++ rd_wd = (read_data >> 16) & 0x000000ff; ++ if (err_cnt[i] != 0 || rd_wd != 0x55) { ++ err_flag[i] = 1; ++ } else { ++ err_flag[i] = 0; ++ } ++ ++ /* Disable EDGE CHK in MT7623 */ ++ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); ++ wait_loop(gsw); ++ ++ } ++ ++ tap_b[i] = rd_tap; /* -rxd_step_size; */ ++ pr_err("MT7623 %dth bit Tap_b = %d\n", i, tap_b[i]); ++ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ ++ read_data = (read_data & 0xffffff80) | final_tap[i]; ++ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); ++ } ++ ++ read_data = mt7530_mdio_r32(gsw, 0x7A40); ++ read_data &= 0x3fffffff; ++ mt7530_mdio_w32(gsw, 0x7A40, read_data); ++} ++ ++static void trgmii_calibration_7530(struct mt7620_gsw *gsw) ++{ ++ ++ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; ++ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; ++ unsigned int final_tap[5]; ++ unsigned int rxc_step_size; ++ unsigned int rxd_step_size; ++ unsigned int read_data; ++ unsigned int tmp = 0; ++ int i; ++ unsigned int err_cnt[5]; ++ unsigned int rd_wd; ++ unsigned int init_toggle_data; ++ unsigned int err_flag[5]; ++ unsigned int err_total_flag; ++ unsigned int training_word; ++ unsigned int rd_tap; ++ ++ u32 TRGMII_7623_base; ++ u32 TRGMII_7530_RD_0; ++ u32 TRGMII_RCK_CTRL; ++ u32 TRGMII_7530_base; ++ u32 TRGMII_7530_TX_base; ++ u32 val; ++ ++ TRGMII_7623_base = 0x300; ++ TRGMII_7530_base = 0x7A00; ++ TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10; ++ TRGMII_RCK_CTRL = TRGMII_7623_base; ++ rxd_step_size = 0x1; ++ rxc_step_size = 0x8; ++ init_toggle_data = 0x00000055; ++ training_word = 0x000000AC; ++ ++ TRGMII_7530_TX_base = TRGMII_7530_base + 0x50; ++ ++ /* pr_err("Calibration begin ........\n"); */ ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); ++ read_data = mt7530_mdio_r32(gsw, 0x7a10); ++ /* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); ++ read_data &= 0x3fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78); ++ read_data |= 0x00002000; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data); /* Set TX OE edge in MT7530 */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ read_data |= 0x80000000; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ read_data &= 0x7fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); ++ read_data |= 0xC0000000; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ ++ ++ /* pr_err("Enable Training Mode in MT7623\n"); */ ++ /*Enable Training Mode in MT7623 */ ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); ++ if (gsw->trgmii_force == 2000) { ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); ++ } else { ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); ++ } ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70); ++ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800; ++ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78); ++ err_total_flag = 0; ++ /* pr_err("Adjust RXC delay in MT7530\n"); */ ++ read_data = 0x0; ++ while (err_total_flag == 0 && (read_data != 0x68)) { ++ /* pr_err("2nd Enable EDGE CHK in MT7530\n"); */ ++ /* Enable EDGE CHK in MT7530 */ ++ for (i = 0; i < 5; i++) { ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ /* pr_err("2nd Disable EDGE CHK in MT7530\n"); */ ++ err_cnt[i] = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ /* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ ++ /* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ ++ err_cnt[i] >>= 8; ++ err_cnt[i] &= 0x0000ff0f; ++ rd_wd = err_cnt[i] >> 8; ++ rd_wd &= 0x000000ff; ++ err_cnt[i] &= 0x0000000f; ++ /* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */ ++ if (err_cnt[i] != 0) { ++ err_flag[i] = 1; ++ } else if (rd_wd != 0x55) { ++ err_flag[i] = 1; ++ } else { ++ err_flag[i] = 0; ++ } ++ if (i == 0) { ++ err_total_flag = err_flag[i]; ++ } else { ++ err_total_flag = err_flag[i] & err_total_flag; ++ } ++ /* Disable EDGE CHK in MT7530 */ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ } ++ /*Adjust RXC delay */ ++ if (err_total_flag == 0) { ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ read_data |= 0x80000000; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ ++ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); ++ read_data &= 0x3fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ tmp = read_data; ++ tmp &= 0x0000007f; ++ tmp += rxc_step_size; ++ /* pr_err("Current rxc delay = %d\n", tmp); */ ++ read_data &= 0xffffff80; ++ read_data |= tmp; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ /* pr_err("Current RXC delay = %x\n", read_data); */ ++ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); ++ read_data &= 0x7fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ ++ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); ++ read_data |= 0xc0000000; ++ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ ++ pr_err("####### MT7530 RXC delay is %d\n", tmp); ++ } ++ read_data = tmp; ++ } ++ pr_err("Finish RXC Adjustment while loop\n"); ++ ++ /* pr_err("Read RD_WD MT7530\n"); */ ++ /* Read RD_WD MT7530 */ ++ for (i = 0; i < 5; i++) { ++ rd_tap = 0; ++ while (err_flag[i] != 0 && rd_tap != 128) { ++ /* Enable EDGE CHK in MT7530 */ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ err_cnt[i] = (read_data >> 8) & 0x0000000f; ++ rd_wd = (read_data >> 16) & 0x000000ff; ++ if (err_cnt[i] != 0 || rd_wd != 0x55) { ++ err_flag[i] = 1; ++ } else { ++ err_flag[i] = 0; ++ } ++ if (err_flag[i] != 0) { ++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7530 */ ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ tap_a[i] = rd_tap; ++ } else { ++ tap_a[i] = (read_data & 0x0000007f); /* Record the min delay TAP_A */ ++ rd_tap = tap_a[i] + 0x4; ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ } ++ ++ /* Disable EDGE CHK in MT7530 */ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ ++ } ++ pr_err("MT7530 %dth bit Tap_a = %d\n", i, tap_a[i]); ++ } ++ ++ /* pr_err("Last While Loop\n"); */ ++ for (i = 0; i < 5; i++) { ++ rd_tap = 0; ++ while (err_flag[i] == 0 && (rd_tap != 128)) { ++ /* Enable EDGE CHK in MT7530 */ ++ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ err_cnt[i] = (read_data >> 8) & 0x0000000f; ++ rd_wd = (read_data >> 16) & 0x000000ff; ++ if (err_cnt[i] != 0 || rd_wd != 0x55) ++ err_flag[i] = 1; ++ else ++ err_flag[i] = 0; ++ ++ if (err_flag[i] == 0 && (rd_tap != 128)) { ++ /* Add RXD delay in MT7530 */ ++ rd_tap = (read_data & 0x0000007f) + rxd_step_size; ++ read_data = (read_data & 0xffffff80) | rd_tap; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ } ++ /* Disable EDGE CHK in MT7530 */ ++ read_data = ++ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); ++ read_data |= 0x40000000; ++ read_data &= 0x4fffffff; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, ++ read_data); ++ wait_loop(gsw); ++ } ++ tap_b[i] = rd_tap; /* - rxd_step_size; */ ++ pr_err("MT7530 %dth bit Tap_b = %d\n", i, tap_b[i]); ++ /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ ++ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; ++ /* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */ ++ ++ read_data = (read_data & 0xffffff80) | final_tap[i]; ++ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data); ++ } ++ ++ if (gsw->trgmii_force == 2000) ++ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40); ++ else ++ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40); ++ ++} ++ ++static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode) ++{ ++ ++ u32 regValue; ++ ++ /* TRGMII Clock */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x404); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ ++ if (xtal_mode == 1) { ++ /* 25MHz */ ++ if (gsw->trgmii_force == 2600) ++ /* 325MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1a00); ++ else if (gsw->trgmii_force == 2000) ++ /* 250MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1400); ++ } else if (xtal_mode == 2) { ++ /* 40MHz */ ++ if (gsw->trgmii_force == 2600) ++ /* 325MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1040); ++ else if (gsw->trgmii_force == 2000) ++ /* 250MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0c80); ++ } ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x405); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x409); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ if (xtal_mode == 1) ++ /* 25MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); ++ else ++ /* 40MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40a); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ if (xtal_mode == 1) ++ /* 25MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); ++ else ++ /* 40MHz */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1800); ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1c00); ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x401); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0xc020); ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0xa030); ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0xa038); ++ ++// udelay(120); /* for MT7623 bring up test */ ++ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x3); ++ ++ regValue = mt7530_mdio_r32(gsw, 0x7830); ++ regValue &= 0xFFFFFFFC; ++ regValue |= 0x00000001; ++ mt7530_mdio_w32(gsw, 0x7830, regValue); ++ ++ regValue = mt7530_mdio_r32(gsw, 0x7a40); ++ regValue &= ~(0x1 << 30); ++ regValue &= ~(0x1 << 28); ++ mt7530_mdio_w32(gsw, 0x7a40, regValue); ++ ++ mt7530_mdio_w32(gsw, 0x7a78, 0x55); ++// udelay(100); /* for mt7623 bring up test */ ++ ++ mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300); ++ ++ trgmii_calibration_7623(gsw); ++ trgmii_calibration_7530(gsw); ++ ++ mtk_switch_m32(gsw, 0, 0x80000000, 0x300); ++ mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300); ++ ++ /*MT7530 RXC reset */ ++ regValue = mt7530_mdio_r32(gsw, 0x7a00); ++ regValue |= (0x1 << 31); ++ mt7530_mdio_w32(gsw, 0x7a00, regValue); ++ mdelay(1); ++ regValue &= ~(0x1 << 31); ++ mt7530_mdio_w32(gsw, 0x7a00, regValue); ++ mdelay(100); ++} ++ ++static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np) ++{ ++ u32 i; ++ u32 val; ++ u32 xtal_mode; ++ ++ regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0, ++ ETHSYS_TRGMII_CLK_SEL362_5, ++ ETHSYS_TRGMII_CLK_SEL362_5); ++ ++ /* reset the TRGMII core */ ++ mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE); ++ mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL); ++ ++ /* Hardware reset Switch */ ++ device_reset(eth->dev); ++ ++ /* Wait for Switch Reset Completed*/ ++ for (i = 0; i < 100; i++) { ++ mdelay(10); ++ if (mt7530_mdio_r32(gsw, MT7530_HWTRAP)) ++ break; ++ } ++ ++ /* turn off all PHYs */ ++ for (i = 0; i <= 4; i++) { ++ val = _mtk_mdio_read(gsw->eth, i, 0x0); ++ val |= BIT(11); ++ _mtk_mdio_write(gsw->eth, i, 0x0, val); ++ } ++ ++ /* reset the switch */ ++ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL, ++ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); ++ udelay(100); ++ ++ /* GE1, Force 1000M/FD, FC ON */ ++ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC); ++ ++ /* GE2, Force 1000M/FD, FC ON */ ++ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC); ++ ++ /* Enable Port 6, P5 as GMAC5, P5 disable */ ++ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP); ++ /* Enable Port 6 */ ++ val &= ~MHWTRAP_P6_DIS; ++ /* Enable Port 5 */ ++ val &= ~MHWTRAP_P5_DIS; ++ /* Port 5 as GMAC */ ++ val |= MHWTRAP_P5_MAC_SEL; ++ /* Port 5 Interface mode */ ++ val |= MHWTRAP_P5_RGMII_MODE; ++ /* Set MT7530 phy direct access mode**/ ++ val &= ~MHWTRAP_PHY_ACCESS; ++ val |= MHWTRAP_PHY_ACCESS; ++ /* manual override of HW-Trap */ ++ val |= MHWTRAP_MANUAL; ++ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val); ++ ++ val = mt7530_mdio_r32(gsw, 0x7800); ++ val = (val >> 9) & 0x3; ++ pr_err("!!%s: Mhz value= %d\n", __func__, val); ++ if (val == 0x3) { ++ xtal_mode = 1; ++ /* 25Mhz Xtal - do nothing */ ++ } else if (val == 0x2) { ++ /* 40Mhz */ ++ xtal_mode = 2; ++ ++ /* disable MT7530 core clock */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); ++ ++ /* disable MT7530 PLL */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x2020); ++ ++ /* for MT7530 core clock = 500Mhz */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40e); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x119); ++ ++ /* enable MT7530 PLL */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x2820); ++ ++ udelay(20); ++ ++ /* enable MT7530 core clock */ ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); ++ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); ++ } else { ++ xtal_mode = 3; ++ /* 20Mhz Xtal - TODO */ ++ } ++ ++ /* RGMII */ ++ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); ++ ++ /* set MT7530 central align */ ++ val = mt7530_mdio_r32(gsw, 0x7830); ++ val &= ~1; ++ val |= 1<<1; ++ mt7530_mdio_w32(gsw, 0x7830, val); ++ ++ val = mt7530_mdio_r32(gsw, 0x7a40); ++ val &= ~(1<<30); ++ mt7530_mdio_w32(gsw, 0x7a40, val); ++ ++ mt7530_mdio_w32(gsw, 0x7a78, 0x855); ++ ++ /* delay setting for 10/1000M */ ++ mt7530_mdio_w32(gsw, 0x7b00, 0x104); ++ mt7530_mdio_w32(gsw, 0x7b04, 0x10); ++ ++ /* lower Tx Driving */ ++ mt7530_mdio_w32(gsw, 0x7a54, 0x88); ++ mt7530_mdio_w32(gsw, 0x7a5c, 0x88); ++ mt7530_mdio_w32(gsw, 0x7a64, 0x88); ++ mt7530_mdio_w32(gsw, 0x7a6c, 0x88); ++ mt7530_mdio_w32(gsw, 0x7a74, 0x88); ++ mt7530_mdio_w32(gsw, 0x7a7c, 0x88); ++ mt7530_mdio_w32(gsw, 0x7810, 0x11); ++ ++ /* Set MT7623/MT7683 TX Driving */ ++ mtk_switch_w32(gsw, 0x88, 0x354); ++ mtk_switch_w32(gsw, 0x88, 0x35c); ++ mtk_switch_w32(gsw, 0x88, 0x364); ++ mtk_switch_w32(gsw, 0x88, 0x36c); ++ mtk_switch_w32(gsw, 0x88, 0x374); ++ mtk_switch_w32(gsw, 0x88, 0x37c); ++ ++ /* Set GE2 driving and slew rate */ ++ regmap_write(gsw->pctl, 0xF00, 0xe00); ++ /* set GE2 TDSEL */ ++ regmap_write(gsw->pctl, 0x4C0, 0x5); ++ /* set GE2 TUNE */ ++ regmap_write(gsw->pctl, 0xED0, 0x0); ++ ++ ++ mt7530_trgmii_clock_setting(gsw, xtal_mode); ++ ++ //LANWANPartition(gsw); ++ ++ /* disable EEE */ ++ for (i = 0; i <= 4; i++) { ++ _mtk_mdio_write(gsw->eth, i, 13, 0x7); ++ _mtk_mdio_write(gsw->eth, i, 14, 0x3C); ++ _mtk_mdio_write(gsw->eth, i, 13, 0x4007); ++ _mtk_mdio_write(gsw->eth, i, 14, 0x0); ++ ++ /* Increase SlvDPSready time */ ++ _mtk_mdio_write(gsw->eth, i, 31, 0x52b5); ++ _mtk_mdio_write(gsw->eth, i, 16, 0xafae); ++ _mtk_mdio_write(gsw->eth, i, 18, 0x2f); ++ _mtk_mdio_write(gsw->eth, i, 16, 0x8fae); ++ ++ /* Incease post_update_timer */ ++ _mtk_mdio_write(gsw->eth, i, 31, 0x3); ++ _mtk_mdio_write(gsw->eth, i, 17, 0x4b); ++ ++ /* Adjust 100_mse_threshold */ ++ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); ++ _mtk_mdio_write(gsw->eth, i, 14, 0x123); ++ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); ++ _mtk_mdio_write(gsw->eth, i, 14, 0xffff); ++ ++ /* Disable mcc */ ++ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); ++ _mtk_mdio_write(gsw->eth, i, 14, 0xa6); ++ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); ++ _mtk_mdio_write(gsw->eth, i, 14, 0x300); ++ ++ /* Disable HW auto downshift*/ ++ _mtk_mdio_write(gsw->eth, i, 31, 0x1); ++ val = _mtk_mdio_read(gsw->eth, i, 0x14); ++ val &= ~(1<<4); ++ _mtk_mdio_write(gsw->eth, i, 0x14, val); ++ } ++ ++ /* turn on all PHYs */ ++ for (i = 0; i <= 4; i++) { ++ val = _mtk_mdio_read(gsw->eth, i, 0); ++ val &= ~BIT(11); ++ _mtk_mdio_write(gsw->eth, i, 0, val); ++ } ++ ++ /* enable irq */ ++ mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL); ++ ++ /* enable autopolling */ ++ if (gsw->eth->mac[1] && gsw->eth->mac[1]->phy_dev) { ++ val = mtk_switch_r32(gsw, 0); ++ val |= (1<<31); ++ val &= ~(0x1f); ++ val &= ~(0x1f<<8); ++ val |= 4; ++ val |= 5 << 8; ++ mtk_switch_w32(gsw, val, 0); ++ ++ val = _mtk_mdio_read(gsw->eth, 5, 4); ++ val |= BIT(10); ++ _mtk_mdio_write(gsw->eth, 5, 4, val); ++ val = _mtk_mdio_read(gsw->eth, 5, 0); ++ val |= BIT(9); ++ _mtk_mdio_write(gsw->eth, 5, 0, val); ++ } ++} ++ ++static const struct of_device_id mediatek_gsw_match[] = { ++ { .compatible = "mediatek,mt7623-gsw" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mediatek_gsw_match); ++ ++int mtk_gsw_init(struct mtk_eth *eth) ++{ ++ struct device_node *np = eth->switch_np; ++ struct platform_device *pdev = of_find_device_by_node(np); ++ struct mt7620_gsw *gsw; ++ ++ if (!pdev) ++ return -ENODEV; ++ ++ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) ++ return -EINVAL; ++ ++ gsw = platform_get_drvdata(pdev); ++ if (!gsw) ++ return -ENODEV; ++ gsw->eth = eth; ++ eth->sw_priv = gsw; ++ ++ mt7623_hw_init(eth, gsw, np); ++ ++ request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0, ++ "gsw", eth); ++ mt7530_mdio_w32(gsw, 0x7008, 0x1f); ++ ++ return 0; ++} ++ ++static int mt7623_gsw_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *pctl; ++ int reset_pin, ret; ++ struct mt7620_gsw *gsw; ++ struct regulator *supply; ++ ++ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); ++ if (!gsw) ++ return -ENOMEM; ++ ++ gsw->dev = &pdev->dev; ++ gsw->trgmii_force = 2000; ++ gsw->irq = irq_of_parse_and_map(np, 0); ++ if (gsw->irq < 0) ++ return -EINVAL; ++ ++ gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys"); ++ if (IS_ERR(gsw->ethsys)) ++ return PTR_ERR(gsw->ethsys); ++ ++ reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0); ++ if (reset_pin < 0) ++ return reset_pin; ++ ++ pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0); ++ if (IS_ERR(pctl)) ++ return PTR_ERR(pctl); ++ ++ gsw->pctl = syscon_node_to_regmap(pctl); ++ if (IS_ERR(pctl)) ++ return PTR_ERR(pctl); ++ ++ ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset"); ++ if (ret) ++ return ret; ++ ++ gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll"); ++ ++ if (IS_ERR(gsw->clk_trgpll)) ++ return -ENODEV; ++ ++ supply = devm_regulator_get(&pdev->dev, "mt7530"); ++ if (IS_ERR(supply)) ++ return PTR_ERR(supply); ++ ++ regulator_set_voltage(supply, 1000000, 1000000); ++ ret = regulator_enable(supply); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret); ++ return ret; ++ } ++ pm_runtime_enable(&pdev->dev); ++ pm_runtime_get_sync(&pdev->dev); ++ ++ ret = clk_set_rate(gsw->clk_trgpll, 500000000); ++ if (ret) ++ return ret; ++ ++ clk_prepare_enable(gsw->clk_trgpll); ++ ++ gpio_direction_output(reset_pin, 0); ++ udelay(1000); ++ gpio_set_value(reset_pin, 1); ++ mdelay(100); ++ ++ platform_set_drvdata(pdev, gsw); ++ ++ return 0; ++} ++ ++static int mt7623_gsw_remove(struct platform_device *pdev) ++{ ++ struct mt7620_gsw *gsw = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(gsw->clk_trgpll); ++ ++ pm_runtime_put_sync(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++static struct platform_driver gsw_driver = { ++ .probe = mt7623_gsw_probe, ++ .remove = mt7623_gsw_remove, ++ .driver = { ++ .name = "mt7623-gsw", ++ .owner = THIS_MODULE, ++ .of_match_table = mediatek_gsw_match, ++ }, ++}; ++ ++module_platform_driver(gsw_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin "); ++MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC"); +diff --git a/drivers/net/ethernet/mediatek/mt7530.c b/drivers/net/ethernet/mediatek/mt7530.c +new file mode 100644 +index 0000000..2e9d280 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mt7530.c +@@ -0,0 +1,808 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2013 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mt7530.h" ++ ++#define MT7530_CPU_PORT 6 ++#define MT7530_NUM_PORTS 8 ++#define MT7530_NUM_VLANS 16 ++#define MT7530_MAX_VID 4095 ++#define MT7530_MIN_VID 0 ++ ++/* registers */ ++#define REG_ESW_VLAN_VTCR 0x90 ++#define REG_ESW_VLAN_VAWD1 0x94 ++#define REG_ESW_VLAN_VAWD2 0x98 ++#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2)) ++ ++#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30) ++#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28) ++#define REG_ESW_VLAN_VAWD1_VALID BIT(0) ++ ++/* vlan egress mode */ ++enum { ++ ETAG_CTRL_UNTAG = 0, ++ ETAG_CTRL_TAG = 2, ++ ETAG_CTRL_SWAP = 1, ++ ETAG_CTRL_STACK = 3, ++}; ++ ++#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8)) ++#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8)) ++#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8)) ++ ++#define REG_HWTRAP 0x7804 ++ ++#define MIB_DESC(_s , _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++struct mt7xxx_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++}; ++ ++#define MT7621_MIB_COUNTER_BASE 0x4000 ++#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100 ++#define MT7621_STATS_TDPC 0x00 ++#define MT7621_STATS_TCRC 0x04 ++#define MT7621_STATS_TUPC 0x08 ++#define MT7621_STATS_TMPC 0x0C ++#define MT7621_STATS_TBPC 0x10 ++#define MT7621_STATS_TCEC 0x14 ++#define MT7621_STATS_TSCEC 0x18 ++#define MT7621_STATS_TMCEC 0x1C ++#define MT7621_STATS_TDEC 0x20 ++#define MT7621_STATS_TLCEC 0x24 ++#define MT7621_STATS_TXCEC 0x28 ++#define MT7621_STATS_TPPC 0x2C ++#define MT7621_STATS_TL64PC 0x30 ++#define MT7621_STATS_TL65PC 0x34 ++#define MT7621_STATS_TL128PC 0x38 ++#define MT7621_STATS_TL256PC 0x3C ++#define MT7621_STATS_TL512PC 0x40 ++#define MT7621_STATS_TL1024PC 0x44 ++#define MT7621_STATS_TOC 0x48 ++#define MT7621_STATS_RDPC 0x60 ++#define MT7621_STATS_RFPC 0x64 ++#define MT7621_STATS_RUPC 0x68 ++#define MT7621_STATS_RMPC 0x6C ++#define MT7621_STATS_RBPC 0x70 ++#define MT7621_STATS_RAEPC 0x74 ++#define MT7621_STATS_RCEPC 0x78 ++#define MT7621_STATS_RUSPC 0x7C ++#define MT7621_STATS_RFEPC 0x80 ++#define MT7621_STATS_ROSPC 0x84 ++#define MT7621_STATS_RJEPC 0x88 ++#define MT7621_STATS_RPPC 0x8C ++#define MT7621_STATS_RL64PC 0x90 ++#define MT7621_STATS_RL65PC 0x94 ++#define MT7621_STATS_RL128PC 0x98 ++#define MT7621_STATS_RL256PC 0x9C ++#define MT7621_STATS_RL512PC 0xA0 ++#define MT7621_STATS_RL1024PC 0xA4 ++#define MT7621_STATS_ROC 0xA8 ++#define MT7621_STATS_RDPC_CTRL 0xB0 ++#define MT7621_STATS_RDPC_ING 0xB4 ++#define MT7621_STATS_RDPC_ARL 0xB8 ++ ++static const struct mt7xxx_mib_desc mt7621_mibs[] = { ++ MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"), ++ MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"), ++ MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"), ++ MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"), ++ MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"), ++ MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"), ++ MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"), ++ MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"), ++ MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"), ++ MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"), ++ MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"), ++ MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"), ++ MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"), ++ MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"), ++ MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"), ++ MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"), ++ MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"), ++ MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"), ++ MIB_DESC(2, MT7621_STATS_TOC, "TxByte"), ++ MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"), ++ MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"), ++ MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"), ++ MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"), ++ MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"), ++ MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"), ++ MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"), ++ MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"), ++ MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"), ++ MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"), ++ MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"), ++ MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"), ++ MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"), ++ MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"), ++ MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"), ++ MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"), ++ MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"), ++ MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"), ++ MIB_DESC(2, MT7621_STATS_ROC, "RxByte"), ++ MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"), ++ MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"), ++ MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop") ++}; ++ ++enum { ++ /* Global attributes. */ ++ MT7530_ATTR_ENABLE_VLAN, ++}; ++ ++struct mt7530_port_entry { ++ u16 pvid; ++}; ++ ++struct mt7530_vlan_entry { ++ u16 vid; ++ u8 member; ++ u8 etags; ++}; ++ ++struct mt7530_priv { ++ void __iomem *base; ++ struct mii_bus *bus; ++ struct switch_dev swdev; ++ ++ bool global_vlan_enable; ++ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS]; ++ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS]; ++}; ++ ++struct mt7530_mapping { ++ char *name; ++ u16 pvids[MT7530_NUM_PORTS]; ++ u8 members[MT7530_NUM_VLANS]; ++ u8 etags[MT7530_NUM_VLANS]; ++ u16 vids[MT7530_NUM_VLANS]; ++} mt7530_defaults[] = { ++ { ++ .name = "llllw", ++ .pvids = { 1, 1, 1, 1, 2, 1, 1 }, ++ .members = { 0, 0x6f, 0x50 }, ++ .etags = { 0, 0x40, 0x40 }, ++ .vids = { 0, 1, 2 }, ++ }, { ++ .name = "wllll", ++ .pvids = { 2, 1, 1, 1, 1, 1, 1 }, ++ .members = { 0, 0x7e, 0x41 }, ++ .etags = { 0, 0x40, 0x40 }, ++ .vids = { 0, 1, 2 }, ++ }, ++}; ++ ++struct mt7530_mapping* ++mt7530_find_mapping(struct device_node *np) ++{ ++ const char *map; ++ int i; ++ ++ if (of_property_read_string(np, "mediatek,portmap", &map)) ++ return NULL; ++ ++ for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++) ++ if (!strcmp(map, mt7530_defaults[i].name)) ++ return &mt7530_defaults[i]; ++ ++ return NULL; ++} ++ ++static void ++mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map) ++{ ++ int i = 0; ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ mt7530->port_entries[i].pvid = map->pvids[i]; ++ ++ for (i = 0; i < MT7530_NUM_VLANS; i++) { ++ mt7530->vlan_entries[i].member = map->members[i]; ++ mt7530->vlan_entries[i].etags = map->etags[i]; ++ mt7530->vlan_entries[i].vid = map->vids[i]; ++ } ++} ++ ++static int ++mt7530_reset_switch(struct switch_dev *dev) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ int i; ++ ++ memset(eth->port_entries, 0, sizeof(eth->port_entries)); ++ memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries)); ++ ++ /* set default vid of each vlan to the same number of vlan, so the vid ++ * won't need be set explicitly. ++ */ ++ for (i = 0; i < MT7530_NUM_VLANS; i++) { ++ eth->vlan_entries[i].vid = i; ++ } ++ ++ return 0; ++} ++ ++static int ++mt7530_get_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ ++ val->value.i = eth->global_vlan_enable; ++ ++ return 0; ++} ++ ++static int ++mt7530_set_vlan_enable(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ ++ eth->global_vlan_enable = val->value.i != 0; ++ ++ return 0; ++} ++ ++static u32 ++mt7530_r32(struct mt7530_priv *eth, u32 reg) ++{ ++ u32 val; ++ if (eth->bus) { ++ u16 high, low; ++ ++ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); ++ low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf); ++ high = mdiobus_read(eth->bus, 0x1f, 0x10); ++ ++ return (high << 16) | (low & 0xffff); ++ } ++ ++ val = ioread32(eth->base + reg); ++ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val); ++ ++ return val; ++} ++ ++static void ++mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val) ++{ ++ if (eth->bus) { ++ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); ++ mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff); ++ mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16); ++ return; ++ } ++ ++ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val); ++ iowrite32(val, eth->base + reg); ++} ++ ++static void ++mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val) ++{ ++ int i; ++ ++ mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val); ++ ++ for (i = 0; i < 20; i++) { ++ u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR); ++ ++ if ((val & BIT(31)) == 0) ++ break; ++ ++ udelay(1000); ++ } ++ if (i == 20) ++ printk("mt7530: vtcr timeout\n"); ++} ++ ++static int ++mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ ++ if (port >= MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ *val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port)); ++ *val &= 0xfff; ++ ++ return 0; ++} ++ ++static int ++mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ ++ if (port >= MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID) ++ return -EINVAL; ++ ++ eth->port_entries[port].pvid = pvid; ++ ++ return 0; ++} ++ ++static int ++mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ u32 member; ++ u32 etags; ++ int i; ++ ++ val->len = 0; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS) ++ return -EINVAL; ++ ++ mt7530_vtcr(eth, 0, val->port_vlan); ++ ++ member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1); ++ member >>= 16; ++ member &= 0xff; ++ ++ etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ struct switch_port *p; ++ int etag; ++ ++ if (!(member & BIT(i))) ++ continue; ++ ++ p = &val->value.ports[val->len++]; ++ p->id = i; ++ ++ etag = (etags >> (i * 2)) & 0x3; ++ ++ if (etag == ETAG_CTRL_TAG) ++ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED); ++ else if (etag != ETAG_CTRL_UNTAG) ++ printk("vlan egress tag control neither untag nor tag.\n"); ++ } ++ ++ return 0; ++} ++ ++static int ++mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ u8 member = 0; ++ u8 etags = 0; ++ int i; ++ ++ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS || ++ val->len > MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ for (i = 0; i < val->len; i++) { ++ struct switch_port *p = &val->value.ports[i]; ++ ++ if (p->id >= MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ member |= BIT(p->id); ++ ++ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) ++ etags |= BIT(p->id); ++ } ++ eth->vlan_entries[val->port_vlan].member = member; ++ eth->vlan_entries[val->port_vlan].etags = etags; ++ ++ return 0; ++} ++ ++static int ++mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ int vlan; ++ u16 vid; ++ ++ vlan = val->port_vlan; ++ vid = (u16)val->value.i; ++ ++ if (vlan < 0 || vlan >= MT7530_NUM_VLANS) ++ return -EINVAL; ++ ++ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID) ++ return -EINVAL; ++ ++ eth->vlan_entries[vlan].vid = vid; ++ return 0; ++} ++ ++static int ++mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ u32 vid; ++ int vlan; ++ ++ vlan = val->port_vlan; ++ ++ vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan)); ++ if (vlan & 1) ++ vid = vid >> 12; ++ vid &= 0xfff; ++ ++ val->value.i = vid; ++ return 0; ++} ++ ++static int ++mt7530_apply_config(struct switch_dev *dev) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ int i, j; ++ u8 tag_ports; ++ u8 untag_ports; ++ ++ if (!eth->global_vlan_enable) { ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0); ++ ++ return 0; ++ } ++ ++ /* set all ports as security mode */ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003); ++ ++ /* check if a port is used in tag/untag vlan egress mode */ ++ tag_ports = 0; ++ untag_ports = 0; ++ ++ for (i = 0; i < MT7530_NUM_VLANS; i++) { ++ u8 member = eth->vlan_entries[i].member; ++ u8 etags = eth->vlan_entries[i].etags; ++ ++ if (!member) ++ continue; ++ ++ for (j = 0; j < MT7530_NUM_PORTS; j++) { ++ if (!(member & BIT(j))) ++ continue; ++ ++ if (etags & BIT(j)) ++ tag_ports |= 1u << j; ++ else ++ untag_ports |= 1u << j; ++ } ++ } ++ ++ /* set all untag-only ports as transparent and the rest as user port */ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ u32 pvc_mode = 0x81000000; ++ ++ if (untag_ports & BIT(i) && !(tag_ports & BIT(i))) ++ pvc_mode = 0x810000c0; ++ ++ mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode); ++ } ++ ++ for (i = 0; i < MT7530_NUM_VLANS; i++) { ++ u16 vid = eth->vlan_entries[i].vid; ++ u8 member = eth->vlan_entries[i].member; ++ u8 etags = eth->vlan_entries[i].etags; ++ u32 val; ++ ++ /* vid of vlan */ ++ val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i)); ++ if (i % 2 == 0) { ++ val &= 0xfff000; ++ val |= vid; ++ } else { ++ val &= 0xfff; ++ val |= (vid << 12); ++ } ++ mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val); ++ ++ /* vlan port membership */ ++ if (member) ++ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC | ++ REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) | ++ REG_ESW_VLAN_VAWD1_VALID); ++ else ++ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0); ++ ++ /* egress mode */ ++ val = 0; ++ for (j = 0; j < MT7530_NUM_PORTS; j++) { ++ if (etags & BIT(j)) ++ val |= ETAG_CTRL_TAG << (j * 2); ++ else ++ val |= ETAG_CTRL_UNTAG << (j * 2); ++ } ++ mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val); ++ ++ /* write to vlan table */ ++ mt7530_vtcr(eth, 1, i); ++ } ++ ++ /* Port Default PVID */ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ u32 val; ++ val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i)); ++ val &= ~0xfff; ++ val |= eth->port_entries[i].pvid; ++ mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val); ++ } ++ ++ return 0; ++} ++ ++static int ++mt7530_get_port_link(struct switch_dev *dev, int port, ++ struct switch_port_link *link) ++{ ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ u32 speed, pmsr; ++ ++ if (port < 0 || port >= MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port)); ++ ++ link->link = pmsr & 1; ++ link->duplex = (pmsr >> 1) & 1; ++ speed = (pmsr >> 2) & 3; ++ ++ switch (speed) { ++ case 0: ++ link->speed = SWITCH_PORT_SPEED_10; ++ break; ++ case 1: ++ link->speed = SWITCH_PORT_SPEED_100; ++ break; ++ case 2: ++ case 3: /* forced gige speed can be 2 or 3 */ ++ link->speed = SWITCH_PORT_SPEED_1000; ++ break; ++ default: ++ link->speed = SWITCH_PORT_SPEED_UNKNOWN; ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct switch_attr mt7530_global[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "enable_vlan", ++ .description = "VLAN mode (1:enabled)", ++ .max = 1, ++ .id = MT7530_ATTR_ENABLE_VLAN, ++ .get = mt7530_get_vlan_enable, ++ .set = mt7530_set_vlan_enable, ++ }, ++}; ++ ++static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port) ++{ ++ unsigned int port_base; ++ u64 t; ++ ++ port_base = MT7621_MIB_COUNTER_BASE + ++ MT7621_MIB_COUNTER_PORT_OFFSET * port; ++ ++ t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset); ++ if (mt7621_mibs[i].size == 2) { ++ u64 hi; ++ ++ hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4); ++ t |= hi << 32; ++ } ++ ++ return t; ++} ++ ++static int mt7621_sw_get_port_mib(struct switch_dev *dev, ++ const struct switch_attr *attr, ++ struct switch_val *val) ++{ ++ static char buf[4096]; ++ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); ++ int i, len = 0; ++ ++ if (val->port_vlan >= MT7530_NUM_PORTS) ++ return -EINVAL; ++ ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "Port %d MIB counters\n", val->port_vlan); ++ ++ for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) { ++ u64 counter; ++ len += snprintf(buf + len, sizeof(buf) - len, ++ "%-11s: ", mt7621_mibs[i].name); ++ counter = get_mib_counter(eth, i, val->port_vlan); ++ len += snprintf(buf + len, sizeof(buf) - len, "%llu\n", ++ counter); ++ } ++ ++ val->value.s = buf; ++ val->len = len; ++ return 0; ++} ++ ++static const struct switch_attr mt7621_port[] = { ++ { ++ .type = SWITCH_TYPE_STRING, ++ .name = "mib", ++ .description = "Get MIB counters for port", ++ .get = mt7621_sw_get_port_mib, ++ .set = NULL, ++ }, ++}; ++ ++static const struct switch_attr mt7530_port[] = { ++}; ++ ++static const struct switch_attr mt7530_vlan[] = { ++ { ++ .type = SWITCH_TYPE_INT, ++ .name = "vid", ++ .description = "VLAN ID (0-4094)", ++ .set = mt7530_set_vid, ++ .get = mt7530_get_vid, ++ .max = 4094, ++ }, ++}; ++ ++static const struct switch_dev_ops mt7621_ops = { ++ .attr_global = { ++ .attr = mt7530_global, ++ .n_attr = ARRAY_SIZE(mt7530_global), ++ }, ++/* .attr_port = { ++ .attr = mt7621_port, ++ .n_attr = ARRAY_SIZE(mt7621_port), ++ },*/ ++ .attr_vlan = { ++ .attr = mt7530_vlan, ++ .n_attr = ARRAY_SIZE(mt7530_vlan), ++ }, ++ .get_vlan_ports = mt7530_get_vlan_ports, ++ .set_vlan_ports = mt7530_set_vlan_ports, ++ .get_port_pvid = mt7530_get_port_pvid, ++ .set_port_pvid = mt7530_set_port_pvid, ++ .get_port_link = mt7530_get_port_link, ++ .apply_config = mt7530_apply_config, ++ .reset_switch = mt7530_reset_switch, ++}; ++ ++static const struct switch_dev_ops mt7530_ops = { ++ .attr_global = { ++ .attr = mt7530_global, ++ .n_attr = ARRAY_SIZE(mt7530_global), ++ }, ++ .attr_port = { ++ .attr = mt7530_port, ++ .n_attr = ARRAY_SIZE(mt7530_port), ++ }, ++ .attr_vlan = { ++ .attr = mt7530_vlan, ++ .n_attr = ARRAY_SIZE(mt7530_vlan), ++ }, ++ .get_vlan_ports = mt7530_get_vlan_ports, ++ .set_vlan_ports = mt7530_set_vlan_ports, ++ .get_port_pvid = mt7530_get_port_pvid, ++ .set_port_pvid = mt7530_set_port_pvid, ++ .get_port_link = mt7530_get_port_link, ++ .apply_config = mt7530_apply_config, ++ .reset_switch = mt7530_reset_switch, ++}; ++ ++int ++mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan) ++{ ++ struct switch_dev *swdev; ++ struct mt7530_priv *mt7530; ++ struct mt7530_mapping *map; ++ int ret; ++ ++ mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL); ++ if (!mt7530) ++ return -ENOMEM; ++ ++ mt7530->base = base; ++ mt7530->bus = bus; ++ mt7530->global_vlan_enable = vlan; ++ ++ swdev = &mt7530->swdev; ++ if (bus) { ++ swdev->alias = "mt7530"; ++ swdev->name = "mt7530"; ++ } else if (IS_ENABLED(CONFIG_MACH_MT7623)) { ++ swdev->alias = "mt7623"; ++ swdev->name = "mt7623"; ++ } else if (IS_ENABLED(CONFIG_SOC_MT7621)) { ++ swdev->alias = "mt7621"; ++ swdev->name = "mt7621"; ++ } else { ++ swdev->alias = "mt7620"; ++ swdev->name = "mt7620"; ++ } ++ swdev->cpu_port = MT7530_CPU_PORT; ++ swdev->ports = MT7530_NUM_PORTS; ++ swdev->vlans = MT7530_NUM_VLANS; ++ if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) ++ swdev->ops = &mt7621_ops; ++ else ++ swdev->ops = &mt7530_ops; ++ ++ ret = register_switch(swdev, NULL); ++ if (ret) { ++ dev_err(dev, "failed to register mt7530\n"); ++ return ret; ++ } ++ ++ mt7530_reset_switch(swdev); ++ ++ map = mt7530_find_mapping(dev->of_node); ++ if (map) ++ mt7530_apply_mapping(mt7530, map); ++ mt7530_apply_config(swdev); ++ ++ /* magic vodoo */ ++ if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) { ++ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n"); ++ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf); ++ } ++ dev_info(dev, "loaded %s driver\n", swdev->name); ++ ++ return 0; ++} +diff --git a/drivers/net/ethernet/mediatek/mt7530.h b/drivers/net/ethernet/mediatek/mt7530.h +new file mode 100644 +index 0000000..1fc8c62 +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mt7530.h +@@ -0,0 +1,20 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2013 John Crispin ++ */ ++ ++#ifndef _MT7530_H__ ++#define _MT7530_H__ ++ ++int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan); ++ ++#endif +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 2097ae1..ca7e961 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,9 @@ + + #include "mtk_eth_soc.h" + ++/* the callback used by the driver core to bringup the switch */ ++int mtk_gsw_init(struct mtk_eth *eth); ++ + static int mtk_msg_level = -1; + module_param_named(msg_level, mtk_msg_level, int, 0); + MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); +@@ -69,7 +72,7 @@ static int mtk_mdio_busy_wait(struct mtk_eth *eth) + return 0; + if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) + break; +- usleep_range(10, 20); ++// usleep_range(10, 20); + } + + dev_err(eth->dev, "mdio: MDIO timeout\n"); +@@ -132,36 +135,8 @@ static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) + + static void mtk_phy_link_adjust(struct net_device *dev) + { +- struct mtk_mac *mac = netdev_priv(dev); +- u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | +- MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | +- MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | +- MAC_MCR_BACKPR_EN; +- +- switch (mac->phy_dev->speed) { +- case SPEED_1000: +- mcr |= MAC_MCR_SPEED_1000; +- break; +- case SPEED_100: +- mcr |= MAC_MCR_SPEED_100; +- break; +- }; +- +- if (mac->phy_dev->link) +- mcr |= MAC_MCR_FORCE_LINK; +- +- if (mac->phy_dev->duplex) +- mcr |= MAC_MCR_FORCE_DPX; +- +- if (mac->phy_dev->pause) +- mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC; +- +- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); +- +- if (mac->phy_dev->link) +- netif_carrier_on(dev); +- else +- netif_carrier_off(dev); ++ netif_carrier_on(dev); ++ return; + } + + static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, +@@ -193,7 +168,7 @@ static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac, + + dev_info(eth->dev, + "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n", +- mac->id, phydev_name(phydev), phydev->phy_id, ++ mac->id, dev_name(&phydev->dev), phydev->phy_id, + phydev->drv->name); + + mac->phy_dev = phydev; +@@ -209,7 +184,7 @@ static int mtk_phy_connect(struct mtk_mac *mac) + + np = of_parse_phandle(mac->of_node, "phy-handle", 0); + if (!np) +- return -ENODEV; ++ return 0; + + switch (of_get_phy_mode(np)) { + case PHY_INTERFACE_MODE_RGMII: +@@ -239,7 +214,8 @@ static int mtk_phy_connect(struct mtk_mac *mac) + mac->phy_dev->supported &= PHY_BASIC_FEATURES; + mac->phy_dev->advertising = mac->phy_dev->supported | + ADVERTISED_Autoneg; +- phy_start_aneg(mac->phy_dev); ++ if (mac->phy_dev) ++ phy_start_aneg(mac->phy_dev); + + return 0; + } +@@ -626,7 +602,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -906,7 +881,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget) + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->netdev[i] || !done[i]) + continue; +- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); + total += done[i]; + } + +@@ -1284,9 +1258,12 @@ static int mtk_open(struct net_device *dev) + } + atomic_inc(ð->dma_refcnt); + +- phy_start(mac->phy_dev); ++ if (mac->phy_dev) ++ phy_start(mac->phy_dev); + netif_start_queue(dev); + ++ netif_carrier_on(dev); ++ + return 0; + } + +@@ -1319,8 +1296,10 @@ static int mtk_stop(struct net_device *dev) + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + ++ netif_carrier_off(dev); + netif_tx_disable(dev); +- phy_stop(mac->phy_dev); ++ if (mac->phy_dev) ++ phy_stop(mac->phy_dev); + + /* only shutdown DMA if this is the last user */ + if (!atomic_dec_and_test(ð->dma_refcnt)) +@@ -1346,20 +1325,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth) + reset_control_deassert(eth->rstc); + usleep_range(10, 20); + +- /* Set GE2 driving and slew rate */ +- regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00); +- +- /* set GE2 TDSEL */ +- regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5); +- +- /* set GE2 TUNE */ +- regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0); +- + /* GE1, Force 1000M/FD, FC ON */ +- mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0)); ++ mtk_w32(eth, 0x0105e33b, MTK_MAC_MCR(0)); + +- /* GE2, Force 1000M/FD, FC ON */ +- mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1)); ++ /* GE2, use autopolling */ ++ mtk_w32(eth, 0x01056300, MTK_MAC_MCR(1)); + + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); +@@ -1377,6 +1347,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth) + if (err) + return err; + ++ mtk_gsw_init(eth); ++ + /* disable delay and normal interrupt */ + mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT); +@@ -1404,6 +1376,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth) + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } + ++ mt7623_gsw_config(eth); ++ + return 0; + } + +@@ -1433,7 +1407,8 @@ static void mtk_uninit(struct net_device *dev) + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + +- phy_disconnect(mac->phy_dev); ++ if (mac->phy_dev) ++ phy_disconnect(mac->phy_dev); + mtk_mdio_cleanup(eth); + mtk_irq_disable(eth, ~0); + free_irq(eth->irq[0], dev); +@@ -1445,7 +1420,7 @@ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + { + struct mtk_mac *mac = netdev_priv(dev); + +- switch (cmd) { ++ if (mac->phy_dev) switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: +@@ -1508,9 +1483,10 @@ static int mtk_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) + { + struct mtk_mac *mac = netdev_priv(dev); +- int err; ++ int err = -1; + +- err = phy_read_status(mac->phy_dev); ++ if (mac->phy_dev) ++ err = phy_read_status(mac->phy_dev); + if (err) + return -ENODEV; + +@@ -1522,11 +1498,16 @@ static int mtk_set_settings(struct net_device *dev, + { + struct mtk_mac *mac = netdev_priv(dev); + +- if (cmd->phy_address != mac->phy_dev->mdio.addr) { +- mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus, +- cmd->phy_address); +- if (!mac->phy_dev) ++ if (!mac->phy_dev) ++ return -ENODEV; ++ ++ if (cmd->phy_address != mac->phy_dev->addr) { ++ if (mac->hw->mii_bus->phy_map[cmd->phy_address]) { ++ mac->phy_dev = ++ mac->hw->mii_bus->phy_map[cmd->phy_address]; ++ } else { + return -ENODEV; ++ } + } + + return phy_ethtool_sset(mac->phy_dev, cmd); +@@ -1560,6 +1541,9 @@ static int mtk_nway_reset(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + ++ if (!mac->phy_dev) ++ return -ENODEV; ++ + return genphy_restart_aneg(mac->phy_dev); + } + +@@ -1568,6 +1552,9 @@ static u32 mtk_get_link(struct net_device *dev) + struct mtk_mac *mac = netdev_priv(dev); + int err; + ++ if (!mac->phy_dev) ++ return -ENODEV; ++ + err = genphy_update_link(mac->phy_dev); + if (err) + return ethtool_op_get_link(dev); +@@ -1619,7 +1606,6 @@ static void mtk_get_ethtool_stats(struct net_device *dev, + data_src = (u64*)hwstats; + data_dst = data; + start = u64_stats_fetch_begin_irq(&hwstats->syncp); +- + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) + *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); + } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); +@@ -1789,6 +1775,9 @@ static int mtk_probe(struct platform_device *pdev) + clk_prepare_enable(eth->clk_gp1); + clk_prepare_enable(eth->clk_gp2); + ++ eth->switch_np = of_parse_phandle(pdev->dev.of_node, ++ "mediatek,switch", 0); ++ + eth->dev = &pdev->dev; + eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); + INIT_WORK(ð->pending_work, mtk_pending_work); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 4cfb40c..bbe0346 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -401,6 +401,9 @@ struct mtk_eth { + struct mii_bus *mii_bus; + struct work_struct pending_work; + struct tasklet_struct tx_clean_tasklet; ++ ++ struct device_node *switch_np; ++ void *sw_priv; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the +@@ -428,4 +431,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac); + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + ++int mt7623_gsw_config(struct mtk_eth *eth); ++ + #endif /* MTK_ETH_H */ +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0075-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.4/0075-clk-mediatek-enable-critical-clocks.patch new file mode 100644 index 0000000000..fe0c366c85 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0075-clk-mediatek-enable-critical-clocks.patch @@ -0,0 +1,74 @@ +From b7a101f53b7cb0e05658e04accf9fd12512b5735 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 06:46:51 +0200 +Subject: [PATCH 75/78] clk: mediatek: enable critical clocks + +Signed-off-by: John Crispin +--- + drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c +index 812b347..1634288 100644 +--- 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[] __initconst = { + 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(struct device_node *node) + 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(struct device_node *node) + 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(struct device_node *node) + 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(struct device_node *node) + 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); +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0076-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.4/0076-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch new file mode 100644 index 0000000000..ee3ba76e33 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0076-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch @@ -0,0 +1,306 @@ +From cc94bef897241da9b978c9799defbdbabe9ff6ec Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 02:26:37 +0200 +Subject: [PATCH 76/78] 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 + +diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile +index 5b2b91b..76bfab6 100644 +--- 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 +diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c +new file mode 100644 +index 0000000..91b5238 +--- /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_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_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_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; ++} +diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h +new file mode 100644 +index 0000000..52c769f +--- /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 */ +diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c +index 1634288..5c37fcb 100644 +--- 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[] __initconst = { + "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(struct device_node *node) + 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", +diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c +index 227e356..dfb109f 100644 +--- 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 + +@@ -526,6 +527,25 @@ static const char * const i2s3_b_ck_parents[] __initconst = { + "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[] __initdata = { ++ 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), +@@ -945,6 +965,9 @@ static void __init mtk_infrasys_init(struct device_node *node) + 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", +diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h +index 50972d1..a6c63b8 100644 +--- a/include/dt-bindings/clock/mt2701-clk.h ++++ b/include/dt-bindings/clock/mt2701-clk.h +@@ -217,7 +217,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 */ + +diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h +index 7956ba1..c82ed7c 100644 +--- a/include/dt-bindings/clock/mt8173-clk.h ++++ b/include/dt-bindings/clock/mt8173-clk.h +@@ -192,7 +192,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 */ + +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0077-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.4/0077-cpufreq-mediatek-add-driver.patch new file mode 100644 index 0000000000..4d8ed58334 --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0077-cpufreq-mediatek-add-driver.patch @@ -0,0 +1,727 @@ +From d1421147c328a7d06d9a6b8330c73e45139b1e48 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Wed, 30 Mar 2016 23:48:53 +0200 +Subject: [PATCH 77/78] cpufreq: mediatek: add driver + +Signed-off-by: John Crispin +--- + arch/arm/boot/dts/mt7623-evb.dts | 160 ++++++++++++---- + arch/arm/boot/dts/mt7623.dtsi | 50 ++++- + drivers/cpufreq/Kconfig.arm | 9 + + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/mt7623-cpufreq.c | 389 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 570 insertions(+), 39 deletions(-) + create mode 100644 drivers/cpufreq/mt7623-cpufreq.c + +diff --git a/arch/arm/boot/dts/mt7623-evb.dts b/arch/arm/boot/dts/mt7623-evb.dts +index bc2b3f1..4a433f0 100644 +--- a/arch/arm/boot/dts/mt7623-evb.dts ++++ b/arch/arm/boot/dts/mt7623-evb.dts +@@ -39,6 +39,22 @@ + }; + }; + ++&cpu0 { ++ proc-supply = <&mt6323_vproc_reg>; ++}; ++ ++&cpu1 { ++ proc-supply = <&mt6323_vproc_reg>; ++}; ++ ++&cpu2 { ++ proc-supply = <&mt6323_vproc_reg>; ++}; ++ ++&cpu3 { ++ proc-supply = <&mt6323_vproc_reg>; ++}; ++ + &pwrap { + pmic: mt6323 { + compatible = "mediatek,mt6323"; +@@ -267,38 +283,36 @@ + }; + }; + +-&uart2 { +- status = "okay"; +-}; ++&pio { ++ nand_pins_default: nanddefault { ++ pins_dat { ++ pinmux = , ++ , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ input-enable; ++ drive-strength = ; ++ bias-pull-up; ++ }; + +-&mmc0 { +- status = "okay"; +- pinctrl-names = "default", "state_uhs"; +- pinctrl-0 = <&mmc0_pins_default>; +- pinctrl-1 = <&mmc0_pins_uhs>; +- bus-width = <8>; +- max-frequency = <50000000>; +- cap-mmc-highspeed; +- vmmc-supply = <&mt6323_vemc3v3_reg>; +- vqmmc-supply = <&mt6323_vio18_reg>; +- non-removable; +-}; ++ pins_we { ++ pinmux = ; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; + +-&mmc1 { +- status = "okay"; +- pinctrl-names = "default", "state_uhs"; +- pinctrl-0 = <&mmc1_pins_default>; +- pinctrl-1 = <&mmc1_pins_uhs>; +- bus-width = <4>; +- max-frequency = <50000000>; +- cap-sd-highspeed; +- sd-uhs-sdr25; +-// cd-gpios = <&pio 132 0>; +- vmmc-supply = <&mt6323_vmch_reg>; +- vqmmc-supply = <&mt6323_vmc_reg>; +-}; ++ pins_ale { ++ pinmux = ; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; + +-&pio { + mmc0_pins_default: mmc0default { + pins_cmd_dat { + pinmux = , +@@ -370,11 +384,6 @@ + bias-pull-down; + drive-strength = ; + }; +- +-// pins_insert { +-// pinmux = ; +-// bias-pull-up; +-// }; + }; + + mmc1_pins_uhs: mmc1 { +@@ -422,6 +431,36 @@ + }; + }; + ++&uart2 { ++ status = "okay"; ++}; ++ ++&mmc0 { ++ status = "okay"; ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ pinctrl-1 = <&mmc0_pins_uhs>; ++ bus-width = <8>; ++ max-frequency = <50000000>; ++ cap-mmc-highspeed; ++ vmmc-supply = <&mt6323_vemc3v3_reg>; ++ vqmmc-supply = <&mt6323_vio18_reg>; ++ non-removable; ++}; ++ ++&mmc1 { ++ status = "okay"; ++ pinctrl-names = "default", "state_uhs"; ++ pinctrl-0 = <&mmc1_pins_default>; ++ pinctrl-1 = <&mmc1_pins_uhs>; ++ bus-width = <4>; ++ max-frequency = <50000000>; ++ cap-sd-highspeed; ++ sd-uhs-sdr25; ++ vmmc-supply = <&mt6323_vmch_reg>; ++ vqmmc-supply = <&mt6323_vmc_reg>; ++}; ++ + &usb1 { + vusb33-supply = <&mt6323_vusb_reg>; + vbus-supply = <&usb_p1_vbus>; +@@ -456,3 +495,56 @@ + mediatek,reset-pin = <&pio 15 0>; + status = "okay"; + }; ++ ++&nand { ++ status = "okay"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&nand_pins_default>; ++ ++ partition@0 { ++ label = "preloader"; ++ reg = <0x0 0x40000>; ++ read-only; ++ }; ++ ++ partition@1 { ++ label = "u-boot"; ++ reg = <0x40000 0x80000>; ++ read-only; ++ }; ++ ++ partition@2 { ++ label = "u-boot-env"; ++ reg = <0xc0000 0x40000>; ++ read-only; ++ }; ++ ++ partition@3 { ++ label = "factory"; ++ reg = <0x100000 0x40000>; ++ read-only; ++ }; ++ ++ partition@4 { ++ label = "kernel"; ++ reg = <0x140000 0x2000000>; ++ }; ++ ++ partition@4 { ++ label = "kernel2"; ++ reg = <0x2140000 0x2000000>; ++ }; ++ ++ partition@5 { ++ label = "rootfs"; ++ reg = <0x4140000 0x1000000>; ++ }; ++ ++ partition@6 { ++ label = "usrdata"; ++ reg = <0x5140000 0x9f80000>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index f405ec7..76d603a 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -31,25 +31,65 @@ + #size-cells = <0>; + enable-method = "mediatek,mt6589-smp"; + +- cpu@0 { ++ cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x0>; ++ clocks = <&infracfg CLK_INFRA_CPUSEL>, ++ <&apmixedsys CLK_APMIXED_MAINPLL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points = < ++ 598000 1150000 ++ 747500 1150000 ++ 1040000 1150000 ++ 1196000 1200000 ++ 1300000 1300000 ++ >; + }; +- cpu@1 { ++ cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x1>; ++ clocks = <&infracfg CLK_INFRA_CPUSEL>, ++ <&apmixedsys CLK_APMIXED_MAINPLL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points = < ++ 598000 1150000 ++ 747500 1150000 ++ 1040000 1150000 ++ 1196000 1200000 ++ 1300000 1300000 ++ >; + }; +- cpu@2 { ++ cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x2>; ++ clocks = <&infracfg CLK_INFRA_CPUSEL>, ++ <&apmixedsys CLK_APMIXED_MAINPLL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points = < ++ 598000 1150000 ++ 747500 1150000 ++ 1040000 1150000 ++ 1196000 1200000 ++ 1300000 1300000 ++ >; + }; +- cpu@3 { ++ cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x3>; ++ clocks = <&infracfg CLK_INFRA_CPUSEL>, ++ <&apmixedsys CLK_APMIXED_MAINPLL>; ++ clock-names = "cpu", "intermediate"; ++ operating-points = < ++ 598000 1150000 ++ 747500 1150000 ++ 1040000 1150000 ++ 1196000 1200000 ++ 1300000 1300000 ++ >; + }; + }; + +@@ -300,7 +340,7 @@ + clocks = <&pericfg CLK_PERI_NFI>, <&pericfg CLK_PERI_NFI_ECC>, + <&pericfg CLK_PERI_NFI_PAD>; + clock-names = "nfi_clk", "nfiecc_clk", "pad_clk"; +- nand-on-flash-bbt; ++ // nand-on-flash-bbt; + status = "disabled"; + }; + +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index b1f8a73..baf945e 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -81,6 +81,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 + bool "Mediatek MT8173 CPUFreq support" + depends on ARCH_MEDIATEK && REGULATOR +diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +index c0af1a1..e198752 100644 +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -57,6 +57,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o + 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 +diff --git a/drivers/cpufreq/mt7623-cpufreq.c b/drivers/cpufreq/mt7623-cpufreq.c +new file mode 100644 +index 0000000..8d154ce +--- /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); +-- +1.7.10.4 + diff --git a/target/linux/mediatek/patches-4.4/0078-arm-mediatek-make-a7-timer-work.patch b/target/linux/mediatek/patches-4.4/0078-arm-mediatek-make-a7-timer-work.patch new file mode 100644 index 0000000000..69117dc76b --- /dev/null +++ b/target/linux/mediatek/patches-4.4/0078-arm-mediatek-make-a7-timer-work.patch @@ -0,0 +1,52 @@ +From e722886f122fd3dd6240160f21937d2f21e9d910 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 31 Mar 2016 06:07:01 +0200 +Subject: [PATCH 78/78] arm: mediatek: make a7 timer work Signed-off-by: John + Crispin + +--- + arch/arm/boot/dts/mt7623.dtsi | 2 ++ + arch/arm/mach-mediatek/Kconfig | 1 + + arch/arm/mach-mediatek/mediatek.c | 1 + + 3 files changed, 4 insertions(+) + +diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi +index 76d603a..cd08b6e 100644 +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -120,6 +120,8 @@ + , + , + ; ++ clock-frequency = <13000000>; ++ arm,cpu-registers-not-fw-configured; + }; + + topckgen: power-controller@10000000 { +diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig +index a7fef77..2c05bc31 100644 +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -24,6 +24,7 @@ config MACH_MT6592 + config MACH_MT7623 + bool "MediaTek MT7623 SoCs support" + default ARCH_MEDIATEK ++ select HAVE_ARM_ARCH_TIMER + select MIGHT_HAVE_PCI + + config MACH_MT8127 +diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c +index bcfca37..7553a8c 100644 +--- a/arch/arm/mach-mediatek/mediatek.c ++++ b/arch/arm/mach-mediatek/mediatek.c +@@ -29,6 +29,7 @@ static void __init mediatek_timer_init(void) + void __iomem *gpt_base; + + if (of_machine_is_compatible("mediatek,mt6589") || ++ of_machine_is_compatible("mediatek,mt7623") || + of_machine_is_compatible("mediatek,mt8135") || + of_machine_is_compatible("mediatek,mt8127")) { + /* turn on GPT6 which ungates arch timer clocks */ +-- +1.7.10.4 +