mediatek: update patches
authorJohn Crispin <john@openwrt.org>
Tue, 22 Mar 2016 21:14:51 +0000 (21:14 +0000)
committerJohn Crispin <john@openwrt.org>
Tue, 22 Mar 2016 21:14:51 +0000 (21:14 +0000)
fixes trgmii on old eco and adds nand support

Signed-off-by: John Crispin <blogic@openwrt.org>
SVN-Revision: 49066

70 files changed:
target/linux/mediatek/base-files/etc/board.d/02_network
target/linux/mediatek/config-4.4
target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
target/linux/mediatek/patches-4.4/0052-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0052-net-out-of-tree-fixes.patch [deleted file]
target/linux/mediatek/patches-4.4/0053-dont-disable-clocks.patch [deleted file]
target/linux/mediatek/patches-4.4/0053-net-mediatek-unlock-on-error-in-mtk_tx_map.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0054-net-mediatek-use-dma_addr_t-correctly.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0055-net-mediatek-remove-incorrect-dma_mask-assignment.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0056-net-mediatek-check-device_reset-return-code.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0057-net-mediatek-out-of-tree-fixes.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0058-dont-disable-clocks.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0059-mtd-nand-add-an-mtd_to_nand-helper.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0060-mtd-nand-add-nand_to_mtd-helper.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0061-mtd-nand-add-helpers-to-access-priv.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0062-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0063-mtd-add-get-set-of_node-flash_node-helpers.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0064-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0065-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch [new file with mode: 0644]
target/linux/mediatek/patches-4.4/0066-net-next-mediatek-mtk_cal_txd_req-returns-bad-value.patch [new file with mode: 0644]

index 93d3d1e43546ef374f29f231717837c9d98beb4b..b936d0e1502f9daf2e28d8f6d6eeffcdea77899f 100755 (executable)
@@ -11,9 +11,9 @@ mediatek_setup_interfaces()
 
        case $board in
        mt7623_evb)
-               ucidef_set_interfaces_lan_wan "eth1" "eth0"
+               ucidef_set_interfaces_lan_wan "eth0" "eth1"
                ucidef_add_switch "switch0" \
-                       "0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "5@eth1" "6@eth0"
+                       "0:lan" "1:lan" "2:lan" "3:lan" "4:wan" "6@eth0" "5@eth1"
                ;;
        esac
 }
index a236d74576f9f945e63bda41e81e72d3382b2bc6..259e65cb36ba55498178862cc5427628a188d51d 100644 (file)
@@ -56,7 +56,7 @@ CONFIG_CLKSRC_MMIO=y
 CONFIG_CLKSRC_OF=y
 CONFIG_CLKSRC_PROBE=y
 CONFIG_CLONE_BACKWARDS=y
-CONFIG_CMDLINE="earlyprintk console=ttyS0,115200"
+CONFIG_CMDLINE="earlyprintk console=ttyS0,115200 block2mtd=/dev/mmcblk0,65536,eMMC,5 mtdparts=eMMC:256k(mbr),512k(uboot),256k(config),256k(factory),32M(bootimg),32M(recovery),1024M(rootfs),2048M(usrdata),-(bmtpool)"
 CONFIG_CMDLINE_FORCE=y
 CONFIG_COMMON_CLK=y
 CONFIG_COMMON_CLK_MEDIATEK=y
@@ -278,6 +278,7 @@ CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 # CONFIG_MMC_TIFM_SD is not set
 CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_M25P80=y
 CONFIG_MTD_SPI_NOR=y
 CONFIG_MTK_INFRACFG=y
index 8917ac328f55b8c19fc145c74e9e3b43a66ee4d0..239e434dbb57221d5b037dd1d9339bee8c27591e 100644 (file)
@@ -1,7 +1,7 @@
 From c30a296646a42302065ba452abe95b0b4b550883 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Sun, 27 Jul 2014 09:38:50 +0100
-Subject: [PATCH 01/53] NET: multi phy support
+Subject: [PATCH 01/66] NET: multi phy support
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 ---
index 53781dc3befc6254ab7fc5654a9dbbdc7f397000..f99496ae62918b1052dcbd848fdfcd07bf9764ed 100644 (file)
@@ -1,7 +1,7 @@
 From 2c93328ed05061a50e3bd4111379dbcf6946d3ac Mon Sep 17 00:00:00 2001
 From: James Liao <jamesjj.liao@mediatek.com>
 Date: Wed, 30 Dec 2015 14:41:43 +0800
-Subject: [PATCH 02/53] soc: mediatek: Separate scpsys driver common code
+Subject: [PATCH 02/66] 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.
index 43ed31c816fa79521662800a0b174e52a77a46ce..0fc766cada7e016494a5ff80df0fb4bc11cd427d 100644 (file)
@@ -1,7 +1,7 @@
 From c359272f86805259c5801385d60fdeea9d629cf9 Mon Sep 17 00:00:00 2001
 From: James Liao <jamesjj.liao@mediatek.com>
 Date: Wed, 30 Dec 2015 14:41:44 +0800
-Subject: [PATCH 03/53] soc: mediatek: Init MT8173 scpsys driver earlier
+Subject: [PATCH 03/66] 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
index 79f849f3c9e5be2478eb04a781358b46d0949665..1b45c441616e813a91786e650ebe8003bc1dcac6 100644 (file)
@@ -1,7 +1,7 @@
 From f371844374fff273f817d6c43f679606417af59e Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Wed, 30 Dec 2015 14:41:45 +0800
-Subject: [PATCH 04/53] soc: mediatek: Add MT2701 power dt-bindings
+Subject: [PATCH 04/66] soc: mediatek: Add MT2701 power dt-bindings
 
 Add power dt-bindings for MT2701.
 
index 6bbeecbb001b9d0a96d818f545ef61504b89b34e..505292e6a66069aa33b42bfef44ca0f78eb3d3dc 100644 (file)
@@ -1,7 +1,7 @@
 From c6711565985f359d7d3c05f01f081e4c216902de Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Wed, 30 Dec 2015 14:41:46 +0800
-Subject: [PATCH 05/53] soc: mediatek: Add MT2701/MT7623 scpsys driver
+Subject: [PATCH 05/66] soc: mediatek: Add MT2701/MT7623 scpsys driver
 
 Add scpsys driver for MT2701 and MT7623.
 
index 6b00dc2274e2d673ef255453810be3b1d266d4a8..e02b7a546b2dbb8b50302cd05c523728bd66363f 100644 (file)
@@ -1,7 +1,7 @@
 From 0c39bcd17fa6ce723f56ad3756b4bb36c4690342 Mon Sep 17 00:00:00 2001
 From: James Liao <jamesjj.liao@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:17 +0800
-Subject: [PATCH 06/53] clk: mediatek: Refine the makefile to support multiple
+Subject: [PATCH 06/66] clk: mediatek: Refine the makefile to support multiple
  clock drivers
 
 Add a Kconfig to define clock configuration for each SoC, and
index 3d6bc709cff3e3e71b8e4672b24d8760fb83d729..c562647e366de0430835f4ed8ccc9fff9072880c 100644 (file)
@@ -1,7 +1,7 @@
 From d7e96f87f66c571e9f4171ecd89c656fbd2de89b Mon Sep 17 00:00:00 2001
 From: James Liao <jamesjj.liao@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:18 +0800
-Subject: [PATCH 07/53] dt-bindings: ARM: Mediatek: Document bindings for
+Subject: [PATCH 07/66] dt-bindings: ARM: Mediatek: Document bindings for
  MT2701
 
 This patch adds the binding documentation for apmixedsys, bdpsys,
index 0cbe27ddbbab7011e4702500dd1b08ad05186b35..6e80e1adc4f1dafb058b54fd1e9a8d263038aac4 100644 (file)
@@ -1,7 +1,7 @@
 From 2fcbc15da2f13164e0851b9c7fae290249f0b44d Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:19 +0800
-Subject: [PATCH 08/53] clk: mediatek: Add dt-bindings for MT2701 clocks
+Subject: [PATCH 08/66] clk: mediatek: Add dt-bindings for MT2701 clocks
 
 Add MT2701 clock dt-bindings, include topckgen, apmixedsys,
 infracfg, pericfg and subsystem clocks.
index f9670e45f6b9bc976821c54bdab5aba025a65ecc..e2bb10deddde04a01845cd80cea1f72e002e667d 100644 (file)
@@ -1,7 +1,7 @@
 From f2c07eaa2df52f9acac9ffc3457d3d81079dd723 Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:20 +0800
-Subject: [PATCH 09/53] clk: mediatek: Add MT2701 clock support
+Subject: [PATCH 09/66] clk: mediatek: Add MT2701 clock support
 
 Add MT2701 clock support, include topckgen, apmixedsys,
 infracfg, pericfg and subsystem clocks.
index c78d7f8aad7223aaa521894ed41fd1ef9fbb82a4..bb4eb5b84fbeb16c91b4f2fb59cd70e3762fd1a7 100644 (file)
@@ -1,7 +1,7 @@
 From 8d134cbe750b59d15c591622d81e2e9daa09f0c4 Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:21 +0800
-Subject: [PATCH 10/53] reset: mediatek: mt2701 reset controller dt-binding
+Subject: [PATCH 10/66] reset: mediatek: mt2701 reset controller dt-binding
  file
 
 Dt-binding file about reset controller is used to provide
index 64d31334d62ebfe7f410b09dedde934fb846a4c3..fc1a35ac7d45dc7fac3353c92b640cb4f39a4ad1 100644 (file)
@@ -1,7 +1,7 @@
 From b86d3303db25a8296e4c3de46ee1470f60f71b0c Mon Sep 17 00:00:00 2001
 From: Shunli Wang <shunli.wang@mediatek.com>
 Date: Tue, 5 Jan 2016 14:30:22 +0800
-Subject: [PATCH 11/53] reset: mediatek: mt2701 reset driver
+Subject: [PATCH 11/66] reset: mediatek: mt2701 reset driver
 
 In infrasys and perifsys, there are many reset
 control bits for kinds of modules. These bits are
index 81e67ca4cad6f9d57619a801a042ef4959bc4038..6c7632ee9fbc6e2c0e42f4bb3643cda465e0c61b 100644 (file)
@@ -1,7 +1,7 @@
 From 3b5df542d52b13a1b20d25311fa4c4029a3b83af Mon Sep 17 00:00:00 2001
 From: Erin Lo <erin.lo@mediatek.com>
 Date: Mon, 28 Dec 2015 15:09:02 +0800
-Subject: [PATCH 12/53] ARM: mediatek: Add MT2701 config options for mediatek
+Subject: [PATCH 12/66] ARM: mediatek: Add MT2701 config options for mediatek
  SoCs.
 
 The upcoming MTK pinctrl driver have a big pin table for each SoC
index 35b613710fa4f71db43763f2e0960d70ae4751d1..11f2cf9ea9a3876a87829e117f635422d001aa66 100644 (file)
@@ -1,7 +1,7 @@
 From 1a254735cad9db5c8605c972b0f16b3929dc0d6e Mon Sep 17 00:00:00 2001
 From: Biao Huang <biao.huang@mediatek.com>
 Date: Mon, 28 Dec 2015 15:09:03 +0800
-Subject: [PATCH 13/53] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 13/66] dt-bindings: mediatek: Modify pinctrl bindings for
  mt2701
 
 Signed-off-by: Biao Huang <biao.huang@mediatek.com>
index 77696b37d7d3a29fb48ab4eb1ddf68e31a91b56d..58de1fe217205dd20855d52943e4cc3fa825fd4b 100644 (file)
@@ -1,7 +1,7 @@
 From 416720ba33d4fd7d3166c17be7c13651cc08d408 Mon Sep 17 00:00:00 2001
 From: Biao Huang <biao.huang@mediatek.com>
 Date: Mon, 28 Dec 2015 15:09:04 +0800
-Subject: [PATCH 14/53] pinctrl: dt bindings: Add pinfunc header file for
+Subject: [PATCH 14/66] pinctrl: dt bindings: Add pinfunc header file for
  mt2701
 
 Add pinfunc header file, mt2701 related dts will include it
index 3f9108738540b79bc3092db7185d585b4b416d52..974f39ea3a33fa48f930bf11e7ff1133e56f4914 100644 (file)
@@ -1,7 +1,7 @@
 From ddc72b659b3642d0496dee4e1ee39416ca008053 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Thu, 7 Jan 2016 23:42:06 +0100
-Subject: [PATCH 15/53] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 15/66] dt-bindings: mediatek: Modify pinctrl bindings for
  mt7623
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
index 0ed28c3340e8b6731d2c5ec9868de77c60c29656..fca1fab9f3d2569f40d9e0b3b76a1780cb139baa 100644 (file)
@@ -1,7 +1,7 @@
 From 1255eaacd6cc9d1fa6bb33185380efed22008baf Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Sat, 27 Jun 2015 13:13:05 +0200
-Subject: [PATCH 16/53] pinctrl: dt bindings: Add pinctrl file for mt7623
+Subject: [PATCH 16/66] pinctrl: dt bindings: Add pinctrl file for mt7623
 
 Add the driver and header files required to make pinctrl work on MediaTek
 MT7623.
index fb6e417a46db26511cea8d1e9d99fc5d4a689014..685a496f85697eac44a2396017f5ef8b3dff3c4f 100644 (file)
@@ -1,7 +1,7 @@
 From 294cf90337d70ad74edf147180bbeef837298bd0 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 6 Jan 2016 20:06:49 +0100
-Subject: [PATCH 17/53] clk: add hifsys reset
+Subject: [PATCH 17/66] clk: add hifsys reset
 
 Hi,
 
index 981d71f7abebf6694e3572fe48f68d5800a643b3..216d388572b5844c87671e43711b0b1b5cc94325 100644 (file)
@@ -1,7 +1,7 @@
 From 84d37aeef94deae3ce87e677f6016a5d980429e8 Mon Sep 17 00:00:00 2001
 From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
 Date: Tue, 17 Nov 2015 17:18:39 +0800
-Subject: [PATCH 18/53] dt-bindings: Add a binding for Mediatek xHCI host
+Subject: [PATCH 18/66] dt-bindings: Add a binding for Mediatek xHCI host
  controller
 
 add a DT binding documentation of xHCI host controller for the
index 05e000b5c5b134f7819986ea397a360f341b5e53..188728d779a22c4917021da45abb4aac3da25404 100644 (file)
@@ -1,7 +1,7 @@
 From 651d8fff94718c7e48b8a40d7774878eb8ed62ee Mon Sep 17 00:00:00 2001
 From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
 Date: Tue, 17 Nov 2015 17:18:40 +0800
-Subject: [PATCH 19/53] xhci: mediatek: support MTK xHCI host controller
+Subject: [PATCH 19/66] 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
index d52b8ebe6c2ebdda9195cc4cb63324e3deb26d7e..e9ce56e3afd674cb5e6d0e643e53d0f51e68dd27 100644 (file)
@@ -1,7 +1,7 @@
 From 31a22fbd0d3b187be61c4c5d22b19c95abb327c3 Mon Sep 17 00:00:00 2001
 From: "chunfeng.yun@mediatek.com" <chunfeng.yun@mediatek.com>
 Date: Tue, 17 Nov 2015 17:18:41 +0800
-Subject: [PATCH 20/53] arm64: dts: mediatek: add xHCI & usb phy for mt8173
+Subject: [PATCH 20/66] arm64: dts: mediatek: add xHCI & usb phy for mt8173
 
 add xHCI and phy drivers for MT8173-EVB
 
index 053c4fe2204cdd50b2051ec6c2aa17b17924ea9c..b7aae926c8ee142c2c54faf6ea68936a4cb48f1a 100644 (file)
@@ -1,7 +1,7 @@
 From 162deec293400cb132161606629654acaec7cb4b Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Tue, 5 Jan 2016 12:13:54 +0100
-Subject: [PATCH 21/53] Document: DT: Add bindings for mediatek MT7623 SoC
+Subject: [PATCH 21/66] Document: DT: Add bindings for mediatek MT7623 SoC
  Platform
 
 This adds a DT binding documentation for the MT7623 SoC from Mediatek.
index 6d76ae3a7d0384f96c696f9bd1afebc814a3dbe8..eefbffdf414f9c7868244610e53b71347b630bec 100644 (file)
@@ -1,7 +1,7 @@
 From fa5d94d6b4b314f751b1c32bb5a87a80b866d05e Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Tue, 5 Jan 2016 16:52:31 +0100
-Subject: [PATCH 22/53] soc: mediatek: add compat string for mt7623 to scpsys
+Subject: [PATCH 22/66] soc: mediatek: add compat string for mt7623 to scpsys
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 ---
index 85ff55128f7d4dcc20325dd2a7fb01a824db581e..af0a68f21339f9f8525b15fbc01dd2e9da16b8f9 100644 (file)
@@ -1,7 +1,7 @@
 From cfe366d7a20f88c7fc92faaf8b25c24e730bd40b Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Tue, 5 Jan 2016 12:16:17 +0100
-Subject: [PATCH 23/53] ARM: dts: mediatek: add MT7623 basic support
+Subject: [PATCH 23/66] ARM: dts: mediatek: add MT7623 basic support
 
 This adds basic chip support for Mediatek MT7623.
 
@@ -16,11 +16,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
  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 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
+@@ -774,6 +774,7 @@
        mt6580-evbp1.dtb \
        mt6589-aquaris5.dtb \
        mt6592-evb.dtb \
@@ -28,9 +26,6 @@ index 30bbc37..2bce370 100644
        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 @@
@@ -493,12 +488,9 @@ index 0000000..5e9381d
 +      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..1ba7790
 --- /dev/null
 +++ b/arch/arm/boot/dts/mt7623.dtsi
-@@ -0,0 +1,507 @@
+@@ -0,0 +1,508 @@
 +/*
 + * Copyright (c) 2016 MediaTek Inc.
 + * Author: John Crispin <blogic@openwrt.org>
@@ -530,6 +522,7 @@ index 0000000..1ba7790
 +      cpus {
 +              #address-cells = <1>;
 +              #size-cells = <0>;
++              enable-method = "mediatek,mt6589-smp";
 +
 +              cpu@0 {
 +                      device_type = "cpu";
@@ -1006,11 +999,9 @@ index 0000000..1ba7790
 +              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 @@ config MACH_MT6592
+@@ -21,6 +21,10 @@
        bool "MediaTek MT6592 SoCs support"
        default ARCH_MEDIATEK
  
@@ -1021,11 +1012,9 @@ index 37dd438..7fb605e 100644
  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 @@ static void __init mediatek_timer_init(void)
+@@ -46,6 +46,7 @@
  static const char * const mediatek_board_dt_compat[] = {
        "mediatek,mt6589",
        "mediatek,mt6592",
@@ -1033,6 +1022,3 @@ index d019a08..bcfca37 100644
        "mediatek,mt8127",
        "mediatek,mt8135",
        NULL,
--- 
-1.7.10.4
-
index 227483355a1951c442de1a640dbccb5b26ec4d25..53db649c25f34e117d9f57a4147ad65a7d27f32f 100644 (file)
@@ -1,12 +1,13 @@
-From 5b51a1e93ccaaec4cd90b73ee20cea219af2f151 Mon Sep 17 00:00:00 2001
+From 2ff725af8a512481d68ebd7f8ad122b1c98f3fad Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 6 Jan 2016 21:55:10 +0100
-Subject: [PATCH 24/53] dt-bindings: add MediaTek PCIe binding documentation
+Subject: [PATCH 24/66] dt-bindings: add MediaTek PCIe binding documentation
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 ---
  .../devicetree/bindings/pci/mediatek-pcie.txt      |  140 ++++++++++++++++++++
- 1 file changed, 140 insertions(+)
+ arch/arm/boot/dts/mt7623.dtsi                      |   12 ++
+ 2 files changed, 152 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie.txt
 
 diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
@@ -155,6 +156,29 @@ index 0000000..8fea3ed
 +                      status = "okay";
 +              };
 +      };
+diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi
+index 1ba7790..ec19283 100644
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -291,6 +291,18 @@
+               status = "disabled";
+       };
++      nand: nfi@1100d000 {
++              compatible = "mediatek,mt2701-nfc";
++              reg = <0 0x1100d000 0 0x1000>, <0 0x1100e000 0 0x1000>;
++              interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>,
++                           <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
++              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;
++              status = "disabled";
++      };
++
+       mmc0: mmc@11230000 {
+               compatible = "mediatek,mt7623-mmc",
+                            "mediatek,mt8135-mmc";
 -- 
 1.7.10.4
 
index 9e12892bc458675c52420e6d263f1cdcffa99b6e..36a7a85582ce3ed2909fc9eaafc31c2843bd8bd0 100644 (file)
@@ -1,7 +1,7 @@
-From fc6d1a9f37cddd79c0c149e3f1394d393ac05772 Mon Sep 17 00:00:00 2001
+From 1ac5a6be891fb934e2a864bb2e424f05315f7385 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Tue, 5 Jan 2016 20:20:04 +0100
-Subject: [PATCH 25/53] PCI: mediatek: add support for PCIe found on
+Subject: [PATCH 25/66] PCI: mediatek: add support for PCIe found on
  MT7623/MT2701
 
 Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
index 1ff25157e93a812653677be504c70b1d0f5d1953..bf26783964c4843d674f2dc59fe60456edfd3fb9 100644 (file)
@@ -1,7 +1,7 @@
-From f027ce51ff728a22428fb0b7107edf9e1bd61712 Mon Sep 17 00:00:00 2001
+From 6c5c23a6c21b1a244db79d6387db915c72f50367 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Sun, 21 Feb 2016 13:52:12 +0100
-Subject: [PATCH 26/53] scpsys: various fixes
+Subject: [PATCH 26/66] scpsys: various fixes
 
 ---
  drivers/clk/mediatek/clk-mt2701.c        |    2 ++
index 970860cff779a3a3964f069bc2aa42089fd29673..2607f93b65fbf353784c5ab2316cc0b033d7da2f 100644 (file)
@@ -1,7 +1,7 @@
-From af4a99b856b584b2426757e905e9b6f39906ce05 Mon Sep 17 00:00:00 2001
+From dadfca5daee5cb40d34542425392e694eddc5bc1 Mon Sep 17 00:00:00 2001
 From: Henry Chen <henryc.chen@mediatek.com>
 Date: Mon, 4 Jan 2016 20:02:52 +0800
-Subject: [PATCH 27/53] soc: mediatek: PMIC wrap: Clear the vldclr if state
+Subject: [PATCH 27/66] 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,
index 80bb4ff3c16420468296aae617d594bb58e28414..24521cb3691bf9ec0c31297630cc87df1b98562d 100644 (file)
@@ -1,7 +1,7 @@
-From 0742887b1d36913ccd5f6fa85649ad5eb0bfb200 Mon Sep 17 00:00:00 2001
+From 7512d9b4bf8ab222b4d542ada87368229770383f Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Tue, 5 Jan 2016 17:24:28 +0100
-Subject: [PATCH 28/53] ARM: mediatek: add MT7623 smp bringup code
+Subject: [PATCH 28/66] ARM: mediatek: add MT7623 smp bringup code
 
 Add support for booting secondary CPUs on MT7623.
 
index f8a1cd151cbaeda8442e26e3aa77cdbd157bf81b..eab74bcf3020d78f8296c93cebda52c5deafc0fc 100644 (file)
@@ -1,7 +1,7 @@
-From 5d75662fcdfef08d82710f8c4b71c58d618d4171 Mon Sep 17 00:00:00 2001
+From f8296ee9561945b5cebb570e06259b8865ef0b91 Mon Sep 17 00:00:00 2001
 From: Henry Chen <henryc.chen@mediatek.com>
 Date: Thu, 21 Jan 2016 19:04:00 +0800
-Subject: [PATCH 29/53] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of
+Subject: [PATCH 29/66] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of
  WDT_SRC_EN
 
 Since STAUPD interrupts aren't handled on mt8173, disable watchdog timeout
index 24e59e8e16c9b57d9182b4b4005e310bdf24e319..9039cc1f38278be04c02747c0112f1209d2a9b71 100644 (file)
@@ -1,7 +1,7 @@
-From f6e138ee1a8ddba7b512cafc2ecc7cd1b41781dc Mon Sep 17 00:00:00 2001
+From 977ccf394047647354093535f9b07f13a74949df Mon Sep 17 00:00:00 2001
 From: Louis Yu <louis.yu@mediatek.com>
 Date: Thu, 7 Jan 2016 20:09:43 +0800
-Subject: [PATCH 30/53] ARM: mediatek: add mt2701 smp bringup code
+Subject: [PATCH 30/66] ARM: mediatek: add mt2701 smp bringup code
 
 Add support for booting secondary CPUs on mt2701.
 
index b44413681f7f1e818779b05a7de6310a897ab68b..fd44518320236925c27ff2fccb2a3a5e8be2c5ab 100644 (file)
@@ -1,7 +1,7 @@
-From 2e4a714f60266098a2b3553d1b1f83732da90abd Mon Sep 17 00:00:00 2001
+From add1cc43bd41e6fc755852a5767e710cb3314013 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 13:12:19 +0100
-Subject: [PATCH 31/53] dt-bindings: ARM: Mediatek: add MT2701/7623 string to
+Subject: [PATCH 31/66] dt-bindings: ARM: Mediatek: add MT2701/7623 string to
  the PMIC wrapper doc
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
index 7f389b3e7d79754a831b4a3c9c70bd296d5c1546..5ee4ea42407c987b3455c1a7108f05ef46bc3f47 100644 (file)
@@ -1,7 +1,7 @@
-From b68e33cc67465ad99299947916678f8ea4418b1c Mon Sep 17 00:00:00 2001
+From 6792f25663b6064f21f033241bbeb6b023fa8ce7 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 06:42:01 +0100
-Subject: [PATCH 32/53] soc: mediatek: PMIC wrap: don't duplicate the wrapper
+Subject: [PATCH 32/66] soc: mediatek: PMIC wrap: don't duplicate the wrapper
  data
 
 As we add support for more devices struct pmic_wrapper_type will grow and
index 67ef86966cf3730683919b6221de65a07014f6b4..55881e0ffd86c72cebc7be153652dccd436e4a5b 100644 (file)
@@ -1,7 +1,7 @@
-From 45ead148322ba7be9de970a2ab6be4ed3f7ca184 Mon Sep 17 00:00:00 2001
+From b67fd66c46f7cc6ac869aafc7f920846aed6bc12 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 05:27:17 +0100
-Subject: [PATCH 33/53] soc: mediatek: PMIC wrap: add wrapper callbacks for
+Subject: [PATCH 33/66] soc: mediatek: PMIC wrap: add wrapper callbacks for
  init_reg_clock
 
 Split init_reg_clock up into SoC specific callbacks. The patch also
index aa34aaf368ec154da634aafb9dab84bda6f51e15..e73c43a38a458c57aed91631db70eefed02a8114 100644 (file)
@@ -1,7 +1,7 @@
-From b3cc9f4c4b1164ac6a0700920eca84dff81d13d7 Mon Sep 17 00:00:00 2001
+From 4dd080818ec30dd101b6248b418751de5ac508f2 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 10:12:00 +0100
-Subject: [PATCH 34/53] soc: mediatek: PMIC wrap: split SoC specific init into
+Subject: [PATCH 34/66] soc: mediatek: PMIC wrap: split SoC specific init into
  callback
 
 This patch moves the SoC specific wrapper init code into separate callback
index 9bfc90d504e7378fc231b47ed196e6c6cb4631e0..8451679633f52f477bab6e19b01f75c86023e25e 100644 (file)
@@ -1,7 +1,7 @@
-From 824563fe3d8b915714816255489fcfb2792c3a8a Mon Sep 17 00:00:00 2001
+From 72300493dbf58de75972fce86e64f4728ff9b594 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 10:14:39 +0100
-Subject: [PATCH 35/53] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a
+Subject: [PATCH 35/66] 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.
index e18f47d0c3264db5e4c7b7d314953b949ddcaa5d..7f7a905a7e3a679f0b73a8874791c83cc208e1a3 100644 (file)
@@ -1,7 +1,7 @@
-From 2028a24d161da25b827b394bdcec4deba5d2efd9 Mon Sep 17 00:00:00 2001
+From 8e28fd218224df9c1a108a0b0d4c3a2ec51ddc62 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 10:21:42 +0100
-Subject: [PATCH 36/53] soc: mediatek: PMIC wrap: SPI_WRITE needs a different
+Subject: [PATCH 36/66] 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
index e5896658e637eafb33c2a7830858b6674df8d1d8..ed225a5daf098877b42475c7c85cdb4bda0628f8 100644 (file)
@@ -1,7 +1,7 @@
-From 50bd0c152a0c33000ae88d0828f320eb603fd535 Mon Sep 17 00:00:00 2001
+From 3a01206ed5749b5469459f82f1152e3699cb8baf Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 10:48:35 +0100
-Subject: [PATCH 37/53] soc: mediatek: PMIC wrap: move wdt_src into the
+Subject: [PATCH 37/66] 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
index 025188347c74ae6a6f3fd0c7fc584986ae7177bd..ad8ff5ff3bd244c875d752191d95815c38498d9f 100644 (file)
@@ -1,7 +1,7 @@
-From f08ce6b84d2759fdff2e8ea2cf2b30b3220521ef Mon Sep 17 00:00:00 2001
+From 20f4eef2f061619762aa87d484b359c3f9a0b228 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 10:54:18 +0100
-Subject: [PATCH 38/53] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and
+Subject: [PATCH 38/66] 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
index c76e27bcaa16a8115272ed54522e465cac754f05..5cde24249d829f181ea72fe51aced135a89d78c6 100644 (file)
@@ -1,7 +1,7 @@
-From 7c6b5e5e36ccd9079a2425dc80507447784b9bb2 Mon Sep 17 00:00:00 2001
+From 023e530aa86c95352dfc97df960ee0039ef2c030 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 09:55:08 +0100
-Subject: [PATCH 39/53] soc: mediatek: PMIC wrap: add a slave specific struct
+Subject: [PATCH 39/66] 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
index 77f46e7b48e81ed009d5fd254ca594fdeadc3d11..a01f992c819254ba9b2c44784abe2054a8c80702 100644 (file)
@@ -1,7 +1,7 @@
-From b82474df3eb9fad739b2b74301b68f71011a9dc7 Mon Sep 17 00:00:00 2001
+From 5db18f42fc5584a516cb7a8b705c97a7f1c4bf1b Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 11:40:43 +0100
-Subject: [PATCH 40/53] soc: mediatek: PMIC wrap: add mt6323 slave support
+Subject: [PATCH 40/66] 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().
index 15445a7c3c8d6d1586a5fa501ad36024bef81b0b..a7e8775edf0b69768c395fe24091f1a3d8bc463b 100644 (file)
@@ -1,7 +1,7 @@
-From 84e83af30688372723a3b5713e914b0867d9a745 Mon Sep 17 00:00:00 2001
+From 444c4931cc6c2d1d9c94d8bbd4ee89438abca212 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 20 Jan 2016 12:09:14 +0100
-Subject: [PATCH 41/53] soc: mediatek: PMIC wrap: add MT2701/7623 support
+Subject: [PATCH 41/66] 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.
index e7a23f75e1e08ed243a6a7fabdaa2a09cb3e83d8..b31f063679ad096130ff7d8fabf1ca794ae0b231 100644 (file)
@@ -1,7 +1,7 @@
-From 3af0e56f55d7676fab0ba39ef599c64dd6ab4b35 Mon Sep 17 00:00:00 2001
+From eb574bce59e66295ee288de0df450a6e82bb5b56 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Sun, 10 Jan 2016 17:12:37 +0100
-Subject: [PATCH 42/53] dt-bindings: mfd: Add bindings for the MediaTek MT6323
+Subject: [PATCH 42/66] dt-bindings: mfd: Add bindings for the MediaTek MT6323
  PMIC
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
index 113c8de7b4a4cdbeee6926d05f7837dc0c20ba69..9d2379dc9697072a7032c94ebeebd63c0ff3a664 100644 (file)
@@ -1,7 +1,7 @@
-From f3d5ef8f5422de25f1c8a96b313baf60e4ce1081 Mon Sep 17 00:00:00 2001
+From 337807a89aec90a313a77336a9296ccd926c7015 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Fri, 8 Jan 2016 08:33:17 +0100
-Subject: [PATCH 43/53] mfd: mt6397: int_con and int_status may vary in
+Subject: [PATCH 43/66] mfd: mt6397: int_con and int_status may vary in
  location
 
 MT6323 has the INT_CON and INT_STATUS located at a different position.
index 30576b76b7a4cb57c9ff98bb7130317cbdafeca9..0550087533eabcbd81155acbec60b8d54e98e753 100644 (file)
@@ -1,7 +1,7 @@
-From d29ee5f0472ea3e964e698e3e9e87a83b4465e9c Mon Sep 17 00:00:00 2001
+From c6fab1574939f968257029dd75da51ab266081c9 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Fri, 8 Jan 2016 08:41:52 +0100
-Subject: [PATCH 44/53] mfd: mt6397: add support for different Slave types
+Subject: [PATCH 44/66] mfd: mt6397: add support for different Slave types
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 ---
index 7831eb613e370335d7772063228c3bd77391a9f8..3b8a752c1c96a0ef41c37e35376559697835eede 100644 (file)
@@ -1,7 +1,7 @@
-From 926910e33f5de67f229ac089ab5f3de1bfd117f9 Mon Sep 17 00:00:00 2001
+From d3d044cff01ef835ef36b6f7d22b19fe47b65e46 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Fri, 8 Jan 2016 04:09:43 +0100
-Subject: [PATCH 45/53] mfd: mt6397: add MT6323 support to MT6397 driver
+Subject: [PATCH 45/66] mfd: mt6397: add MT6323 support to MT6397 driver
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 ---
index b6b237dc45fa8b0e9dea755617484d2f88987a14..f5b7f2363dc147ad2f1423d1ab7614faa91c2572 100644 (file)
@@ -1,7 +1,7 @@
-From 3900467f0f0470f889b9e6cdfd7dc4cf460e8d41 Mon Sep 17 00:00:00 2001
+From 9877cc960be38947b6bce371e3dce2be185dc337 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Sun, 10 Jan 2016 17:31:46 +0100
-Subject: [PATCH 46/53] regulator: Add document for MT6323 regulator
+Subject: [PATCH 46/66] regulator: Add document for MT6323 regulator
 
 Signed-off-by: John Crispin <blogic@openwrt.org>
 Cc: devicetree@vger.kernel.org
index 36702dca34dc6d37347207f4a729964ba28db833..37d7fd1904f6e68669a54429ba98fadf5298ef70 100644 (file)
@@ -1,7 +1,7 @@
-From eb0a8e236431bf233267299ba797e2269b6e19ea Mon Sep 17 00:00:00 2001
+From 34163b123140c2668d52385bb9ab501cb025f943 Mon Sep 17 00:00:00 2001
 From: Chen Zhong <chen.zhong@mediatek.com>
 Date: Fri, 8 Jan 2016 04:17:37 +0100
-Subject: [PATCH 47/53] regulator: mt6323: Add support for MT6323 regulator
+Subject: [PATCH 47/66] 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
index 43e8795ae00c66e7056f2ad6a042c2ab11259ff2..34a033e4503b889a9ee5c008f45f18e94c21bcb2 100644 (file)
@@ -1,7 +1,7 @@
-From 32f95a0bc03886b38a53569466d5bee4a6d66875 Mon Sep 17 00:00:00 2001
+From 13e64dd7fb55bf3948005863a494646874c22c1b Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 2 Mar 2016 07:18:52 +0100
-Subject: [PATCH 48/53] net-next: mediatek: document MediaTek SoC ethernet
+Subject: [PATCH 48/66] net-next: mediatek: document MediaTek SoC ethernet
  binding
 
 This adds the binding documentation for the MediaTek Ethernet
index 5bfc00f0682324fb2046d5e174e03f8793a15db8..a3e3efd9993ccb64d33fbb3c2fced4ae1333f0ac 100644 (file)
@@ -1,7 +1,7 @@
-From 873a5623ef43181f07b58328131e98fee5bc3d64 Mon Sep 17 00:00:00 2001
+From ce02aa9cebf5805427b874201b4ccb2a5e770597 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 2 Mar 2016 04:27:10 +0100
-Subject: [PATCH 49/53] net-next: mediatek: add support for MT7623 ethernet
+Subject: [PATCH 49/66] 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
index 2358b6a8c0bdd29dbde4472e4f0181bcfd627a06..d2bd7a866ff9e627a692ff99d0f30c5bb99fa104 100644 (file)
@@ -1,7 +1,7 @@
-From 093d38375d35e6fa0f54c2c30b517a73d8448710 Mon Sep 17 00:00:00 2001
+From e39d6547a391e3e32f88b6dde16dee271e905562 Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 2 Mar 2016 04:32:43 +0100
-Subject: [PATCH 50/53] net-next: mediatek: add Kconfig and Makefile
+Subject: [PATCH 50/66] net-next: mediatek: add Kconfig and Makefile
 
 This patch adds the Makefile and Kconfig required to make the driver build.
 
index deb6eff45314a63e8c3a45faaa0be247d97ceb35..fe1f4af182ece51f70fb9493d70b1294138c0810 100644 (file)
@@ -1,7 +1,7 @@
-From 3180cf4f325411f796468e12d524fe6354ded274 Mon Sep 17 00:00:00 2001
+From 0ab2afe39e683c82b5c176047e81eeb2d1b9119c Mon Sep 17 00:00:00 2001
 From: John Crispin <blogic@openwrt.org>
 Date: Wed, 2 Mar 2016 04:34:04 +0100
-Subject: [PATCH 51/53] net-next: mediatek: add an entry to MAINTAINERS
+Subject: [PATCH 51/66] 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-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
new file mode 100644 (file)
index 0000000..5e54291
--- /dev/null
@@ -0,0 +1,32 @@
+From 7809955b6f4319773a5ef561a5e98c61dc891a47 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+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 <dan.carpenter@oracle.com>
+---
+ 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/0052-net-out-of-tree-fixes.patch b/target/linux/mediatek/patches-4.4/0052-net-out-of-tree-fixes.patch
deleted file mode 100644 (file)
index 10d9d71..0000000
+++ /dev/null
@@ -1,2409 +0,0 @@
-From 242801fc94db9ceb1e3e2a8b19fb2c57122e53f3 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 21 Mar 2016 16:36:22 +0100
-Subject: [PATCH] net: out of tree fixes
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- 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  |  966 +++++++++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.c      |  808 ++++++++++++++++++++++
- drivers/net/ethernet/mediatek/mt7530.h      |   20 +
- drivers/net/ethernet/mediatek/mtk_eth_soc.c |   59 +-
- drivers/net/ethernet/mediatek/mtk_eth_soc.h |    5 +
- lib/dynamic_queue_limits.c                  |    6 +-
- 10 files changed, 2110 insertions(+), 47 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 1ba7790..5926e14 100644
---- a/arch/arm/boot/dts/mt7623.dtsi
-+++ b/arch/arm/boot/dts/mt7623.dtsi
-@@ -440,23 +440,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>,
-+                       <&ethsys CLK_ETHSYS_ESW>,
-+                       <&ethsys CLK_ETHSYS_GP2>,
-+                       <&ethsys CLK_ETHSYS_GP1>;
-+              clock-names = "ethif", "esw", "gp2", "gp1";
-               interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>;
-               power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
-+              resets = <&ethsys 6>;
-+              reset-names = "eth";
-+
-               mediatek,ethsys = <&ethsys>;
-+              mediatek,pctl = <&syscfg_pctl_a>;
-+
-               mediatek,switch = <&gsw>;
-               #address-cells = <1>;
-@@ -468,6 +475,8 @@
-                       compatible = "mediatek,eth-mac";
-                       reg = <0>;
-+                      phy-handle = <&phy4>;
-+
-                       status = "disabled";
-               };
-@@ -475,6 +484,7 @@
-                       compatible = "mediatek,eth-mac";
-                       reg = <1>;
-+                      phy-handle = <&phy5>;
-                       status = "disabled";
-               };
-       
-@@ -482,6 +492,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";
-@@ -491,14 +511,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>,
--                       <&ethsys CLK_ETHSYS_ESW>,
--                       <&ethsys CLK_ETHSYS_GP2>,
--                       <&ethsys CLK_ETHSYS_GP1>;
--              clock-names = "trgpll", "esw", "gp2", "gp1";
-+              resets = <&ethsys 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 = <&ethsys>;
-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 <blogic@openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
-+ */
-+
-+#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..78c36c7
---- /dev/null
-+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c
-@@ -0,0 +1,966 @@
-+/*   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 <blogic@openwrt.org>
-+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
-+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_gpio.h>
-+#include <linux/clk.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/mii.h>
-+#include <linux/interrupt.h>
-+#include <linux/netdevice.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/phy.h>
-+#include <linux/ethtool.h>
-+#include <linux/version.h>
-+#include <linux/atomic.h>
-+
-+#include "mtk_eth_soc.h"
-+#include "gsw_mt7620.h"
-+#include "mt7530.h"
-+
-+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);
-+}
-+
-+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, MT7530_SYS_INT_STS);
-+
-+      for (i = 0; i < 5; i++) {
-+              unsigned int link;
-+
-+              if ((reg & BIT(i)) == 0)
-+                      continue;
-+
-+              link = mt7530_mdio_r32(gsw, MT7530_PMSR_P(i)) & 0x1;
-+
-+              if (link)
-+                      dev_info(gsw->dev, "port %d link up\n", i);
-+              else
-+                      dev_info(gsw->dev, "port %d link down\n", i);
-+      }
-+
-+      mt7530_mdio_w32(gsw, MT7530_SYS_INT_STS, 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);
-+}
-+
-+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 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);
-+
-+      /* Enable Training Mode in MT7530 */
-+      mt7530_mdio_m32(gsw, 0, 0xC0000000, 0x7A40);
-+
-+      /* Adjust RXC delay in MT7623 */
-+      read_data = 0x0;
-+      err_total_flag = 0;
-+      while (err_total_flag == 0 && read_data != 0x68) {
-+              /* 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;
-+
-+      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;
-+
-+      /* Calibration begin */
-+      mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x40);
-+
-+      /* RX clock gating in MT7530 */
-+      mt7530_mdio_m32(gsw, 0x3fffffff, 0, TRGMII_7530_base + 0x04);
-+
-+      /* Set TX OE edge in  MT7530 */
-+      mt7530_mdio_m32(gsw, 0, 0x2000, TRGMII_7530_base + 0x78);
-+
-+      /* Assert RX  reset in MT7530 */
-+      mt7530_mdio_m32(gsw, 0, 0x80000000, TRGMII_7530_base);
-+
-+      /* Release RX reset in MT7530 */
-+      mt7530_mdio_m32(gsw, 0x7fffffff, 0, TRGMII_7530_base);
-+
-+      /* Disable RX clock gating in MT7530 */
-+      mt7530_mdio_m32(gsw, 0, 0xC0000000, TRGMII_7530_base + 0x04);
-+
-+      /* Enable Training Mode in MT7623 */
-+      mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x40);
-+      if (gsw->trgmii_force == 2000)
-+              mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x40);
-+      else
-+              mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x40);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x078);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x50);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x58);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x60);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x68);
-+      mtk_switch_m32(gsw, 0xfffff0ff, 0, TRGMII_7623_base + 0x70);
-+      mtk_switch_m32(gsw, 0x00000800, 0, TRGMII_7623_base + 0x78);
-+
-+      /* Adjust RXC delay in MT7530 */
-+      err_total_flag = 0;
-+      read_data = 0x0;
-+      while (err_total_flag == 0 && (read_data != 0x68)) {
-+              /* Enable EDGE CHK in MT7530 */
-+              for (i = 0; i < 5; i++) {
-+                      mt7530_mdio_m32(gsw, 0x4fffffff, 0x40000000,
-+                                      TRGMII_7530_RD_0 + i * 8);
-+                      wait_loop(gsw);
-+
-+                      /* 2nd Disable EDGE CHK in MT7530 */
-+                      err_cnt[i] = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8);
-+                      err_cnt[i] >>= 8;
-+                      err_cnt[i] &= 0x0000ff0f;
-+
-+                      rd_wd = err_cnt[i] >> 8;
-+                      rd_wd &= 0x000000ff;
-+
-+                      err_cnt[i] &= 0x0000000f;
-+                      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 */
-+                      mt7530_mdio_m32(gsw, 0x4fffffff, 0x40000000,
-+                                      TRGMII_7530_RD_0 + i * 8);
-+                      wait_loop(gsw);
-+              }
-+
-+              /* Adjust RXC delay */
-+              if (err_total_flag == 0) {
-+                      /* Assert RX reset in MT7530 */
-+                      mt7530_mdio_m32(gsw, 0, 0x80000000, TRGMII_7530_base);
-+
-+                      /* RX clock gating in MT7530 */
-+                      mt7530_mdio_m32(gsw, 0x3fffffff, 0, TRGMII_7530_base + 0x04);
-+
-+                      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]);
-+              final_tap[i] = (tap_a[i] + tap_b[i]) / 2;       
-+
-+              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)
-+{
-+      /* 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);
-+
-+      _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);
-+
-+      mt7530_mdio_m32(gsw, 0xfffffffc, 0x1, 0x7830);
-+      mt7530_mdio_m32(gsw, 0xcfffffff, 0, 0x7a40);
-+      mt7530_mdio_w32(gsw, 0x7a78, 0x55);
-+      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 */
-+      mt7530_mdio_m32(gsw, 0, BIT(31), 0x7a00);
-+      mdelay(1);
-+
-+      mt7530_mdio_m32(gsw, ~BIT(31), 0, 0x7a00);
-+      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);
-+      printk("%s:%s[%d]reset_switch\n", __FILE__, __func__, __LINE__);
-+
-+      /* 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);
-+
-+      xtal_mode = mt7530_mdio_r32(gsw, MT7530_HWTRAP);
-+      xtal_mode >>= HWTRAP_XTAL_SHIFT;
-+      xtal_mode &= HWTRAP_XTAL_MASK;
-+      if (xtal_mode == MT7623_XTAL_40) {
-+              /* 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);
-+      }
-+
-+      /* RGMII */
-+      _mtk_mdio_write(gsw->eth, 0, 14, 0x1);
-+
-+      /* set MT7530 central align */
-+      mt7530_mdio_m32(gsw, ~BIT(0), BIT(1), MT7530_P6ECR);
-+      mt7530_mdio_m32(gsw, ~BIT(30), 0, MT7530_TRGMII_TXCTRL);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TCK_CTRL, 0x855);
-+
-+      /* delay setting for 10/1000M */
-+      mt7530_mdio_w32(gsw, MT7530_P5RGMIIRXCR, 0x104);
-+      mt7530_mdio_w32(gsw, MT7530_P5RGMIITXCR, 0x10);
-+
-+      /* lower Tx Driving */
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD0_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD1_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD2_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD3_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD4_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_TRGMII_TD5_ODT, 0x88);
-+      mt7530_mdio_w32(gsw, MT7530_IO_DRV_CR, 0x11);
-+
-+      /* Set MT7623/MT7683 TX Driving */
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TD0_ODT);
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TD0_ODT);
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TD0_ODT);
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TD0_ODT);
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TXCTL_ODT);
-+      mtk_switch_w32(gsw, 0x88, GSW_TRGMII_TCK_ODT);
-+
-+//    mt7530_trgmii_clock_setting(gsw, xtal_mode);
-+
-+      /* 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 &= ~BIT(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;
-+      eth->sw_priv = gsw;
-+      gsw->eth = eth;
-+
-+      mt7623_hw_init(eth, gsw, np);
-+
-+      request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0,
-+                           "gsw", eth);
-+      mt7530_mdio_w32(gsw, MT7530_SYS_INT_EN, 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->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 <blogic@openwrt.org>");
-+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 <blogic@openwrt.org>
-+ */
-+
-+#include <linux/if.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/if_ether.h>
-+#include <linux/skbuff.h>
-+#include <linux/netdevice.h>
-+#include <linux/netlink.h>
-+#include <linux/bitops.h>
-+#include <net/genetlink.h>
-+#include <linux/switch.h>
-+#include <linux/delay.h>
-+#include <linux/phy.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/lockdep.h>
-+#include <linux/workqueue.h>
-+#include <linux/of_device.h>
-+
-+#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 <blogic@openwrt.org>
-+ */
-+
-+#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 ba3afa5..62058a2 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,20 @@ 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)
- {
-+      return;
-+
-       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;
--
-+      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));
--
--      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 +180,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 +621,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
-       spin_unlock_irqrestore(&eth->page_lock, flags);
--      netdev_sent_queue(dev, skb->len);
-       skb_tx_timestamp(skb);
-       ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-@@ -882,7 +868,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];
-       }
-@@ -1249,6 +1234,8 @@ static int mtk_open(struct net_device *dev)
-       phy_start(mac->phy_dev);
-       netif_start_queue(dev);
-+      netif_carrier_on(dev);
-+
-       return 0;
- }
-@@ -1281,6 +1268,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);
-@@ -1326,6 +1314,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)
-@@ -1358,6 +1347,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;
- }
-@@ -1464,11 +1455,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);
-@@ -1561,7 +1554,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));
-@@ -1733,6 +1725,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 */
-diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c
-index f346715..b04f8e6 100644
---- a/lib/dynamic_queue_limits.c
-+++ b/lib/dynamic_queue_limits.c
-@@ -23,8 +23,10 @@ void dql_completed(struct dql *dql, unsigned int count)
-       num_queued = ACCESS_ONCE(dql->num_queued);
-       /* Can't complete more than what's in queue */
--      BUG_ON(count > num_queued - dql->num_completed);
--
-+      if (count > num_queued - dql->num_completed) {
-+              printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
-+              count = 0;
-+      }
-       completed = dql->num_completed + count;
-       limit = dql->limit;
-       ovlimit = POSDIFF(num_queued - dql->num_completed, limit);
--- 
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0053-dont-disable-clocks.patch b/target/linux/mediatek/patches-4.4/0053-dont-disable-clocks.patch
deleted file mode 100644 (file)
index 9ec5c89..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 308cdd2b743a5e01b26d79c8fb89e513dea09856 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 23 Jun 2015 23:46:00 +0200
-Subject: [PATCH 53/53] 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/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
new file mode 100644 (file)
index 0000000..89ad003
--- /dev/null
@@ -0,0 +1,29 @@
+From a2559aaca7c4a9b80699147390efda51df20ac96 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+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 <dan.carpenter@oracle.com>
+---
+ 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(&eth->page_lock, flags);
++
+       return -ENOMEM;
+ }
+-- 
+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
new file mode 100644 (file)
index 0000000..d00d9b6
--- /dev/null
@@ -0,0 +1,35 @@
+From ca4d9b6f3476e18e3136e488debdb35cd402d8d3 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+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 <arnd@arndb.de>
+---
+ 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-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0055-net-mediatek-remove-incorrect-dma_mask-assignment.patch
new file mode 100644 (file)
index 0000000..4bf0947
--- /dev/null
@@ -0,0 +1,36 @@
+From 9d602a7040c0fe9c81f2beffb3c277442a6d9ea2 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+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 <arnd@arndb.de>
+---
+ 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-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0056-net-mediatek-check-device_reset-return-code.patch
new file mode 100644 (file)
index 0000000..00e5c8b
--- /dev/null
@@ -0,0 +1,38 @@
+From b461f1a8dfcf32f289a559b6eba4e784b37d121c Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+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 <arnd@arndb.de>
+---
+ 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-net-mediatek-out-of-tree-fixes.patch b/target/linux/mediatek/patches-4.4/0057-net-mediatek-out-of-tree-fixes.patch
new file mode 100644 (file)
index 0000000..1e78d49
--- /dev/null
@@ -0,0 +1,2469 @@
+From cee958b55f35f953481c2ddf9609dbd018ef5979 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 21 Mar 2016 16:36:22 +0100
+Subject: [PATCH 57/66] net: mediatek: out of tree fixes
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ 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>,
++                       <&ethsys CLK_ETHSYS_ESW>,
++                       <&ethsys CLK_ETHSYS_GP2>,
++                       <&ethsys CLK_ETHSYS_GP1>;
++              clock-names = "ethif", "esw", "gp2", "gp1";
+               interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>;
+               power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
++              resets = <&ethsys 6>;
++              reset-names = "eth";
++
+               mediatek,ethsys = <&ethsys>;
++              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>,
+-                       <&ethsys CLK_ETHSYS_ESW>,
+-                       <&ethsys CLK_ETHSYS_GP2>,
+-                       <&ethsys CLK_ETHSYS_GP1>;
+-              clock-names = "trgpll", "esw", "gp2", "gp1";
++              resets = <&ethsys 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 = <&ethsys>;
+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 <blogic@openwrt.org>
++ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
++ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
++ */
++
++#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 <blogic@openwrt.org>
++ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
++ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/platform_device.h>
++#include <linux/of_device.h>
++#include <linux/of_irq.h>
++#include <linux/of_gpio.h>
++#include <linux/clk.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regulator/consumer.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/mii.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <linux/dma-mapping.h>
++#include <linux/phy.h>
++#include <linux/ethtool.h>
++#include <linux/version.h>
++#include <linux/atomic.h>
++
++#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 <blogic@openwrt.org>");
++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 <blogic@openwrt.org>
++ */
++
++#include <linux/if.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/netlink.h>
++#include <linux/bitops.h>
++#include <net/genetlink.h>
++#include <linux/switch.h>
++#include <linux/delay.h>
++#include <linux/phy.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/lockdep.h>
++#include <linux/workqueue.h>
++#include <linux/of_device.h>
++
++#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 <blogic@openwrt.org>
++ */
++
++#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(&eth->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
new file mode 100644 (file)
index 0000000..d91915c
--- /dev/null
@@ -0,0 +1,25 @@
+From 36875ed8153d9b1eeae676579302a2fc746b286b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+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/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
new file mode 100644 (file)
index 0000000..636575e
--- /dev/null
@@ -0,0 +1,35 @@
+From 179937ef20beb9d4af4807f3540d4dfc4d48516a Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <boris.brezillon@free-electrons.com>
+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 <boris.brezillon@free-electrons.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ 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/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
new file mode 100644 (file)
index 0000000..d68a2fe
--- /dev/null
@@ -0,0 +1,32 @@
+From 8c32f64172fbf43d23c99dc4d32f5a1cb5eb08ae Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <boris.brezillon@free-electrons.com>
+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 <boris.brezillon@free-electrons.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ 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/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
new file mode 100644 (file)
index 0000000..49fbcbc
--- /dev/null
@@ -0,0 +1,39 @@
+From 738a76df006dedd1feb87c596867438b7d59027a Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <boris.brezillon@free-electrons.com>
+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 <boris.brezillon@free-electrons.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ 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/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
new file mode 100644 (file)
index 0000000..598f879
--- /dev/null
@@ -0,0 +1,42 @@
+From 088bf341472e8da8595d49f15af9becf3a4b52e7 Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <boris.brezillon@free-electrons.com>
+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 <boris.brezillon@free-electrons.com>
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ 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/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
new file mode 100644 (file)
index 0000000..b72ecfd
--- /dev/null
@@ -0,0 +1,87 @@
+From 63c8331b826ad5f21cb0175308099f18d5fe526a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+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 <computersforpeace@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ 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/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
new file mode 100644 (file)
index 0000000..533ff56
--- /dev/null
@@ -0,0 +1,64 @@
+From 91f978e8a8f27eb9988d33904eaba55309b6c0b9 Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+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 <jorge.ramirez-ortiz@linaro.org>
+---
+ .../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 = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>,
++                      <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
++              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/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
new file mode 100644 (file)
index 0000000..c21ca1d
--- /dev/null
@@ -0,0 +1,1798 @@
+From 7a9d3c8c4084fd37fa14c0e8db2830623f5da8cc Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+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 <jorge.ramirez-ortiz@linaro.org>
+---
+ 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              <xiaolei.li@mediatek.com>
++ *            Jorge Ramirez-Ortiz     <jorge.ramirez-ortiz@linaro.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/of_mtd.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/module.h>
++
++#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 <xiaolei.li@mediatek.com>");
++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 <xiaolei.li@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef 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 <xiaolei.li@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef 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/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
new file mode 100644 (file)
index 0000000..28899c4
--- /dev/null
@@ -0,0 +1,31 @@
+From a160c7846e1f81b5cd6c5d0fbe5c1f8757e8884b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+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 <blogic@openwrt.org>
+---
+ 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
+