aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-4.4
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mediatek/patches-4.4')
-rw-r--r--target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch34
-rw-r--r--target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch16
-rw-r--r--target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch16
-rw-r--r--target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch40
-rw-r--r--target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch34
-rw-r--r--target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch12
-rw-r--r--target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch12
-rw-r--r--target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch218
-rw-r--r--target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch20
-rw-r--r--target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch25
-rw-r--r--target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch15
-rw-r--r--target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch19
-rw-r--r--target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch23
-rw-r--r--target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch21
-rw-r--r--target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch10
-rw-r--r--target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch13
-rw-r--r--target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch17
-rw-r--r--target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch11
-rw-r--r--target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch (renamed from target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch)9
-rw-r--r--target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch35
-rw-r--r--target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch (renamed from target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch)19
-rw-r--r--target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch (renamed from target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch)33
-rw-r--r--target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch39
-rw-r--r--target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch (renamed from target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch)16
-rw-r--r--target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch42
-rw-r--r--target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch (renamed from target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch)15
-rw-r--r--target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch87
-rw-r--r--target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch64
-rw-r--r--target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch (renamed from target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch1798
-rw-r--r--target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch (renamed from target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch)9
-rw-r--r--target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch46
-rw-r--r--target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch (renamed from target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch (renamed from target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch (renamed from target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch (renamed from target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch (renamed from target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch (renamed from target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch (renamed from target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch)17
-rw-r--r--target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch (renamed from target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch (renamed from target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch)19
-rw-r--r--target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch (renamed from target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch)21
-rw-r--r--target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch (renamed from target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch)13
-rw-r--r--target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch (renamed from target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch)11
-rw-r--r--target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch337
-rw-r--r--target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch5489
-rw-r--r--target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch91
-rw-r--r--target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch179
-rw-r--r--target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch2064
-rw-r--r--target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch67
-rw-r--r--target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch71
-rw-r--r--target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch38
-rw-r--r--target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch59
-rw-r--r--target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch31
-rw-r--r--target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch32
-rw-r--r--target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch (renamed from target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch)29
-rw-r--r--target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch29
-rw-r--r--target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch (renamed from target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch)16
-rw-r--r--target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch (renamed from target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch)24
-rw-r--r--target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch27
-rw-r--r--target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch (renamed from target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch)18
-rw-r--r--target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch39
-rw-r--r--target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch30
-rw-r--r--target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch26
-rw-r--r--target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch77
-rw-r--r--target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch249
-rw-r--r--target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch48
-rw-r--r--target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch36
-rw-r--r--target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch37
-rw-r--r--target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch82
-rw-r--r--target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch (renamed from target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch)28
-rw-r--r--target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch (renamed from target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch)164
-rw-r--r--target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch57
-rw-r--r--target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch (renamed from target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch)56
-rw-r--r--target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch46
-rw-r--r--target/linux/mediatek/patches-4.4/0200-devicetree.patch2
-rw-r--r--target/linux/mediatek/patches-4.4/0201-block2mtd.patch (renamed from target/linux/mediatek/patches-4.4/0100-block2mtd.patch)0
115 files changed, 9402 insertions, 3789 deletions
diff --git a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
index 32b574992f..4b75613979 100644
--- a/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
+++ b/target/linux/mediatek/patches-4.4/0001-NET-multi-phy-support.patch
@@ -1,7 +1,7 @@
-From c30a296646a42302065ba452abe95b0b4b550883 Mon Sep 17 00:00:00 2001
+From 1e021917e634b173d466bf0dd3d2ae84e51a77ff Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:38:50 +0100
-Subject: [PATCH 01/91] NET: multi phy support
+Subject: [PATCH 001/102] NET: multi phy support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -9,11 +9,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/linux/phy.h | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
-diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
-index 47cd306..f69d12f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
-@@ -844,7 +844,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -888,7 +888,8 @@ void phy_state_machine(struct work_struc
/* If the link is down, give up on negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
@@ -23,7 +21,7 @@ index 47cd306..f69d12f 100644
phydev->adjust_link(phydev->attached_dev);
break;
}
-@@ -927,7 +928,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -971,7 +972,8 @@ void phy_state_machine(struct work_struc
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
@@ -33,7 +31,7 @@ index 47cd306..f69d12f 100644
}
phydev->adjust_link(phydev->attached_dev);
-@@ -939,7 +941,8 @@ void phy_state_machine(struct work_struct *work)
+@@ -983,7 +985,8 @@ void phy_state_machine(struct work_struc
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
@@ -43,8 +41,6 @@ index 47cd306..f69d12f 100644
phydev->adjust_link(phydev->attached_dev);
do_suspend = true;
}
-diff --git a/include/linux/phy.h b/include/linux/phy.h
-index 05fde31..276ab8a 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -377,6 +377,7 @@ struct phy_device {
@@ -55,6 +51,3 @@ index 05fde31..276ab8a 100644
enum phy_state state;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
index 389a09ea8c..194e66970e 100644
--- a/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
+++ b/target/linux/mediatek/patches-4.4/0002-soc-mediatek-Separate-scpsys-driver-common-code.patch
@@ -1,7 +1,7 @@
-From 2c93328ed05061a50e3bd4111379dbcf6946d3ac Mon Sep 17 00:00:00 2001
+From 1892fcf687116720d07135c83d489a23ec56a166 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/91] soc: mediatek: Separate scpsys driver common code
+Subject: [PATCH 002/102] 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.
@@ -17,8 +17,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
create mode 100644 drivers/soc/mediatek/mtk-scpsys-mt8173.c
create mode 100644 drivers/soc/mediatek/mtk-scpsys.h
-diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
-index 0a4ea80..eca6fb7 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -22,11 +22,20 @@ config MTK_PMIC_WRAP
@@ -44,8 +42,6 @@ index 0a4ea80..eca6fb7 100644
+ driver.
+ The System Control Processor System (SCPSYS) has several power
+ management related tasks in the system.
-diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
-index 12998b0..3b22baa 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
@@ -53,9 +49,6 @@ index 12998b0..3b22baa 100644
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
+obj-$(CONFIG_MTK_SCPSYS_MT8173) += mtk-scpsys-mt8173.o
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt8173.c b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-new file mode 100644
-index 0000000..3c7b569
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
@@ -0,0 +1,179 @@
@@ -238,8 +231,6 @@ index 0000000..3c7b569
+};
+
+module_platform_driver_probe(scpsys_drv, scpsys_probe);
-diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
-index 4d4203c..a0943c5 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -11,28 +11,14 @@
@@ -257,7 +248,7 @@ index 4d4203c..a0943c5 100644
-#include <linux/regmap.h>
#include <linux/soc/mediatek/infracfg.h>
-#include <dt-bindings/power/mt8173-power.h>
--
+
-#define SPM_VDE_PWR_CON 0x0210
-#define SPM_MFG_PWR_CON 0x0214
-#define SPM_VEN_PWR_CON 0x0230
@@ -268,7 +259,6 @@ index 4d4203c..a0943c5 100644
-#define SPM_MFG_2D_PWR_CON 0x02c0
-#define SPM_MFG_ASYNC_PWR_CON 0x02c4
-#define SPM_USB_PWR_CON 0x02cc
-+
+#include "mtk-scpsys.h"
+
#define SPM_PWR_STATUS 0x060c
@@ -428,7 +418,7 @@ index 4d4203c..a0943c5 100644
static int scpsys_domain_is_on(struct scp_domain *scpd)
{
struct scp *scp = scpd->scp;
-@@ -398,63 +237,89 @@ static bool scpsys_active_wakeup(struct device *dev)
+@@ -398,63 +237,89 @@ static bool scpsys_active_wakeup(struct
return scpd->active_wakeup;
}
@@ -518,13 +508,13 @@ index 4d4203c..a0943c5 100644
+ return ERR_PTR(-ENOMEM);
+
+ pd_data = &scp->pd_data;
-+
+
+- for (i = 0; i < NUM_DOMAINS; i++) {
+ pd_data->domains = devm_kzalloc(&pdev->dev,
+ sizeof(*pd_data->domains) * num, GFP_KERNEL);
+ if (!pd_data->domains)
+ return ERR_PTR(-ENOMEM);
-
-- for (i = 0; i < NUM_DOMAINS; i++) {
++
+ pd_data->num_domains = num;
+
+ init_clks(pdev, clk);
@@ -549,7 +539,7 @@ index 4d4203c..a0943c5 100644
pd_data->domains[i] = genpd;
scpd->scp = scp;
-@@ -464,13 +329,25 @@ static int __init scpsys_probe(struct platform_device *pdev)
+@@ -464,13 +329,25 @@ static int __init scpsys_probe(struct pl
scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
scpd->bus_prot_mask = data->bus_prot_mask;
scpd->active_wakeup = data->active_wakeup;
@@ -577,7 +567,7 @@ index 4d4203c..a0943c5 100644
/*
* Initially turn on all domains to make the domains usable
-@@ -489,37 +366,9 @@ static int __init scpsys_probe(struct platform_device *pdev)
+@@ -489,37 +366,9 @@ static int __init scpsys_probe(struct pl
* valid.
*/
@@ -616,9 +606,6 @@ index 4d4203c..a0943c5 100644
-};
-
-module_platform_driver_probe(scpsys_drv, scpsys_probe);
-diff --git a/drivers/soc/mediatek/mtk-scpsys.h b/drivers/soc/mediatek/mtk-scpsys.h
-new file mode 100644
-index 0000000..466728d
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys.h
@@ -0,0 +1,54 @@
@@ -676,6 +663,3 @@ index 0000000..466728d
+ struct scp *scp, int num);
+
+#endif /* __DRV_SOC_MTK_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
index c1eabc1716..46af96450b 100644
--- a/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
+++ b/target/linux/mediatek/patches-4.4/0003-soc-mediatek-Init-MT8173-scpsys-driver-earlier.patch
@@ -1,7 +1,7 @@
-From c359272f86805259c5801385d60fdeea9d629cf9 Mon Sep 17 00:00:00 2001
+From 6f87948c3a58f02f6a64eadda719317016739d5e 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/91] soc: mediatek: Init MT8173 scpsys driver earlier
+Subject: [PATCH 003/102] 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
@@ -12,11 +12,9 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
drivers/soc/mediatek/mtk-scpsys-mt8173.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt8173.c b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-index 3c7b569..827e696 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt8173.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt8173.c
-@@ -176,4 +176,15 @@ static struct platform_driver scpsys_drv = {
+@@ -176,4 +176,15 @@ static struct platform_driver scpsys_drv
},
};
@@ -33,6 +31,3 @@ index 3c7b569..827e696 100644
+
+subsys_initcall(scpsys_drv_init);
+module_exit(scpsys_drv_exit);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
index 42980394fa..132d6c89c8 100644
--- a/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
+++ b/target/linux/mediatek/patches-4.4/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch
@@ -1,7 +1,7 @@
-From f371844374fff273f817d6c43f679606417af59e Mon Sep 17 00:00:00 2001
+From 7c5b29de78f1b15c5bde40a6ca4510fc09588457 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/91] soc: mediatek: Add MT2701 power dt-bindings
+Subject: [PATCH 004/102] soc: mediatek: Add MT2701 power dt-bindings
Add power dt-bindings for MT2701.
@@ -12,9 +12,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
1 file changed, 27 insertions(+)
create mode 100644 include/dt-bindings/power/mt2701-power.h
-diff --git a/include/dt-bindings/power/mt2701-power.h b/include/dt-bindings/power/mt2701-power.h
-new file mode 100644
-index 0000000..64cc826
--- /dev/null
+++ b/include/dt-bindings/power/mt2701-power.h
@@ -0,0 +1,27 @@
@@ -45,6 +42,3 @@ index 0000000..64cc826
+#define MT2701_POWER_DOMAIN_IFR_MSC 8
+
+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
index 158d6d0b2b..2f2337a8e3 100644
--- a/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0005-soc-mediatek-Add-MT2701-MT7623-scpsys-driver.patch
@@ -1,7 +1,7 @@
-From c6711565985f359d7d3c05f01f081e4c216902de Mon Sep 17 00:00:00 2001
+From 8aa49d107d8a22fd6cbf37174614baf32d0976e2 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/91] soc: mediatek: Add MT2701/MT7623 scpsys driver
+Subject: [PATCH 005/102] soc: mediatek: Add MT2701/MT7623 scpsys driver
Add scpsys driver for MT2701 and MT7623.
@@ -14,8 +14,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
3 files changed, 173 insertions(+)
create mode 100644 drivers/soc/mediatek/mtk-scpsys-mt2701.c
-diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
-index eca6fb7..92cf838 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -39,3 +39,14 @@ config MTK_SCPSYS_MT8173
@@ -33,18 +31,13 @@ index eca6fb7..92cf838 100644
+ domain driver.
+ The System Control Processor System (SCPSYS) has several power
+ management related tasks in the system.
-diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
-index 3b22baa..822986d 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
-@@ -2,3 +2,4 @@ obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+@@ -2,3 +2,4 @@ obj-$(CONFIG_MTK_INFRACFG) += mtk-infrac
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
obj-$(CONFIG_MTK_SCPSYS_MT8173) += mtk-scpsys-mt8173.o
+obj-$(CONFIG_MTK_SCPSYS_MT2701) += mtk-scpsys-mt2701.o
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-new file mode 100644
-index 0000000..339d5b8
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
@@ -0,0 +1,161 @@
@@ -209,6 +202,3 @@ index 0000000..339d5b8
+
+MODULE_DESCRIPTION("MediaTek MT2701 scpsys driver");
+MODULE_LICENSE("GPL v2");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
index 62b825555d..d4bac233b9 100644
--- a/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
+++ b/target/linux/mediatek/patches-4.4/0006-clk-mediatek-Refine-the-makefile-to-support-multiple.patch
@@ -1,8 +1,8 @@
-From 0c39bcd17fa6ce723f56ad3756b4bb36c4690342 Mon Sep 17 00:00:00 2001
+From 69d4e250847f82a5896c41bcb5f1e793c5a8fbac 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/91] clk: mediatek: Refine the makefile to support multiple
- clock drivers
+Subject: [PATCH 006/102] clk: mediatek: Refine the makefile to support
+ multiple clock drivers
Add a Kconfig to define clock configuration for each SoC, and
modify the Makefile to build drivers that only selected in config.
@@ -16,8 +16,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
3 files changed, 27 insertions(+), 3 deletions(-)
create mode 100644 drivers/clk/mediatek/Kconfig
-diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
-index c3e3a02..b7a37dc 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -198,3 +198,4 @@ source "drivers/clk/mvebu/Kconfig"
@@ -25,9 +23,6 @@ index c3e3a02..b7a37dc 100644
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/tegra/Kconfig"
+source "drivers/clk/mediatek/Kconfig"
-diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
-new file mode 100644
-index 0000000..dc224e6
--- /dev/null
+++ b/drivers/clk/mediatek/Kconfig
@@ -0,0 +1,23 @@
@@ -54,8 +49,6 @@ index 0000000..dc224e6
+ default ARCH_MEDIATEK
+ ---help---
+ This driver supports Mediatek MT8173 clocks.
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 95fdfac..32e7222 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -1,4 +1,4 @@
@@ -66,6 +59,3 @@ index 95fdfac..32e7222 100644
-obj-y += clk-mt8173.o
+obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
index 5c24ef8a0e..fd21c0b788 100644
--- a/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
+++ b/target/linux/mediatek/patches-4.4/0007-dt-bindings-ARM-Mediatek-Document-bindings-for-MT270.patch
@@ -1,7 +1,7 @@
-From d7e96f87f66c571e9f4171ecd89c656fbd2de89b Mon Sep 17 00:00:00 2001
+From 7c98b20fa68a2a64bca69822eb7be4fa9b668fab 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/91] dt-bindings: ARM: Mediatek: Document bindings for
+Subject: [PATCH 007/102] dt-bindings: ARM: Mediatek: Document bindings for
MT2701
This patch adds the binding documentation for apmixedsys, bdpsys,
@@ -25,11 +25,9 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
-index 936166f..a701e19 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,apmixedsys.txt
-@@ -6,6 +6,7 @@ The Mediatek apmixedsys controller provides the PLLs to the system.
+@@ -6,6 +6,7 @@ The Mediatek apmixedsys controller provi
Required Properties:
- compatible: Should be:
@@ -37,9 +35,6 @@ index 936166f..a701e19 100644
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt
-new file mode 100644
-index 0000000..4137196
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt
@@ -0,0 +1,22 @@
@@ -65,9 +60,6 @@ index 0000000..4137196
+ reg = <0 0x1c000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
-new file mode 100644
-index 0000000..768f3a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
@@ -0,0 +1,22 @@
@@ -93,9 +85,6 @@ index 0000000..768f3a5
+ reg = <0 0x1b000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
-new file mode 100644
-index 0000000..b7a39b6
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,hifsys.txt
@@ -0,0 +1,22 @@
@@ -121,11 +110,9 @@ index 0000000..b7a39b6
+ reg = <0 0x1a000000 0 0x1000>;
+ #clock-cells = <1>;
+};
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
-index b1f2ce1..9bda7f7 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt
-@@ -6,6 +6,7 @@ The Mediatek imgsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek imgsys controller provides
Required Properties:
- compatible: Should be:
@@ -133,8 +120,6 @@ index b1f2ce1..9bda7f7 100644
- "mediatek,mt8173-imgsys", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
-index f6cd3e4..2f11a69 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.txt
@@ -7,6 +7,7 @@ outputs to the system.
@@ -145,11 +130,9 @@ index f6cd3e4..2f11a69 100644
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
-index 4385946..c9d9d43 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt
-@@ -6,6 +6,7 @@ The Mediatek mmsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek mmsys controller provides v
Required Properties:
- compatible: Should be:
@@ -157,8 +140,6 @@ index 4385946..c9d9d43 100644
- "mediatek,mt8173-mmsys", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
-index f25b854..d3454cd 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.txt
@@ -7,6 +7,7 @@ outputs to the system.
@@ -169,11 +150,9 @@ index f25b854..d3454cd 100644
- "mediatek,mt8135-pericfg", "syscon"
- "mediatek,mt8173-pericfg", "syscon"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
-index f9e9179..602e5bc 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,topckgen.txt
-@@ -6,6 +6,7 @@ The Mediatek topckgen controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek topckgen controller provide
Required Properties:
- compatible: Should be:
@@ -181,11 +160,9 @@ index f9e9179..602e5bc 100644
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- #clock-cells: Must be 1
-diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
-index 1faacf1..f5b1e7d 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt
-@@ -6,6 +6,7 @@ The Mediatek vdecsys controller provides various clocks to the system.
+@@ -6,6 +6,7 @@ The Mediatek vdecsys controller provides
Required Properties:
- compatible: Should be:
@@ -193,6 +170,3 @@ index 1faacf1..f5b1e7d 100644
- "mediatek,mt8173-vdecsys", "syscon"
- #clock-cells: Must be 1
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
index 057eb44fa7..422a5bec3a 100644
--- a/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
+++ b/target/linux/mediatek/patches-4.4/0008-clk-mediatek-Add-dt-bindings-for-MT2701-clocks.patch
@@ -1,7 +1,7 @@
-From 2fcbc15da2f13164e0851b9c7fae290249f0b44d Mon Sep 17 00:00:00 2001
+From 190696e3995be38fa01490e4ab88ea2c859829c9 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/91] clk: mediatek: Add dt-bindings for MT2701 clocks
+Subject: [PATCH 008/102] clk: mediatek: Add dt-bindings for MT2701 clocks
Add MT2701 clock dt-bindings, include topckgen, apmixedsys,
infracfg, pericfg and subsystem clocks.
@@ -13,9 +13,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
1 file changed, 481 insertions(+)
create mode 100644 include/dt-bindings/clock/mt2701-clk.h
-diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
-new file mode 100644
-index 0000000..50972d1
--- /dev/null
+++ b/include/dt-bindings/clock/mt2701-clk.h
@@ -0,0 +1,481 @@
@@ -500,6 +497,3 @@ index 0000000..50972d1
+#define CLK_BDP_NR 50
+
+#endif /* _DT_BINDINGS_CLK_MT2701_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
index b29285e864..6f8f68a300 100644
--- a/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
+++ b/target/linux/mediatek/patches-4.4/0009-clk-mediatek-Add-MT2701-clock-support.patch
@@ -1,7 +1,7 @@
-From f2c07eaa2df52f9acac9ffc3457d3d81079dd723 Mon Sep 17 00:00:00 2001
+From a4c507d052390b42d7e8c59241e3c336796f730f Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:20 +0800
-Subject: [PATCH 09/91] clk: mediatek: Add MT2701 clock support
+Subject: [PATCH 009/102] clk: mediatek: Add MT2701 clock support
Add MT2701 clock support, include topckgen, apmixedsys,
infracfg, pericfg and subsystem clocks.
@@ -19,8 +19,6 @@ Signed-off-by: James Liao <jamesjj.liao@mediatek.com>
7 files changed, 1334 insertions(+), 3 deletions(-)
create mode 100644 drivers/clk/mediatek/clk-mt2701.c
-diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
-index dc224e6..6c7cdc0 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -6,6 +6,14 @@ config COMMON_CLK_MEDIATEK
@@ -38,8 +36,6 @@ index dc224e6..6c7cdc0 100644
config COMMON_CLK_MT8135
bool "Clock driver for Mediatek MT8135"
depends on COMMON_CLK
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 32e7222..5b2b91b 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -1,4 +1,5 @@
@@ -48,11 +44,9 @@ index 32e7222..5b2b91b 100644
+obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
-diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c
-index 576bdb7..38badb4 100644
--- a/drivers/clk/mediatek/clk-gate.c
+++ b/drivers/clk/mediatek/clk-gate.c
-@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw *hw)
+@@ -61,6 +61,26 @@ static void mtk_cg_clr_bit(struct clk_hw
regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
}
@@ -79,7 +73,7 @@ index 576bdb7..38badb4 100644
static int mtk_cg_enable(struct clk_hw *hw)
{
mtk_cg_clr_bit(hw);
-@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct clk_hw *hw)
+@@ -85,6 +105,30 @@ static void mtk_cg_disable_inv(struct cl
mtk_cg_clr_bit(hw);
}
@@ -110,7 +104,7 @@ index 576bdb7..38badb4 100644
const struct clk_ops mtk_clk_gate_ops_setclr = {
.is_enabled = mtk_cg_bit_is_cleared,
.enable = mtk_cg_enable,
-@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
+@@ -97,6 +141,18 @@ const struct clk_ops mtk_clk_gate_ops_se
.disable = mtk_cg_disable_inv,
};
@@ -129,11 +123,9 @@ index 576bdb7..38badb4 100644
struct clk * __init mtk_clk_register_gate(
const char *name,
const char *parent_name,
-diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h
-index 11e25c9..7f7ef34 100644
--- a/drivers/clk/mediatek/clk-gate.h
+++ b/drivers/clk/mediatek/clk-gate.h
-@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
+@@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_cl
extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
@@ -142,9 +134,6 @@ index 11e25c9..7f7ef34 100644
struct clk *mtk_clk_register_gate(
const char *name,
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-new file mode 100644
-index 0000000..2f521f4
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -0,0 +1,1210 @@
@@ -1358,11 +1347,9 @@ index 0000000..2f521f4
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
+ mtk_apmixedsys_init);
-diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
-index cf08db6..be19a41 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
-@@ -242,3 +242,28 @@ void __init mtk_clk_register_composites(const struct mtk_composite *mcs,
+@@ -242,3 +242,28 @@ void __init mtk_clk_register_composites(
clk_data->clks[mc->id] = clk;
}
}
@@ -1391,8 +1378,6 @@ index cf08db6..be19a41 100644
+ clk_data->clks[mcd->id] = clk;
+ }
+}
-diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
-index 32d2e45..60701e8 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -110,7 +110,8 @@ struct mtk_composite {
@@ -1444,6 +1429,3 @@ index 32d2e45..60701e8 100644
struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
index 8f5db79c76..b5b10e7b0b 100644
--- a/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
+++ b/target/linux/mediatek/patches-4.4/0010-reset-mediatek-mt2701-reset-controller-dt-binding-fi.patch
@@ -1,7 +1,7 @@
-From 8d134cbe750b59d15c591622d81e2e9daa09f0c4 Mon Sep 17 00:00:00 2001
+From 8bf0f2a1e8ff082de3f650211abd985ef68abe1b 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/91] reset: mediatek: mt2701 reset controller dt-binding
+Subject: [PATCH 010/102] reset: mediatek: mt2701 reset controller dt-binding
file
Dt-binding file about reset controller is used to provide
@@ -14,9 +14,6 @@ Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
1 file changed, 74 insertions(+)
create mode 100644 include/dt-bindings/reset-controller/mt2701-resets.h
-diff --git a/include/dt-bindings/reset-controller/mt2701-resets.h b/include/dt-bindings/reset-controller/mt2701-resets.h
-new file mode 100644
-index 0000000..00efeb0
--- /dev/null
+++ b/include/dt-bindings/reset-controller/mt2701-resets.h
@@ -0,0 +1,74 @@
@@ -94,6 +91,3 @@ index 0000000..00efeb0
+#define MT2701_TOPRGU_BDP_DISP_RST 13
+
+#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2701 */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
index bbb123e575..18d4fbf252 100644
--- a/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0011-reset-mediatek-mt2701-reset-driver.patch
@@ -1,7 +1,7 @@
-From b86d3303db25a8296e4c3de46ee1470f60f71b0c Mon Sep 17 00:00:00 2001
+From 3ba0020ea70ffb5503eff1823be7fa5ceda38286 Mon Sep 17 00:00:00 2001
From: Shunli Wang <shunli.wang@mediatek.com>
Date: Tue, 5 Jan 2016 14:30:22 +0800
-Subject: [PATCH 11/91] reset: mediatek: mt2701 reset driver
+Subject: [PATCH 011/102] reset: mediatek: mt2701 reset driver
In infrasys and perifsys, there are many reset
control bits for kinds of modules. These bits are
@@ -14,11 +14,9 @@ Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
drivers/clk/mediatek/clk-mt2701.c | 4 ++++
1 file changed, 4 insertions(+)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 2f521f4..39472e4 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(struct device_node *node)
+@@ -665,6 +665,8 @@ static void __init mtk_infrasys_init(str
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -27,7 +25,7 @@ index 2f521f4..39472e4 100644
}
CLK_OF_DECLARE(mtk_infrasys, "mediatek,mt2701-infracfg", mtk_infrasys_init);
-@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(struct device_node *node)
+@@ -782,6 +784,8 @@ static void __init mtk_pericfg_init(stru
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -36,6 +34,3 @@ index 2f521f4..39472e4 100644
}
CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt2701-pericfg", mtk_pericfg_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
index 0e532ffcbf..479334a92d 100644
--- a/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
+++ b/target/linux/mediatek/patches-4.4/0012-ARM-mediatek-Add-MT2701-config-options-for-mediatek-.patch
@@ -1,8 +1,8 @@
-From 3b5df542d52b13a1b20d25311fa4c4029a3b83af Mon Sep 17 00:00:00 2001
+From 32fa899c6ab79953e4f470fb23c38bcc40edc5c8 Mon Sep 17 00:00:00 2001
From: Erin Lo <erin.lo@mediatek.com>
Date: Mon, 28 Dec 2015 15:09:02 +0800
-Subject: [PATCH 12/91] ARM: mediatek: Add MT2701 config options for mediatek
- SoCs.
+Subject: [PATCH 012/102] ARM: mediatek: Add MT2701 config options for
+ mediatek SoCs.
The upcoming MTK pinctrl driver have a big pin table for each SoC
and we don't want to bloat the kernel binary if we don't need it.
@@ -14,8 +14,6 @@ Acked-by: Linus Walleij <linus.walleij@linaro.org>
arch/arm/mach-mediatek/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index aeece17..37dd438 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -9,6 +9,10 @@ menuconfig ARCH_MEDIATEK
@@ -29,6 +27,3 @@ index aeece17..37dd438 100644
config MACH_MT6589
bool "MediaTek MT6589 SoCs support"
default ARCH_MEDIATEK
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
index ba3bd08806..af1ad668f5 100644
--- a/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
+++ b/target/linux/mediatek/patches-4.4/0013-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt2.patch
@@ -1,7 +1,7 @@
-From 1a254735cad9db5c8605c972b0f16b3929dc0d6e Mon Sep 17 00:00:00 2001
+From afcbed6f51e8c3a9195952b27c8aad047c314ed0 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/91] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 013/102] dt-bindings: mediatek: Modify pinctrl bindings for
mt2701
Signed-off-by: Biao Huang <biao.huang@mediatek.com>
@@ -11,11 +11,9 @@ Reviewed-by: Mathias Brugger <matthias.bgg@gmail.com>
Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
-diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-index 0480bc3..9ffb0b2 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to control SoC pins.
+@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to
Required properties:
- compatible: value should be one of the following.
@@ -31,6 +29,3 @@ index 0480bc3..9ffb0b2 100644
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
specify pins.
- gpio-controller : Marks the device node as a gpio controller.
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
index d898f3c06f..0df6d186ba 100644
--- a/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
+++ b/target/linux/mediatek/patches-4.4/0014-pinctrl-dt-bindings-Add-pinfunc-header-file-for-mt27.patch
@@ -1,7 +1,7 @@
-From 416720ba33d4fd7d3166c17be7c13651cc08d408 Mon Sep 17 00:00:00 2001
+From 124894a4d1635915ff95c447767677b60fd27e9c 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/91] pinctrl: dt bindings: Add pinfunc header file for
+Subject: [PATCH 014/102] pinctrl: dt bindings: Add pinfunc header file for
mt2701
Add pinfunc header file, mt2701 related dts will include it
@@ -21,9 +21,6 @@ Acked-by: Linus Walleij <linus.walleij@linaro.org>
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt2701.c
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
-diff --git a/arch/arm/boot/dts/mt2701-pinfunc.h b/arch/arm/boot/dts/mt2701-pinfunc.h
-new file mode 100644
-index 0000000..e24ebc8
--- /dev/null
+++ b/arch/arm/boot/dts/mt2701-pinfunc.h
@@ -0,0 +1,735 @@
@@ -762,8 +759,6 @@ index 0000000..e24ebc8
+#define MT2701_PIN_278_JTAG_RESET__FUNC_JTAG_RESET (MTK_PIN_NO(278) | 1)
+
+#endif /* __DTS_MT2701_PINFUNC_H */
-diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
-index 02f6f92..13e9939 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -9,6 +9,12 @@ config PINCTRL_MTK_COMMON
@@ -779,8 +774,6 @@ index 02f6f92..13e9939 100644
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
depends on OF
-diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
-index eb923d6..da30314 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -2,6 +2,7 @@
@@ -791,9 +784,6 @@ index eb923d6..da30314 100644
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
-new file mode 100644
-index 0000000..4861b5d
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -0,0 +1,586 @@
@@ -1383,8 +1373,6 @@ index 0000000..4861b5d
+}
+
+arch_initcall(mtk_pinctrl_init);
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
-index 5c71727..05ba7a8 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -47,6 +47,8 @@
@@ -1396,7 +1384,7 @@ index 5c71727..05ba7a8 100644
};
/*
-@@ -81,6 +83,9 @@ static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+@@ -81,6 +83,9 @@ static int mtk_pmx_gpio_set_direction(st
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
@@ -1406,7 +1394,7 @@ index 5c71727..05ba7a8 100644
if (input)
/* Different SoC has different alignment offset. */
reg_addr = CLR_ADDR(reg_addr, pctl);
-@@ -347,6 +352,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
+@@ -347,6 +352,7 @@ static int mtk_pconf_parse_conf(struct p
ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
break;
case PIN_CONFIG_INPUT_ENABLE:
@@ -1414,7 +1402,7 @@ index 5c71727..05ba7a8 100644
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_OUTPUT:
-@@ -354,6 +360,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
+@@ -354,6 +360,7 @@ static int mtk_pconf_parse_conf(struct p
ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
@@ -1422,7 +1410,7 @@ index 5c71727..05ba7a8 100644
ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
-@@ -667,9 +674,14 @@ static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
+@@ -667,9 +674,14 @@ static int mtk_pmx_set_mode(struct pinct
unsigned int mask = (1L << GPIO_MODE_BITS) - 1;
struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -1437,7 +1425,7 @@ index 5c71727..05ba7a8 100644
bit = pin % MAX_GPIO_MODE_PER_REG;
mask <<= (GPIO_MODE_BITS * bit);
val = (mode << (GPIO_MODE_BITS * bit));
-@@ -746,6 +758,10 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+@@ -746,6 +758,10 @@ static int mtk_gpio_get_direction(struct
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
@@ -1448,8 +1436,6 @@ index 5c71727..05ba7a8 100644
regmap_read(pctl->regmap1, reg_addr, &read_val);
return !(read_val & bit);
}
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
-index 55a5343..8543bc4 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -209,7 +209,14 @@ struct mtk_eint_offsets {
@@ -1478,9 +1464,6 @@ index 55a5343..8543bc4 100644
unsigned int dir_offset;
unsigned int ies_offset;
unsigned int smt_offset;
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
-new file mode 100644
-index 0000000..f906420
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt2701.h
@@ -0,0 +1,2323 @@
@@ -3807,6 +3790,3 @@ index 0000000..f906420
+};
+
+#endif /* __PINCTRL_MTK_MT2701_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
index d1e231eb72..fcd39c487d 100644
--- a/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
+++ b/target/linux/mediatek/patches-4.4/0015-dt-bindings-mediatek-Modify-pinctrl-bindings-for-mt7.patch
@@ -1,7 +1,7 @@
-From ddc72b659b3642d0496dee4e1ee39416ca008053 Mon Sep 17 00:00:00 2001
+From 3800e5c33e5becbb56c6694008d1f3435fd78707 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/91] dt-bindings: mediatek: Modify pinctrl bindings for
+Subject: [PATCH 015/102] dt-bindings: mediatek: Modify pinctrl bindings for
mt7623
Signed-off-by: John Crispin <blogic@openwrt.org>
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
2 files changed, 522 insertions(+)
create mode 100644 include/dt-bindings/pinctrl/mt7623-pinfunc.h
-diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
-index 9ffb0b2..17631d0 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
@@ -6,6 +6,7 @@ Required properties:
@@ -23,9 +21,6 @@ index 9ffb0b2..17631d0 100644
"mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
"mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
"mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
-diff --git a/include/dt-bindings/pinctrl/mt7623-pinfunc.h b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-new file mode 100644
-index 0000000..891b173
--- /dev/null
+++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
@@ -0,0 +1,521 @@
@@ -550,6 +545,3 @@ index 0000000..891b173
+
+#endif /* __DTS_MT7623_PINFUNC_H */
+
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
index cf09ae5da0..3428fce39c 100644
--- a/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
+++ b/target/linux/mediatek/patches-4.4/0016-pinctrl-dt-bindings-Add-pinctrl-file-for-mt7623.patch
@@ -1,7 +1,7 @@
-From 1255eaacd6cc9d1fa6bb33185380efed22008baf Mon Sep 17 00:00:00 2001
+From 641ccb565a934ffaa30b828f2361e6f57325c70a 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/91] pinctrl: dt bindings: Add pinctrl file for mt7623
+Subject: [PATCH 016/102] pinctrl: dt bindings: Add pinctrl file for mt7623
Add the driver and header files required to make pinctrl work on MediaTek
MT7623.
@@ -17,8 +17,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mt7623.c
create mode 100644 drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
-index 13e9939..78654a8 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -15,6 +15,12 @@ config PINCTRL_MT2701
@@ -34,11 +32,9 @@ index 13e9939..78654a8 100644
config PINCTRL_MT8135
bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
depends on OF
-diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
-index da30314..1be2f3f 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
-@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinctrl-mtk-common.o
+@@ -3,6 +3,7 @@ obj-$(CONFIG_PINCTRL_MTK_COMMON) += pinc
# SoC Drivers
obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
@@ -46,9 +42,6 @@ index da30314..1be2f3f 100644
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
-new file mode 100644
-index 0000000..bf0d05b
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -0,0 +1,380 @@
@@ -432,9 +425,6 @@ index 0000000..bf0d05b
+}
+
+arch_initcall(mtk_pinctrl_init);
-diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
-new file mode 100644
-index 0000000..fb63c01
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
@@ -0,0 +1,1937 @@
@@ -2375,8 +2365,6 @@ index 0000000..fb63c01
+};
+
+#endif /* __PINCTRL_MTK_MT7623_H */
-diff --git a/include/dt-bindings/pinctrl/mt7623-pinfunc.h b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
-index 891b173..eeb2380 100644
--- a/include/dt-bindings/pinctrl/mt7623-pinfunc.h
+++ b/include/dt-bindings/pinctrl/mt7623-pinfunc.h
@@ -505,6 +505,9 @@
@@ -2389,6 +2377,3 @@ index 891b173..eeb2380 100644
#define MT7623_PIN_274_G2_RXDV_FUNC_GPIO274 (MTK_PIN_NO(274) | 0)
#define MT7623_PIN_274_G2_RXDV_FUNC_G2_RXDV (MTK_PIN_NO(274) | 1)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
index 0b1b59be9c..d7d151cedb 100644
--- a/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
+++ b/target/linux/mediatek/patches-4.4/0017-clk-add-hifsys-reset.patch
@@ -1,7 +1,7 @@
-From 294cf90337d70ad74edf147180bbeef837298bd0 Mon Sep 17 00:00:00 2001
+From f7121d2b19ddad33a09408a2c5923bfd95da8533 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 6 Jan 2016 20:06:49 +0100
-Subject: [PATCH 17/91] clk: add hifsys reset
+Subject: [PATCH 017/102] clk: add hifsys reset
Hi,
@@ -18,11 +18,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/dt-bindings/reset-controller/mt2701-resets.h | 9 +++++++++
2 files changed, 11 insertions(+)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 39472e4..0e40bb8 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struct device_node *node)
+@@ -1000,6 +1000,8 @@ static void __init mtk_hifsys_init(struc
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -31,8 +29,6 @@ index 39472e4..0e40bb8 100644
}
CLK_OF_DECLARE(mtk_hifsys, "mediatek,mt2701-hifsys", mtk_hifsys_init);
-diff --git a/include/dt-bindings/reset-controller/mt2701-resets.h b/include/dt-bindings/reset-controller/mt2701-resets.h
-index 00efeb0..aaf0305 100644
--- a/include/dt-bindings/reset-controller/mt2701-resets.h
+++ b/include/dt-bindings/reset-controller/mt2701-resets.h
@@ -71,4 +71,13 @@
@@ -49,6 +45,3 @@ index 00efeb0..aaf0305 100644
+#define MT2701_HIFSYS_PCIE2_RST 26
+
#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT2701 */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
index d011bf344d..9c178f2918 100644
--- a/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
+++ b/target/linux/mediatek/patches-4.4/0018-dt-bindings-Add-a-binding-for-Mediatek-xHCI-host-con.patch
@@ -1,7 +1,7 @@
-From 84d37aeef94deae3ce87e677f6016a5d980429e8 Mon Sep 17 00:00:00 2001
+From ba126a519da8a036dae0032e9d5a89e47570e5fb 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/91] dt-bindings: Add a binding for Mediatek xHCI host
+Subject: [PATCH 018/102] dt-bindings: Add a binding for Mediatek xHCI host
controller
add a DT binding documentation of xHCI host controller for the
@@ -13,9 +13,6 @@ Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/mt8173-xhci.txt
-diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
-new file mode 100644
-index 0000000..a78f20b
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt
@@ -0,0 +1,51 @@
@@ -70,6 +67,3 @@ index 0000000..a78f20b
+ mediatek,syscon-wakeup = <&pericfg>;
+ mediatek,wakeup-src = <1>;
+};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
index 603abe0704..f344be6fdd 100644
--- a/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
+++ b/target/linux/mediatek/patches-4.4/0019-xhci-mediatek-support-MTK-xHCI-host-controller.patch
@@ -1,7 +1,7 @@
-From 651d8fff94718c7e48b8a40d7774878eb8ed62ee Mon Sep 17 00:00:00 2001
+From 8b8185586a13ebbd760e80bbe5f22f9417b50fd2 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/91] xhci: mediatek: support MTK xHCI host controller
+Subject: [PATCH 019/102] 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
@@ -31,8 +31,6 @@ Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
create mode 100644 drivers/usb/host/xhci-mtk.c
create mode 100644 drivers/usb/host/xhci-mtk.h
-diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
-index 3bb0887..daa563f 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -41,6 +41,15 @@ config USB_XHCI_PLATFORM
@@ -51,8 +49,6 @@ index 3bb0887..daa563f 100644
config USB_XHCI_MVEBU
tristate "xHCI support for Marvell Armada 375/38x"
select USB_XHCI_PLATFORM
-diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
-index e7558ab..65a06b4 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -13,6 +13,9 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
@@ -73,9 +69,6 @@ index e7558ab..65a06b4 100644
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
-diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
-new file mode 100644
-index 0000000..c30de7c
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -0,0 +1,415 @@
@@ -494,9 +487,6 @@ index 0000000..c30de7c
+ }
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
-diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
-new file mode 100644
-index 0000000..c9ab6a4
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.c
@@ -0,0 +1,763 @@
@@ -1263,9 +1253,6 @@ index 0000000..c9ab6a4
+MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek xHCI Host Controller Driver");
+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
-new file mode 100644
-index 0000000..7da677c
--- /dev/null
+++ b/drivers/usb/host/xhci-mtk.h
@@ -0,0 +1,162 @@
@@ -1431,8 +1418,6 @@ index 0000000..7da677c
+#endif
+
+#endif /* _XHCI_MTK_H_ */
-diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
-index eeaa6c6..f1c21c4 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -68,6 +68,7 @@
@@ -1443,7 +1428,7 @@ index eeaa6c6..f1c21c4 100644
/*
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
-@@ -3075,17 +3076,22 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
+@@ -3065,17 +3066,22 @@ static u32 xhci_td_remainder(struct xhci
{
u32 maxp, total_packet_count;
@@ -1470,7 +1455,7 @@ index eeaa6c6..f1c21c4 100644
/* Queueing functions don't count the current TRB into transferred */
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
-@@ -3473,7 +3479,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+@@ -3463,7 +3469,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
field |= 0x1;
/* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
@@ -1479,8 +1464,6 @@ index eeaa6c6..f1c21c4 100644
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_TX_TYPE(TRB_DATA_IN);
-diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
-index 3f91270..15fedb2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -31,6 +31,7 @@
@@ -1491,7 +1474,7 @@ index 3f91270..15fedb2 100644
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
-@@ -634,7 +635,11 @@ int xhci_run(struct usb_hcd *hcd)
+@@ -635,7 +636,11 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
@@ -1504,7 +1487,7 @@ index 3f91270..15fedb2 100644
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
-@@ -1698,6 +1703,9 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+@@ -1701,6 +1706,9 @@ int xhci_drop_endpoint(struct usb_hcd *h
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
@@ -1514,7 +1497,7 @@ index 3f91270..15fedb2 100644
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
-@@ -1793,6 +1801,15 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+@@ -1796,6 +1804,15 @@ int xhci_add_endpoint(struct usb_hcd *hc
return -ENOMEM;
}
@@ -1530,11 +1513,9 @@ index 3f91270..15fedb2 100644
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
-diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
-index 0b94512..40cf36e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
-@@ -1630,6 +1630,7 @@ struct xhci_hcd {
+@@ -1631,6 +1631,7 @@ struct xhci_hcd {
/* For controllers with a broken beyond repair streams implementation */
#define XHCI_BROKEN_STREAMS (1 << 19)
#define XHCI_PME_STUCK_QUIRK (1 << 20)
@@ -1542,6 +1523,3 @@ index 0b94512..40cf36e 100644
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
index c5bfd0f0e1..50c03ee892 100644
--- a/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
+++ b/target/linux/mediatek/patches-4.4/0020-arm64-dts-mediatek-add-xHCI-usb-phy-for-mt8173.patch
@@ -1,7 +1,7 @@
-From 31a22fbd0d3b187be61c4c5d22b19c95abb327c3 Mon Sep 17 00:00:00 2001
+From 645465d4c6dd46c5e6c9ac25cd42608b4201fde0 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/91] arm64: dts: mediatek: add xHCI & usb phy for mt8173
+Subject: [PATCH 020/102] arm64: dts: mediatek: add xHCI & usb phy for mt8173
add xHCI and phy drivers for MT8173-EVB
@@ -11,8 +11,6 @@ Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 42 +++++++++++++++++++++++++++
2 files changed, 58 insertions(+)
-diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
-index 811cb76..9b1482a 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -13,6 +13,7 @@
@@ -49,8 +47,6 @@ index 811cb76..9b1482a 100644
+ vbus-supply = <&usb_p1_vbus>;
+ mediatek,wakeup-src = <1>;
+};
-diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
-index 4dd5f93..c1fd275 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -14,6 +14,7 @@
@@ -109,6 +105,3 @@ index 4dd5f93..c1fd275 100644
mmsys: clock-controller@14000000 {
compatible = "mediatek,mt8173-mmsys", "syscon";
reg = <0 0x14000000 0 0x1000>;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
index 470da141e8..223c2263f3 100644
--- a/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
+++ b/target/linux/mediatek/patches-4.4/0021-Document-DT-Add-bindings-for-mediatek-MT7623-SoC-Pla.patch
@@ -1,7 +1,7 @@
-From 162deec293400cb132161606629654acaec7cb4b Mon Sep 17 00:00:00 2001
+From e111a35542ac14712026fe1a55236f76c7fc9048 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/91] Document: DT: Add bindings for mediatek MT7623 SoC
+Subject: [PATCH 021/102] Document: DT: Add bindings for mediatek MT7623 SoC
Platform
This adds a DT binding documentation for the MT7623 SoC from Mediatek.
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt | 1 +
3 files changed, 6 insertions(+)
-diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
-index 618a9199..40e9d32 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek.txt
@@ -10,6 +10,7 @@ compatible: Must contain one of
@@ -35,8 +33,6 @@ index 618a9199..40e9d32 100644
- MTK mt8127 tablet moose EVB:
Required root node properties:
- compatible = "mediatek,mt8127-moose", "mediatek,mt8127";
-diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt
-index 2d47add..474f0cf 100644
--- a/Documentation/devicetree/bindings/serial/mtk-uart.txt
+++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt
@@ -2,6 +2,7 @@
@@ -47,8 +43,6 @@ index 2d47add..474f0cf 100644
* "mediatek,mt8135-uart" for MT8135 compatible UARTS
* "mediatek,mt8127-uart" for MT8127 compatible UARTS
* "mediatek,mt8173-uart" for MT8173 compatible UARTS
-diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
-index 64083bc..6bacda1b3 100644
--- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
+++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
@@ -5,6 +5,7 @@ Required properties:
@@ -59,6 +53,3 @@ index 64083bc..6bacda1b3 100644
* "mediatek,mt8127-timer" for MT8127 compatible timers
* "mediatek,mt8135-timer" for MT8135 compatible timers
* "mediatek,mt8173-timer" for MT8173 compatible timers
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
index 5ae71d73db..453b61288a 100644
--- a/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
+++ b/target/linux/mediatek/patches-4.4/0022-soc-mediatek-add-compat-string-for-mt7623-to-scpsys.patch
@@ -1,18 +1,17 @@
-From fa5d94d6b4b314f751b1c32bb5a87a80b866d05e Mon Sep 17 00:00:00 2001
+From f232c3b36355974bf3442de3a4726d2e499ed3fe 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/91] soc: mediatek: add compat string for mt7623 to scpsys
+Subject: [PATCH 022/102] soc: mediatek: add compat string for mt7623 to
+ scpsys
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/soc/mediatek/mtk-scpsys-mt2701.c | 2 ++
1 file changed, 2 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-index 339d5b8..3a31946 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt2701.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-@@ -136,6 +136,8 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
+@@ -136,6 +136,8 @@ static const struct of_device_id of_scps
{
.compatible = "mediatek,mt2701-scpsys",
}, {
@@ -21,6 +20,3 @@ index 339d5b8..3a31946 100644
/* sentinel */
}
};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
index edc20b7855..5be3b27eb2 100644
--- a/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
+++ b/target/linux/mediatek/patches-4.4/0023-ARM-dts-mediatek-add-MT7623-basic-support.patch
@@ -1,23 +1,21 @@
-From 83ef9fb21a896ac03c3a78bc3ae0b21f3b0a43a3 Mon Sep 17 00:00:00 2001
+From 51d5ca9e151eb323bd965e72ad1e1dc93fcf7b13 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/91] ARM: dts: mediatek: add MT7623 basic support
+Subject: [PATCH 023/102] ARM: dts: mediatek: add MT7623 basic support
This adds basic chip support for Mediatek MT7623.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/mt7623-evb.dts | 474 +++++++++++++++++++++++++++++
- arch/arm/boot/dts/mt7623.dtsi | 593 +++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7623-evb.dts | 421 ++++++++++++++++++++++++++
+ arch/arm/boot/dts/mt7623.dtsi | 601 +++++++++++++++++++++++++++++++++++++
arch/arm/mach-mediatek/Kconfig | 4 +
arch/arm/mach-mediatek/mediatek.c | 1 +
- 5 files changed, 1073 insertions(+)
+ 5 files changed, 1028 insertions(+)
create mode 100644 arch/arm/boot/dts/mt7623-evb.dts
create mode 100644 arch/arm/boot/dts/mt7623.dtsi
-diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
-index 30bbc37..2bce370 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -774,6 +774,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
@@ -28,12 +26,9 @@ 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..70b92a4
--- /dev/null
+++ b/arch/arm/boot/dts/mt7623-evb.dts
-@@ -0,0 +1,474 @@
+@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
@@ -323,127 +318,32 @@ index 0000000..70b92a4
+ status = "okay";
+};
+
-+&mmc0 {
-+ status = "okay";
-+ pinctrl-names = "default", "state_uhs";
-+ pinctrl-0 = <&mmc0_pins_default>;
-+ pinctrl-1 = <&mmc0_pins_uhs>;
-+ bus-width = <8>;
-+ max-frequency = <50000000>;
-+ cap-mmc-highspeed;
-+ vmmc-supply = <&mt6323_vemc3v3_reg>;
-+ vqmmc-supply = <&mt6323_vio18_reg>;
-+ non-removable;
-+};
-+
-+&mmc1 {
-+ status = "okay";
-+ pinctrl-names = "default", "state_uhs";
-+ pinctrl-0 = <&mmc1_pins_default>;
-+ pinctrl-1 = <&mmc1_pins_uhs>;
-+ bus-width = <4>;
-+ max-frequency = <50000000>;
-+ cap-sd-highspeed;
-+ sd-uhs-sdr25;
-+// cd-gpios = <&pio 132 0>;
-+ vmmc-supply = <&mt6323_vmch_reg>;
-+ vqmmc-supply = <&mt6323_vmc_reg>;
-+};
-+
+&pio {
-+ mmc0_pins_default: mmc0default {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
-+ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
-+ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
-+ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
-+ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
-+ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
-+ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
-+ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
-+ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
-+ input-enable;
-+ bias-pull-up;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
-+ bias-pull-down;
-+ };
-+
-+ pins_rst {
-+ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
-+ bias-pull-up;
++ nand_pins_default: nanddefault {
++ pins_dat {
++ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_NLD7>,
++ <MT7623_PIN_112_MSDC0_DAT6_FUNC_NLD6>,
++ <MT7623_PIN_114_MSDC0_DAT4_FUNC_NLD4>,
++ <MT7623_PIN_118_MSDC0_DAT3_FUNC_NLD3>,
++ <MT7623_PIN_121_MSDC0_DAT0_FUNC_NLD0>,
++ <MT7623_PIN_120_MSDC0_DAT1_FUNC_NLD1>,
++ <MT7623_PIN_113_MSDC0_DAT5_FUNC_NLD5>,
++ <MT7623_PIN_115_MSDC0_RSTB_FUNC_NLD8>,
++ <MT7623_PIN_119_MSDC0_DAT2_FUNC_NLD2>;
++ input-enable;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up;
+ };
-+ };
+
-+ mmc0_pins_uhs: mmc0 {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_111_MSDC0_DAT7_FUNC_MSDC0_DAT7>,
-+ <MT7623_PIN_112_MSDC0_DAT6_FUNC_MSDC0_DAT6>,
-+ <MT7623_PIN_113_MSDC0_DAT5_FUNC_MSDC0_DAT5>,
-+ <MT7623_PIN_114_MSDC0_DAT4_FUNC_MSDC0_DAT4>,
-+ <MT7623_PIN_118_MSDC0_DAT3_FUNC_MSDC0_DAT3>,
-+ <MT7623_PIN_119_MSDC0_DAT2_FUNC_MSDC0_DAT2>,
-+ <MT7623_PIN_120_MSDC0_DAT1_FUNC_MSDC0_DAT1>,
-+ <MT7623_PIN_121_MSDC0_DAT0_FUNC_MSDC0_DAT0>,
-+ <MT7623_PIN_116_MSDC0_CMD_FUNC_MSDC0_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_2mA>;
-+ bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_MSDC0_CLK>;
-+ drive-strength = <MTK_DRIVE_2mA>;
-+ bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
-+ };
-+
-+ pins_rst {
-+ pinmux = <MT7623_PIN_115_MSDC0_RSTB_FUNC_MSDC0_RSTB>;
-+ bias-pull-up;
-+ };
-+ };
-+
-+ mmc1_pins_default: mmc1default {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_107_MSDC1_DAT0_FUNC_MSDC1_DAT0>,
-+ <MT7623_PIN_108_MSDC1_DAT1_FUNC_MSDC1_DAT1>,
-+ <MT7623_PIN_109_MSDC1_DAT2_FUNC_MSDC1_DAT2>,
-+ <MT7623_PIN_110_MSDC1_DAT3_FUNC_MSDC1_DAT3>,
-+ <MT7623_PIN_105_MSDC1_CMD_FUNC_MSDC1_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_4mA>;
++ pins_we {
++ pinmux = <MT7623_PIN_117_MSDC0_CLK_FUNC_NWEB>;
++ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
+ };
+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_106_MSDC1_CLK_FUNC_MSDC1_CLK>;
-+ bias-pull-down;
-+ drive-strength = <MTK_DRIVE_4mA>;
-+ };
-+
-+// pins_insert {
-+// pinmux = <MT8173_PIN_132_I2S0_DATA1_FUNC_GPIO132>;
-+// bias-pull-up;
-+// };
-+ };
-+
-+ mmc1_pins_uhs: mmc1 {
-+ pins_cmd_dat {
-+ pinmux = <MT7623_PIN_107_MSDC1_DAT0_FUNC_MSDC1_DAT0>,
-+ <MT7623_PIN_108_MSDC1_DAT1_FUNC_MSDC1_DAT1>,
-+ <MT7623_PIN_109_MSDC1_DAT2_FUNC_MSDC1_DAT2>,
-+ <MT7623_PIN_110_MSDC1_DAT3_FUNC_MSDC1_DAT3>,
-+ <MT7623_PIN_105_MSDC1_CMD_FUNC_MSDC1_CMD>;
-+ input-enable;
-+ drive-strength = <MTK_DRIVE_4mA>;
-+ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
-+ };
-+
-+ pins_clk {
-+ pinmux = <MT7623_PIN_106_MSDC1_CLK_FUNC_MSDC1_CLK>;
-+ drive-strength = <MTK_DRIVE_4mA>;
++ pins_ale {
++ pinmux = <MT7623_PIN_116_MSDC0_CMD_FUNC_NALE>;
++ drive-strength = <MTK_DRIVE_8mA>;
+ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+ };
+ };
@@ -474,6 +374,48 @@ index 0000000..70b92a4
+ };
+};
+
++&nandc {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&nand_pins_default>;
++ nand@0 {
++ reg = <0>;
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ partition@C0000 {
++ label = "uboot-env";
++ reg = <0xC0000 0x40000>;
++ };
++
++ partition@100000 {
++ label = "factory";
++ reg = <0x100000 0x40000>;
++ };
++
++ partition@140000 {
++ label = "kernel";
++ reg = <0x140000 0x2000000>;
++ };
++
++ partition@2140000 {
++ label = "recovery";
++ reg = <0x2140000 0x2000000>;
++ };
++
++ partition@4140000 {
++ label = "rootfs";
++ reg = <0x4140000 0x1000000>;
++ };
++ };
++ };
++};
++&bch {
++ status = "okay";
++};
++
+&usb1 {
+ vusb33-supply = <&mt6323_vusb_reg>;
+ vbus-supply = <&usb_p1_vbus>;
@@ -508,12 +450,9 @@ index 0000000..70b92a4
+ 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..80c1ab8
--- /dev/null
+++ b/arch/arm/boot/dts/mt7623.dtsi
-@@ -0,0 +1,593 @@
+@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: John Crispin <blogic@openwrt.org>
@@ -854,6 +793,7 @@ index 0000000..80c1ab8
+ compatible = "mediatek,mt2701-nfc";
+ reg = <0 0x1100d000 0 0x1000>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
++ power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
+ clocks = <&pericfg CLK_PERI_NFI>,
+ <&pericfg CLK_PERI_NFI_PAD>;
+ clock-names = "nfi_clk", "pad_clk";
@@ -1073,8 +1013,15 @@ index 0000000..80c1ab8
+ compatible = "mediatek,eth-mac";
+ reg = <1>;
+
-+ phy-handle = <&phy5>;
+ status = "disabled";
++
++ phy-mode = "rgmii";
++
++ fixed-link {
++ speed = <1000>;
++ full-duplex;
++ pause;
++ };
+ };
+
+ mdio-bus {
@@ -1107,8 +1054,6 @@ index 0000000..80c1ab8
+ 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
@@ -1122,11 +1067,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 void __init mediatek_timer_init(v
static const char * const mediatek_board_dt_compat[] = {
"mediatek,mt6589",
"mediatek,mt6592",
@@ -1134,6 +1077,3 @@ index d019a08..bcfca37 100644
"mediatek,mt8127",
"mediatek,mt8135",
NULL,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
index 4874373ad5..d6fe977793 100644
--- a/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
+++ b/target/linux/mediatek/patches-4.4/0024-dt-bindings-add-MediaTek-PCIe-binding-documentation.patch
@@ -1,7 +1,7 @@
-From 427a938858630fe4cec1b3829624676a4106d236 Mon Sep 17 00:00:00 2001
+From 05be818061b9f2a0fa5ad0cde6881917ff14a2f2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 6 Jan 2016 21:55:10 +0100
-Subject: [PATCH 24/91] dt-bindings: add MediaTek PCIe binding documentation
+Subject: [PATCH 024/102] dt-bindings: add MediaTek PCIe binding documentation
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -9,9 +9,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
1 file changed, 140 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
-new file mode 100644
-index 0000000..8fea3ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt
@@ -0,0 +1,140 @@
@@ -155,6 +152,3 @@ index 0000000..8fea3ed
+ status = "okay";
+ };
+ };
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
index a6534b6643..bcb109d6a9 100644
--- a/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
+++ b/target/linux/mediatek/patches-4.4/0025-PCI-mediatek-add-support-for-PCIe-found-on-MT7623-MT.patch
@@ -1,7 +1,7 @@
-From 5571cc63036daf0e0a05f07b0137fee86d58acb0 Mon Sep 17 00:00:00 2001
+From 8ab1d4e0a9a68e03f472dee1c036a01d0198c20c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 5 Jan 2016 20:20:04 +0100
-Subject: [PATCH 25/91] PCI: mediatek: add support for PCIe found on
+Subject: [PATCH 025/102] PCI: mediatek: add support for PCIe found on
MT7623/MT2701
Add PCIe controller support on MediaTek MT2701/MT7623. The driver supports
@@ -17,8 +17,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
4 files changed, 654 insertions(+)
create mode 100644 drivers/pci/host/pcie-mediatek.c
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index 7fb605e..a7fef77 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -24,6 +24,7 @@ config MACH_MT6592
@@ -29,11 +27,9 @@ index 7fb605e..a7fef77 100644
config MACH_MT8127
bool "MediaTek MT8127 SoCs support"
-diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
-index f131ba9..912f0e1 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
-@@ -172,4 +172,15 @@ config PCI_HISI
+@@ -173,4 +173,15 @@ config PCI_HISI
help
Say Y here if you want PCIe controller support on HiSilicon HIP05 SoC
@@ -49,18 +45,13 @@ index f131ba9..912f0e1 100644
+ PCIe include one Host/PCI bridge and 3 PCIe MAC.
+
endmenu
-diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
-index 9d4d3c6..3b53374 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
-@@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
+@@ -20,3 +20,4 @@ obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-ip
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
obj-$(CONFIG_PCI_HISI) += pcie-hisi.o
+obj-$(CONFIG_PCIE_MTK) += pcie-mediatek.o
-diff --git a/drivers/pci/host/pcie-mediatek.c b/drivers/pci/host/pcie-mediatek.c
-new file mode 100644
-index 0000000..ef03952
--- /dev/null
+++ b/drivers/pci/host/pcie-mediatek.c
@@ -0,0 +1,641 @@
@@ -705,6 +696,3 @@ index 0000000..ef03952
+}
+
+module_init(mtk_pcie_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
index 7f64c518a1..7ec3033463 100644
--- a/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
+++ b/target/linux/mediatek/patches-4.4/0026-scpsys-various-fixes.patch
@@ -1,7 +1,7 @@
-From a366216a08408949eca2d7823273da6826d3c483 Mon Sep 17 00:00:00 2001
+From 59aafd667d2880c90776931b6102b8252214d93c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 21 Feb 2016 13:52:12 +0100
-Subject: [PATCH 26/91] scpsys: various fixes
+Subject: [PATCH 026/102] scpsys: various fixes
---
drivers/clk/mediatek/clk-mt2701.c | 2 ++
@@ -9,11 +9,9 @@ Subject: [PATCH 26/91] scpsys: various fixes
include/dt-bindings/power/mt2701-power.h | 4 ++--
3 files changed, 4 insertions(+), 10 deletions(-)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 0e40bb8..812b347 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struct device_node *node)
+@@ -1043,6 +1043,8 @@ static void __init mtk_ethsys_init(struc
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -22,11 +20,9 @@ index 0e40bb8..812b347 100644
}
CLK_OF_DECLARE(mtk_ethsys, "mediatek,mt2701-ethsys", mtk_ethsys_init);
-diff --git a/drivers/soc/mediatek/mtk-scpsys-mt2701.c b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-index 3a31946..19489bc 100644
--- a/drivers/soc/mediatek/mtk-scpsys-mt2701.c
+++ b/drivers/soc/mediatek/mtk-scpsys-mt2701.c
-@@ -61,14 +61,6 @@ static const struct scp_domain_data scp_domain_data[] = {
+@@ -61,14 +61,6 @@ static const struct scp_domain_data scp_
.bus_prot_mask = MT2701_TOP_AXI_PROT_EN_DISP,
.active_wakeup = true,
},
@@ -41,8 +37,6 @@ index 3a31946..19489bc 100644
[MT2701_POWER_DOMAIN_VDEC] = {
.name = "vdec",
.sta_mask = VDE_PWR_STA_MASK,
-diff --git a/include/dt-bindings/power/mt2701-power.h b/include/dt-bindings/power/mt2701-power.h
-index 64cc826..c168597 100644
--- a/include/dt-bindings/power/mt2701-power.h
+++ b/include/dt-bindings/power/mt2701-power.h
@@ -16,12 +16,12 @@
@@ -60,6 +54,3 @@ index 64cc826..c168597 100644
+#define MT2701_POWER_DOMAIN_IFR_MSC 2
#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
index dfd274b1e2..964373bf49 100644
--- a/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
+++ b/target/linux/mediatek/patches-4.4/0027-soc-mediatek-PMIC-wrap-Clear-the-vldclr-if-state-mac.patch
@@ -1,7 +1,7 @@
-From 4d02177361d13355d98a38830c69bb9add3c109c Mon Sep 17 00:00:00 2001
+From 55231d8299d3dccde8588ed2e86c2bc0ef2e12ce 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/91] soc: mediatek: PMIC wrap: Clear the vldclr if state
+Subject: [PATCH 027/102] 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,
@@ -20,11 +20,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
drivers/soc/mediatek/mtk-pmic-wrap.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 105597a..696071b 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
-@@ -412,6 +412,20 @@ static bool pwrap_is_fsm_vldclr(struct pmic_wrapper *wrp)
+@@ -412,6 +412,20 @@ static bool pwrap_is_fsm_vldclr(struct p
return PWRAP_GET_WACS_FSM(val) == PWRAP_WACS_FSM_WFVLDCLR;
}
@@ -45,7 +43,7 @@ index 105597a..696071b 100644
static bool pwrap_is_sync_idle(struct pmic_wrapper *wrp)
{
return pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_SYNC_IDLE0;
-@@ -445,8 +459,10 @@ static int pwrap_write(struct pmic_wrapper *wrp, u32 adr, u32 wdata)
+@@ -445,8 +459,10 @@ static int pwrap_write(struct pmic_wrapp
int ret;
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
@@ -57,7 +55,7 @@ index 105597a..696071b 100644
pwrap_writel(wrp, (1 << 31) | ((adr >> 1) << 16) | wdata,
PWRAP_WACS2_CMD);
-@@ -459,8 +475,10 @@ static int pwrap_read(struct pmic_wrapper *wrp, u32 adr, u32 *rdata)
+@@ -459,8 +475,10 @@ static int pwrap_read(struct pmic_wrappe
int ret;
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle);
@@ -69,6 +67,3 @@ index 105597a..696071b 100644
pwrap_writel(wrp, (adr >> 1) << 16, PWRAP_WACS2_CMD);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
index 8c22fd9a26..4aacd26a1f 100644
--- a/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
+++ b/target/linux/mediatek/patches-4.4/0028-ARM-mediatek-add-MT7623-smp-bringup-code.patch
@@ -1,7 +1,7 @@
-From e4a5c39f75a11ecb78d1243b19b929af54f888fa Mon Sep 17 00:00:00 2001
+From d088a94afc768683a881b627b6737442158e7db6 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/91] ARM: mediatek: add MT7623 smp bringup code
+Subject: [PATCH 028/102] ARM: mediatek: add MT7623 smp bringup code
Add support for booting secondary CPUs on MT7623.
@@ -11,11 +11,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
arch/arm/mach-mediatek/platsmp.c | 7 +++++++
1 file changed, 7 insertions(+)
-diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
-index 8141f3f..8151400 100644
--- a/arch/arm/mach-mediatek/platsmp.c
+++ b/arch/arm/mach-mediatek/platsmp.c
-@@ -44,6 +44,12 @@ static const struct mtk_smp_boot_info mtk_mt6589_boot = {
+@@ -44,6 +44,12 @@ static const struct mtk_smp_boot_info mt
{ 0x38, 0x3c, 0x40 },
};
@@ -28,7 +26,7 @@ index 8141f3f..8151400 100644
static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
{ .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
-@@ -51,6 +57,7 @@ static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
+@@ -51,6 +57,7 @@ static const struct of_device_id mtk_tz_
static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt6589", .data = &mtk_mt6589_boot },
@@ -36,6 +34,3 @@ index 8141f3f..8151400 100644
};
static void __iomem *mtk_smp_base;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
index 6ad960ec42..eb936a789b 100644
--- a/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
+++ b/target/linux/mediatek/patches-4.4/0029-soc-mediatek-PMIC-wrap-clear-the-STAUPD_TRIG-bit-of-.patch
@@ -1,8 +1,8 @@
-From b4a6293df00036129d26a7f06bfb220ba5a73c42 Mon Sep 17 00:00:00 2001
+From b92861fbc79b3a7a9bc1c51e2dbfa2c191cc27ea 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/91] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit of
- WDT_SRC_EN
+Subject: [PATCH 029/102] soc: mediatek: PMIC wrap: clear the STAUPD_TRIG bit
+ of WDT_SRC_EN
Since STAUPD interrupts aren't handled on mt8173, disable watchdog timeout
monitor of STAUPD to avoid WDT_INT triggered by STAUPD.
@@ -14,8 +14,6 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
drivers/soc/mediatek/mtk-pmic-wrap.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 696071b..0d9b19a 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -60,6 +60,15 @@
@@ -34,7 +32,7 @@ index 696071b..0d9b19a 100644
/* macro for slave device wrapper registers */
#define PWRAP_DEW_BASE 0xbc00
#define PWRAP_DEW_EVENT_OUT_EN (PWRAP_DEW_BASE + 0x0)
-@@ -822,7 +831,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+@@ -822,7 +831,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_t
static int pwrap_probe(struct platform_device *pdev)
{
@@ -43,7 +41,7 @@ index 696071b..0d9b19a 100644
struct pmic_wrapper *wrp;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
-@@ -912,7 +921,13 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -912,7 +921,13 @@ static int pwrap_probe(struct platform_d
/* Initialize watchdog, may not be done by the bootloader */
pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
@@ -58,6 +56,3 @@ index 696071b..0d9b19a 100644
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
index 61fa475046..790ccca1ff 100644
--- a/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
+++ b/target/linux/mediatek/patches-4.4/0030-ARM-mediatek-add-mt2701-smp-bringup-code.patch
@@ -1,7 +1,7 @@
-From 0befbd007b72ba2b14c65558d3bb72ea885496f6 Mon Sep 17 00:00:00 2001
+From f88ec31c6ba3a006d0be87ff1d99145f8cc85bee 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/91] ARM: mediatek: add mt2701 smp bringup code
+Subject: [PATCH 030/102] ARM: mediatek: add mt2701 smp bringup code
Add support for booting secondary CPUs on mt2701.
@@ -11,11 +11,9 @@ Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
arch/arm/mach-mediatek/platsmp.c | 1 +
1 file changed, 1 insertion(+)
-diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
-index 8151400..2078f92d5 100644
--- a/arch/arm/mach-mediatek/platsmp.c
+++ b/arch/arm/mach-mediatek/platsmp.c
-@@ -53,6 +53,7 @@ static const struct mtk_smp_boot_info mtk_mt7623_boot = {
+@@ -53,6 +53,7 @@ static const struct mtk_smp_boot_info mt
static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
{ .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
{ .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
@@ -23,6 +21,3 @@ index 8151400..2078f92d5 100644
};
static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
index dd20cca520..186b2f4e34 100644
--- a/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
+++ b/target/linux/mediatek/patches-4.4/0031-dt-bindings-ARM-Mediatek-add-MT2701-7623-string-to-t.patch
@@ -1,8 +1,8 @@
-From 9367fb14e1be8dd174f8d63ec83f7ee2d90ae733 Mon Sep 17 00:00:00 2001
+From 15f4d895578f02cbaed10b0f5f6853b873aba10b 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/91] dt-bindings: ARM: Mediatek: add MT2701/7623 string to
- the PMIC wrapper doc
+Subject: [PATCH 031/102] dt-bindings: ARM: Mediatek: add MT2701/7623 string
+ to the PMIC wrapper doc
Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: Rob Herring <robh@kernel.org>
@@ -11,8 +11,6 @@ Cc: devicetree@vger.kernel.org
Documentation/devicetree/bindings/soc/mediatek/pwrap.txt | 1 +
1 file changed, 1 insertion(+)
-diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
-index ddeb5b6..107700d 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
@@ -18,6 +18,7 @@ IP Pairing
@@ -23,6 +21,3 @@ index ddeb5b6..107700d 100644
"mediatek,mt8135-pwrap" for MT8135 SoCs
"mediatek,mt8173-pwrap" for MT8173 SoCs
- interrupts: IRQ for pwrap in SOC
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
index e350f445f2..8092e96d71 100644
--- a/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
+++ b/target/linux/mediatek/patches-4.4/0032-soc-mediatek-PMIC-wrap-don-t-duplicate-the-wrapper-d.patch
@@ -1,8 +1,8 @@
-From 7b7d59b4219c30e1b9601300348f1431fdab7081 Mon Sep 17 00:00:00 2001
+From 64e8091be39c3f0a7bf4651bd2045b8c86429d55 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/91] soc: mediatek: PMIC wrap: don't duplicate the wrapper
- data
+Subject: [PATCH 032/102] soc: mediatek: PMIC wrap: don't duplicate the
+ wrapper data
As we add support for more devices struct pmic_wrapper_type will grow and
we do not really want to start duplicating all the elements in
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 0d9b19a..340c4b5 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -376,9 +376,7 @@ struct pmic_wrapper {
@@ -55,7 +53,7 @@ index 0d9b19a..340c4b5 100644
}
static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp)
-@@ -697,7 +695,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -697,7 +695,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_WRAP_EN);
@@ -64,7 +62,7 @@ index 0d9b19a..340c4b5 100644
pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
-@@ -742,7 +740,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -742,7 +740,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 0x1, PWRAP_CRC_EN);
pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE);
pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR);
@@ -73,7 +71,7 @@ index 0d9b19a..340c4b5 100644
if (pwrap_is_mt8135(wrp))
pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
-@@ -836,7 +834,6 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -836,7 +834,6 @@ static int pwrap_probe(struct platform_d
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(of_pwrap_match_tbl, &pdev->dev);
@@ -81,7 +79,7 @@ index 0d9b19a..340c4b5 100644
struct resource *res;
wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
-@@ -845,10 +842,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -845,10 +842,7 @@ static int pwrap_probe(struct platform_d
platform_set_drvdata(pdev, wrp);
@@ -93,6 +91,3 @@ index 0d9b19a..340c4b5 100644
wrp->dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
index 9b37004c46..9368a85f82 100644
--- a/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
+++ b/target/linux/mediatek/patches-4.4/0033-soc-mediatek-PMIC-wrap-add-wrapper-callbacks-for-ini.patch
@@ -1,7 +1,7 @@
-From 35d879d80437cc6ed811538903e115dbcda777ac Mon Sep 17 00:00:00 2001
+From 756b919b7874cc241a276b4fc5bbec5b3fb4bca8 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/91] soc: mediatek: PMIC wrap: add wrapper callbacks for
+Subject: [PATCH 033/102] soc: mediatek: PMIC wrap: add wrapper callbacks for
init_reg_clock
Split init_reg_clock up into SoC specific callbacks. The patch also
@@ -12,8 +12,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 70 ++++++++++++++++++----------------
1 file changed, 38 insertions(+), 32 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 340c4b5..b22b664 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -354,24 +354,6 @@ enum pwrap_type {
@@ -55,7 +53,7 @@ index 340c4b5..b22b664 100644
static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp)
{
return wrp->master->type == PWRAP_MT8135;
-@@ -578,20 +567,23 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+@@ -578,20 +567,23 @@ static int pwrap_init_sidly(struct pmic_
return 0;
}
@@ -92,7 +90,7 @@ index 340c4b5..b22b664 100644
return 0;
}
-@@ -699,7 +691,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -699,7 +691,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_WACS2_EN);
@@ -101,7 +99,7 @@ index 340c4b5..b22b664 100644
if (ret)
return ret;
-@@ -814,6 +806,20 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -814,6 +806,20 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -122,6 +120,3 @@ index 340c4b5..b22b664 100644
static struct of_device_id of_pwrap_match_tbl[] = {
{
.compatible = "mediatek,mt8135-pwrap",
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
index cb90f1e82f..6d9c99a695 100644
--- a/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
+++ b/target/linux/mediatek/patches-4.4/0034-soc-mediatek-PMIC-wrap-split-SoC-specific-init-into-.patch
@@ -1,8 +1,8 @@
-From d82889cec95358b917fcf29fc3214980deb138b9 Mon Sep 17 00:00:00 2001
+From a1bbd630710d5da89a9c347c84d7badd30e7e68a 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/91] soc: mediatek: PMIC wrap: split SoC specific init into
- callback
+Subject: [PATCH 034/102] soc: mediatek: PMIC wrap: split SoC specific init
+ into callback
This patch moves the SoC specific wrapper init code into separate callback
to avoid pwrap_init() getting too large. This is done by adding a new
@@ -16,8 +16,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 67 +++++++++++++++++++++-------------
1 file changed, 42 insertions(+), 25 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index b22b664..22c89e9 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -372,6 +372,7 @@ struct pmic_wrapper_type {
@@ -28,7 +26,7 @@ index b22b664..22c89e9 100644
};
static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp)
-@@ -665,6 +666,41 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -665,6 +666,41 @@ static int pwrap_init_cipher(struct pmic
return 0;
}
@@ -70,7 +68,7 @@ index b22b664..22c89e9 100644
static int pwrap_init(struct pmic_wrapper *wrp)
{
int ret;
-@@ -743,31 +779,10 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -743,31 +779,10 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
@@ -106,7 +104,7 @@ index b22b664..22c89e9 100644
}
/* Setup the init done registers */
-@@ -811,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -811,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
.init_reg_clock = pwrap_mt8135_init_reg_clock,
@@ -114,7 +112,7 @@ index b22b664..22c89e9 100644
};
static struct pmic_wrapper_type pwrap_mt8173 = {
-@@ -818,6 +834,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -818,6 +834,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
.init_reg_clock = pwrap_mt8173_init_reg_clock,
@@ -122,6 +120,3 @@ index b22b664..22c89e9 100644
};
static struct of_device_id of_pwrap_match_tbl[] = {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
index 7a27a6c493..42fbe2e1ca 100644
--- a/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
+++ b/target/linux/mediatek/patches-4.4/0035-soc-mediatek-PMIC-wrap-WRAP_INT_EN-needs-a-different.patch
@@ -1,7 +1,7 @@
-From 613acba0068461948e6b5283df03d7c1e1583a40 Mon Sep 17 00:00:00 2001
+From 274fd9ba57170de88bbdf522cbd6c290c2e51fb8 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/91] soc: mediatek: PMIC wrap: WRAP_INT_EN needs a
+Subject: [PATCH 035/102] 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.
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 22c89e9..9df1135 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -371,6 +371,7 @@ struct pmic_wrapper_type {
@@ -23,7 +21,7 @@ index 22c89e9..9df1135 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -825,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -825,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt
.regs = mt8135_regs,
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
@@ -31,7 +29,7 @@ index 22c89e9..9df1135 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -833,6 +835,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -833,6 +835,7 @@ static struct pmic_wrapper_type pwrap_mt
.regs = mt8173_regs,
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
@@ -39,7 +37,7 @@ index 22c89e9..9df1135 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -946,7 +949,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -946,7 +949,7 @@ static int pwrap_probe(struct platform_d
PWRAP_WDT_SRC_MASK_NO_STAUPD : PWRAP_WDT_SRC_MASK_ALL;
pwrap_writel(wrp, wdt_src, PWRAP_WDT_SRC_EN);
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
@@ -48,6 +46,3 @@ index 22c89e9..9df1135 100644
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
index f88981c31e..a80bd731d9 100644
--- a/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
+++ b/target/linux/mediatek/patches-4.4/0036-soc-mediatek-PMIC-wrap-SPI_WRITE-needs-a-different-b.patch
@@ -1,8 +1,8 @@
-From 1186088ab86b7286e1920dcbfbbbf2627a0daeda Mon Sep 17 00:00:00 2001
+From 511e697282c6425950b95373ac8dc59a42fd2485 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/91] soc: mediatek: PMIC wrap: SPI_WRITE needs a different
- bitmask for MT2701/7623
+Subject: [PATCH 036/102] 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
patch defines the bitmask in the pmic_wrapper_type struct. This allows us
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 9df1135..8ce1bad 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -372,6 +372,7 @@ struct pmic_wrapper_type {
@@ -25,7 +23,7 @@ index 9df1135..8ce1bad 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -511,15 +512,15 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp)
+@@ -511,15 +512,15 @@ static int pwrap_reset_spislave(struct p
pwrap_writel(wrp, 1, PWRAP_MAN_EN);
pwrap_writel(wrp, 0, PWRAP_DIO_EN);
@@ -45,7 +43,7 @@ index 9df1135..8ce1bad 100644
PWRAP_MAN_CMD);
ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle);
-@@ -827,6 +828,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -827,6 +828,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8135,
.arb_en_all = 0x1ff,
.int_en_all = ~(BIT(31) | BIT(1)),
@@ -53,7 +51,7 @@ index 9df1135..8ce1bad 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -836,6 +838,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -836,6 +838,7 @@ static struct pmic_wrapper_type pwrap_mt
.type = PWRAP_MT8173,
.arb_en_all = 0x3f,
.int_en_all = ~(BIT(31) | BIT(1)),
@@ -61,6 +59,3 @@ index 9df1135..8ce1bad 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
index cccbe1034f..1e2c587605 100644
--- a/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
+++ b/target/linux/mediatek/patches-4.4/0037-soc-mediatek-PMIC-wrap-move-wdt_src-into-the-pmic_wr.patch
@@ -1,7 +1,7 @@
-From 95f72db32afd545b88eaa04802736f1f84242a9f Mon Sep 17 00:00:00 2001
+From 6aecbc79322efd3068c6140f74a68654fbe5b5f6 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/91] soc: mediatek: PMIC wrap: move wdt_src into the
+Subject: [PATCH 037/102] 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
@@ -13,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 8ce1bad..aa54df3 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -373,6 +373,7 @@ struct pmic_wrapper_type {
@@ -25,7 +23,7 @@ index 8ce1bad..aa54df3 100644
int (*init_reg_clock)(struct pmic_wrapper *wrp);
int (*init_soc_specific)(struct pmic_wrapper *wrp);
};
-@@ -829,6 +830,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -829,6 +830,7 @@ static struct pmic_wrapper_type pwrap_mt
.arb_en_all = 0x1ff,
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
@@ -33,7 +31,7 @@ index 8ce1bad..aa54df3 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -839,6 +841,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -839,6 +841,7 @@ static struct pmic_wrapper_type pwrap_mt
.arb_en_all = 0x3f,
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
@@ -41,7 +39,7 @@ index 8ce1bad..aa54df3 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -858,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl);
+@@ -858,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_t
static int pwrap_probe(struct platform_device *pdev)
{
@@ -50,7 +48,7 @@ index 8ce1bad..aa54df3 100644
struct pmic_wrapper *wrp;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
-@@ -948,9 +951,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -948,9 +951,7 @@ static int pwrap_probe(struct platform_d
* Since STAUPD was not used on mt8173 platform,
* so STAUPD of WDT_SRC which should be turned off
*/
@@ -61,6 +59,3 @@ index 8ce1bad..aa54df3 100644
pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
index 7f8a2930a5..001793f585 100644
--- a/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
+++ b/target/linux/mediatek/patches-4.4/0038-soc-mediatek-PMIC-wrap-remove-pwrap_is_mt8135-and-pw.patch
@@ -1,8 +1,8 @@
-From bb19fd13b1ed629873ea144b22c4764aa4baa5ef Mon Sep 17 00:00:00 2001
+From da09b34ad22e8f065a02af114668f7d86357244a 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/91] soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and
- pwrap_is_mt8173()
+Subject: [PATCH 038/102] 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
grow. To mitigate this problem we remove the existing helpers and change
@@ -18,8 +18,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index aa54df3..a2bacda 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -374,20 +374,11 @@ struct pmic_wrapper_type {
@@ -44,7 +42,7 @@ index aa54df3..a2bacda 100644
static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg)
{
return readl(wrp->base + wrp->master->regs[reg]);
-@@ -619,11 +610,14 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -619,11 +610,14 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 0x1, PWRAP_CIPHER_KEY_SEL);
pwrap_writel(wrp, 0x2, PWRAP_CIPHER_IV_SEL);
@@ -61,7 +59,7 @@ index aa54df3..a2bacda 100644
}
/* Config cipher mode @PMIC */
-@@ -713,7 +707,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -713,7 +707,7 @@ static int pwrap_init(struct pmic_wrappe
if (wrp->rstc_bridge)
reset_control_reset(wrp->rstc_bridge);
@@ -70,7 +68,7 @@ index aa54df3..a2bacda 100644
/* Enable DCM */
pwrap_writel(wrp, 3, PWRAP_DCM_EN);
pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
-@@ -773,7 +767,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -773,7 +767,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR);
pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
@@ -79,7 +77,7 @@ index aa54df3..a2bacda 100644
pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN);
pwrap_writel(wrp, 0x1, PWRAP_WACS0_EN);
-@@ -793,7 +787,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -793,7 +787,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
@@ -88,7 +86,7 @@ index aa54df3..a2bacda 100644
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
}
-@@ -831,6 +825,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = {
+@@ -831,6 +825,7 @@ static struct pmic_wrapper_type pwrap_mt
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_ALL,
@@ -96,7 +94,7 @@ index aa54df3..a2bacda 100644
.init_reg_clock = pwrap_mt8135_init_reg_clock,
.init_soc_specific = pwrap_mt8135_init_soc_specific,
};
-@@ -842,6 +837,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -842,6 +837,7 @@ static struct pmic_wrapper_type pwrap_mt
.int_en_all = ~(BIT(31) | BIT(1)),
.spi_w = PWRAP_MAN_CMD_SPI_WRITE,
.wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
@@ -104,7 +102,7 @@ index aa54df3..a2bacda 100644
.init_reg_clock = pwrap_mt8173_init_reg_clock,
.init_soc_specific = pwrap_mt8173_init_soc_specific,
};
-@@ -889,7 +885,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -889,7 +885,7 @@ static int pwrap_probe(struct platform_d
return ret;
}
@@ -113,6 +111,3 @@ index aa54df3..a2bacda 100644
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pwrap-bridge");
wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
index 5fb66dbb5c..dea271af66 100644
--- a/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
+++ b/target/linux/mediatek/patches-4.4/0039-soc-mediatek-PMIC-wrap-add-a-slave-specific-struct.patch
@@ -1,7 +1,8 @@
-From daa4d054bb0557799c8b324d7aa5f0a3a4a7b078 Mon Sep 17 00:00:00 2001
+From 21bdcd324f769545b1765fe391d939a1edd07cbb 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/91] soc: mediatek: PMIC wrap: add a slave specific struct
+Subject: [PATCH 039/102] 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
@@ -12,8 +13,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 159 ++++++++++++++++++++++++----------
1 file changed, 112 insertions(+), 47 deletions(-)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index a2bacda..bcc841e 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -69,33 +69,54 @@
@@ -125,7 +124,7 @@ index a2bacda..bcc841e 100644
struct clk *clk_spi;
struct clk *clk_wrap;
struct reset_control *rstc;
-@@ -544,7 +575,8 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp)
+@@ -544,7 +575,8 @@ static int pwrap_init_sidly(struct pmic_
for (i = 0; i < 4; i++) {
pwrap_writel(wrp, i, PWRAP_SIDLY);
@@ -135,7 +134,7 @@ index a2bacda..bcc841e 100644
if (rdata == PWRAP_DEW_READ_TEST_VAL) {
dev_dbg(wrp->dev, "[Read Test] pass, SIDLY=%x\n", i);
pass |= 1 << i;
-@@ -593,7 +625,8 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
+@@ -593,7 +625,8 @@ static bool pwrap_is_pmic_cipher_ready(s
u32 rdata;
int ret;
@@ -145,7 +144,7 @@ index a2bacda..bcc841e 100644
if (ret)
return 0;
-@@ -621,12 +654,12 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -621,12 +654,12 @@ static int pwrap_init_cipher(struct pmic
}
/* Config cipher mode @PMIC */
@@ -164,7 +163,7 @@ index a2bacda..bcc841e 100644
/* wait for cipher data ready@AP */
ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
-@@ -643,7 +676,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -643,7 +676,7 @@ static int pwrap_init_cipher(struct pmic
}
/* wait for cipher mode idle */
@@ -173,7 +172,7 @@ index a2bacda..bcc841e 100644
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
if (ret) {
dev_err(wrp->dev, "cipher mode idle fail, ret=%d\n", ret);
-@@ -653,9 +686,11 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -653,9 +686,11 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 1, PWRAP_CIPHER_MODE);
/* Write Test */
@@ -188,7 +187,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "rdata=0x%04X\n", rdata);
return -EFAULT;
}
-@@ -677,8 +712,10 @@ static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -677,8 +712,10 @@ static int pwrap_mt8135_init_soc_specifi
writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN);
/* enable PMIC event out and sources */
@@ -201,7 +200,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "enable dewrap fail\n");
return -EFAULT;
}
-@@ -689,8 +726,10 @@ static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -689,8 +726,10 @@ static int pwrap_mt8135_init_soc_specifi
static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp)
{
/* PMIC_DEWRAP enables */
@@ -214,7 +213,7 @@ index a2bacda..bcc841e 100644
dev_err(wrp->dev, "enable dewrap fail\n");
return -EFAULT;
}
-@@ -734,7 +773,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -734,7 +773,7 @@ static int pwrap_init(struct pmic_wrappe
return ret;
/* Enable dual IO mode */
@@ -223,7 +222,7 @@ index a2bacda..bcc841e 100644
/* Check IDLE & INIT_DONE in advance */
ret = pwrap_wait_for_state(wrp, pwrap_is_fsm_idle_and_sync_idle);
-@@ -746,7 +785,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -746,7 +785,7 @@ static int pwrap_init(struct pmic_wrappe
pwrap_writel(wrp, 1, PWRAP_DIO_EN);
/* Read Test */
@@ -232,7 +231,7 @@ index a2bacda..bcc841e 100644
if (rdata != PWRAP_DEW_READ_TEST_VAL) {
dev_err(wrp->dev, "Read test failed after switch to DIO mode: 0x%04x != 0x%04x\n",
PWRAP_DEW_READ_TEST_VAL, rdata);
-@@ -759,12 +798,13 @@ static int pwrap_init(struct pmic_wrapper *wrp)
+@@ -759,12 +798,13 @@ static int pwrap_init(struct pmic_wrappe
return ret;
/* Signature checking - using CRC */
@@ -248,7 +247,7 @@ index a2bacda..bcc841e 100644
pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN);
if (wrp->master->type == PWRAP_MT8135)
-@@ -818,6 +858,21 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -818,6 +858,21 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -270,7 +269,7 @@ index a2bacda..bcc841e 100644
static struct pmic_wrapper_type pwrap_mt8135 = {
.regs = mt8135_regs,
.type = PWRAP_MT8135,
-@@ -862,8 +917,17 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -862,8 +917,17 @@ static int pwrap_probe(struct platform_d
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(of_pwrap_match_tbl, &pdev->dev);
@@ -288,7 +287,7 @@ index a2bacda..bcc841e 100644
wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL);
if (!wrp)
return -ENOMEM;
-@@ -871,6 +935,7 @@ static int pwrap_probe(struct platform_device *pdev)
+@@ -871,6 +935,7 @@ static int pwrap_probe(struct platform_d
platform_set_drvdata(pdev, wrp);
wrp->master = of_id->data;
@@ -296,6 +295,3 @@ index a2bacda..bcc841e 100644
wrp->dev = &pdev->dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap");
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
index 509ba3346c..51f06288fb 100644
--- a/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
+++ b/target/linux/mediatek/patches-4.4/0040-soc-mediatek-PMIC-wrap-add-mt6323-slave-support.patch
@@ -1,7 +1,7 @@
-From 15143b59a26a06e890e2ba3c9944b3f751ce39bd Mon Sep 17 00:00:00 2001
+From 4418ba9a0bb105f00259d10ceb16f9e27199e9b0 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/91] soc: mediatek: PMIC wrap: add mt6323 slave support
+Subject: [PATCH 040/102] 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().
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 43 ++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index bcc841e..0e4ebb8 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -93,6 +93,27 @@ enum dew_regs {
@@ -51,7 +49,7 @@ index bcc841e..0e4ebb8 100644
PMIC_MT6397,
};
-@@ -661,6 +683,19 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -661,6 +683,19 @@ static int pwrap_init_cipher(struct pmic
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1);
pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1);
@@ -71,7 +69,7 @@ index bcc841e..0e4ebb8 100644
/* wait for cipher data ready@AP */
ret = pwrap_wait_for_state(wrp, pwrap_is_cipher_ready);
if (ret) {
-@@ -858,6 +893,11 @@ static const struct regmap_config pwrap_regmap_config = {
+@@ -858,6 +893,11 @@ static const struct regmap_config pwrap_
.max_register = 0xffff,
};
@@ -83,7 +81,7 @@ index bcc841e..0e4ebb8 100644
static const struct pwrap_slv_type pmic_mt6397 = {
.dew_regs = mt6397_regs,
.type = PMIC_MT6397,
-@@ -865,6 +905,9 @@ static const struct pwrap_slv_type pmic_mt6397 = {
+@@ -865,6 +905,9 @@ static const struct pwrap_slv_type pmic_
static const struct of_device_id of_slave_match_tbl[] = {
{
@@ -93,6 +91,3 @@ index bcc841e..0e4ebb8 100644
.compatible = "mediatek,mt6397",
.data = &pmic_mt6397,
}, {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
index b575405ab6..a50a34af6a 100644
--- a/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
+++ b/target/linux/mediatek/patches-4.4/0041-soc-mediatek-PMIC-wrap-add-MT2701-7623-support.patch
@@ -1,7 +1,7 @@
-From 2f5df30a7b913069c8fce22dc702e0d7c76ef361 Mon Sep 17 00:00:00 2001
+From 7736d97fe2c6c71c9009a1b45a94de06bfc94a37 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/91] soc: mediatek: PMIC wrap: add MT2701/7623 support
+Subject: [PATCH 041/102] 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.
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/soc/mediatek/mtk-pmic-wrap.c | 154 ++++++++++++++++++++++++++++++++++
1 file changed, 154 insertions(+)
-diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
-index 0e4ebb8..3c3e56d 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -52,6 +52,7 @@
@@ -138,7 +136,7 @@ index 0e4ebb8..3c3e56d 100644
PWRAP_MT8135,
PWRAP_MT8173,
};
-@@ -637,6 +732,31 @@ static int pwrap_mt8173_init_reg_clock(struct pmic_wrapper *wrp)
+@@ -637,6 +732,31 @@ static int pwrap_mt8173_init_reg_clock(s
return 0;
}
@@ -170,7 +168,7 @@ index 0e4ebb8..3c3e56d 100644
static bool pwrap_is_cipher_ready(struct pmic_wrapper *wrp)
{
return pwrap_readl(wrp, PWRAP_CIPHER_RDY) & 1;
-@@ -670,6 +790,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
+@@ -670,6 +790,7 @@ static int pwrap_init_cipher(struct pmic
pwrap_writel(wrp, 1, PWRAP_CIPHER_LOAD);
pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
break;
@@ -178,7 +176,7 @@ index 0e4ebb8..3c3e56d 100644
case PWRAP_MT8173:
pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
break;
-@@ -772,6 +893,24 @@ static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp)
+@@ -772,6 +893,24 @@ static int pwrap_mt8173_init_soc_specifi
return 0;
}
@@ -203,7 +201,7 @@ index 0e4ebb8..3c3e56d 100644
static int pwrap_init(struct pmic_wrapper *wrp)
{
int ret;
-@@ -916,6 +1055,18 @@ static const struct of_device_id of_slave_match_tbl[] = {
+@@ -916,6 +1055,18 @@ static const struct of_device_id of_slav
};
MODULE_DEVICE_TABLE(of, of_slave_match_tbl);
@@ -222,7 +220,7 @@ index 0e4ebb8..3c3e56d 100644
static struct pmic_wrapper_type pwrap_mt8135 = {
.regs = mt8135_regs,
.type = PWRAP_MT8135,
-@@ -942,6 +1093,9 @@ static struct pmic_wrapper_type pwrap_mt8173 = {
+@@ -942,6 +1093,9 @@ static struct pmic_wrapper_type pwrap_mt
static struct of_device_id of_pwrap_match_tbl[] = {
{
@@ -232,6 +230,3 @@ index 0e4ebb8..3c3e56d 100644
.compatible = "mediatek,mt8135-pwrap",
.data = &pwrap_mt8135,
}, {
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
index ffb0580c3e..701ee67bad 100644
--- a/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
+++ b/target/linux/mediatek/patches-4.4/0042-dt-bindings-mfd-Add-bindings-for-the-MediaTek-MT6323.patch
@@ -1,8 +1,8 @@
-From edc6e6a2f10f7b7fc94dc6147c86520e5a439d16 Mon Sep 17 00:00:00 2001
+From c14dc2993a272c706650502ec579ceabe5f2355e 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/91] dt-bindings: mfd: Add bindings for the MediaTek MT6323
- PMIC
+Subject: [PATCH 042/102] dt-bindings: mfd: Add bindings for the MediaTek
+ MT6323 PMIC
Signed-off-by: John Crispin <blogic@openwrt.org>
Acked-by: Rob Herring <robh@kernel.org>
@@ -11,8 +11,6 @@ Cc: devicetree@vger.kernel.org
Documentation/devicetree/bindings/mfd/mt6397.txt | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
-diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt
-index 15043e6..949c85f 100644
--- a/Documentation/devicetree/bindings/mfd/mt6397.txt
+++ b/Documentation/devicetree/bindings/mfd/mt6397.txt
@@ -1,6 +1,6 @@
@@ -24,7 +22,7 @@ index 15043e6..949c85f 100644
- Regulator
- RTC
- Audio codec
-@@ -8,14 +8,14 @@ MT6397 is a multifunction device with the following sub modules:
+@@ -8,14 +8,14 @@ MT6397 is a multifunction device with th
- Clock
It is interfaced to host controller using SPI interface by a proprietary hardware
@@ -50,6 +48,3 @@ index 15043e6..949c85f 100644
- codec
Required properties:
- compatible: "mediatek,mt6397-codec"
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
index 16be0ba09a..6b433b0dfa 100644
--- a/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
+++ b/target/linux/mediatek/patches-4.4/0043-mfd-mt6397-int_con-and-int_status-may-vary-in-locati.patch
@@ -1,7 +1,7 @@
-From f97549172878651725a719a4fc4b610613fe5843 Mon Sep 17 00:00:00 2001
+From 8269ed007349714e9ef0e3408a68159d763145dd 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/91] mfd: mt6397: int_con and int_status may vary in
+Subject: [PATCH 043/102] mfd: mt6397: int_con and int_status may vary in
location
MT6323 has the INT_CON and INT_STATUS located at a different position.
@@ -13,11 +13,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
include/linux/mfd/mt6397/core.h | 2 ++
2 files changed, 19 insertions(+), 10 deletions(-)
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index 1749c1c..75ad0fe 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
-@@ -69,8 +69,10 @@ static void mt6397_irq_sync_unlock(struct irq_data *data)
+@@ -69,8 +69,10 @@ static void mt6397_irq_sync_unlock(struc
{
struct mt6397_chip *mt6397 = irq_data_get_irq_chip_data(data);
@@ -30,7 +28,7 @@ index 1749c1c..75ad0fe 100644
mutex_unlock(&mt6397->irqlock);
}
-@@ -147,8 +149,8 @@ static irqreturn_t mt6397_irq_thread(int irq, void *data)
+@@ -147,8 +149,8 @@ static irqreturn_t mt6397_irq_thread(int
{
struct mt6397_chip *mt6397 = data;
@@ -41,7 +39,7 @@ index 1749c1c..75ad0fe 100644
return IRQ_HANDLED;
}
-@@ -177,8 +179,8 @@ static int mt6397_irq_init(struct mt6397_chip *mt6397)
+@@ -177,8 +179,8 @@ static int mt6397_irq_init(struct mt6397
mutex_init(&mt6397->irqlock);
/* Mask all interrupt sources */
@@ -52,7 +50,7 @@ index 1749c1c..75ad0fe 100644
mt6397->irq_domain = irq_domain_add_linear(mt6397->dev->of_node,
MT6397_IRQ_NR, &mt6397_irq_domain_ops, mt6397);
-@@ -203,8 +205,8 @@ static int mt6397_irq_suspend(struct device *dev)
+@@ -203,8 +205,8 @@ static int mt6397_irq_suspend(struct dev
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
@@ -63,7 +61,7 @@ index 1749c1c..75ad0fe 100644
enable_irq_wake(chip->irq);
-@@ -215,8 +217,8 @@ static int mt6397_irq_resume(struct device *dev)
+@@ -215,8 +217,8 @@ static int mt6397_irq_resume(struct devi
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
@@ -74,7 +72,7 @@ index 1749c1c..75ad0fe 100644
disable_irq_wake(chip->irq);
-@@ -237,6 +239,11 @@ static int mt6397_probe(struct platform_device *pdev)
+@@ -237,6 +239,11 @@ static int mt6397_probe(struct platform_
return -ENOMEM;
mt6397->dev = &pdev->dev;
@@ -86,8 +84,6 @@ index 1749c1c..75ad0fe 100644
/*
* mt6397 MFD is child device of soc pmic wrapper.
* Regmap is set from its parent.
-diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h
-index 45b8e8a..d678f52 100644
--- a/include/linux/mfd/mt6397/core.h
+++ b/include/linux/mfd/mt6397/core.h
@@ -60,6 +60,8 @@ struct mt6397_chip {
@@ -99,6 +95,3 @@ index 45b8e8a..d678f52 100644
};
#endif /* __MFD_MT6397_CORE_H__ */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
index cd69ac0065..bae05fb51b 100644
--- a/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
+++ b/target/linux/mediatek/patches-4.4/0044-mfd-mt6397-add-support-for-different-Slave-types.patch
@@ -1,15 +1,13 @@
-From 5fbdf1ebc267561781ce812793cd35e63fa39614 Mon Sep 17 00:00:00 2001
+From c6c447480e51301faa2254c7316ab075e20c4b0c 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/91] mfd: mt6397: add support for different Slave types
+Subject: [PATCH 044/102] mfd: mt6397: add support for different Slave types
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mfd/mt6397-core.c | 58 ++++++++++++++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 17 deletions(-)
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index 75ad0fe..aa91606 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -24,6 +24,9 @@
@@ -22,7 +20,7 @@ index 75ad0fe..aa91606 100644
static const struct resource mt6397_rtc_resources[] = {
{
.start = MT6397_RTC_BASE,
-@@ -232,39 +235,60 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_irq_suspend,
+@@ -232,39 +235,60 @@ static SIMPLE_DEV_PM_OPS(mt6397_pm_ops,
static int mt6397_probe(struct platform_device *pdev)
{
int ret;
@@ -100,6 +98,3 @@ index 75ad0fe..aa91606 100644
return ret;
}
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
index 0f398cddde..d673a0a096 100644
--- a/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0045-mfd-mt6397-add-MT6323-support-to-MT6397-driver.patch
@@ -1,7 +1,7 @@
-From 2a1c7879d8c3eac4313abc011adbefbc50fd5f92 Mon Sep 17 00:00:00 2001
+From 0ae7153c9f00361c3e6dac9da0c2d994557953f5 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/91] mfd: mt6397: add MT6323 support to MT6397 driver
+Subject: [PATCH 045/102] mfd: mt6397: add MT6323 support to MT6397 driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -12,8 +12,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 include/linux/mfd/mt6323/core.h
create mode 100644 include/linux/mfd/mt6323/registers.h
-diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c
-index aa91606..8234cd3 100644
--- a/drivers/mfd/mt6397-core.c
+++ b/drivers/mfd/mt6397-core.c
@@ -19,11 +19,14 @@
@@ -31,7 +29,7 @@ index aa91606..8234cd3 100644
#define MT6391_CID_CODE 0x91
#define MT6397_CID_CODE 0x97
-@@ -40,6 +43,13 @@ static const struct resource mt6397_rtc_resources[] = {
+@@ -40,6 +43,13 @@ static const struct resource mt6397_rtc_
},
};
@@ -45,7 +43,7 @@ index aa91606..8234cd3 100644
static const struct mfd_cell mt6397_devs[] = {
{
.name = "mt6397-rtc",
-@@ -261,6 +271,15 @@ static int mt6397_probe(struct platform_device *pdev)
+@@ -261,6 +271,15 @@ static int mt6397_probe(struct platform_
}
switch (id & 0xff) {
@@ -61,7 +59,7 @@ index aa91606..8234cd3 100644
case MT6397_CID_CODE:
case MT6391_CID_CODE:
pmic->int_con[0] = MT6397_INT_CON0;
-@@ -302,6 +321,7 @@ static int mt6397_remove(struct platform_device *pdev)
+@@ -302,6 +321,7 @@ static int mt6397_remove(struct platform
static const struct of_device_id mt6397_of_match[] = {
{ .compatible = "mediatek,mt6397" },
@@ -69,9 +67,6 @@ index aa91606..8234cd3 100644
{ }
};
MODULE_DEVICE_TABLE(of, mt6397_of_match);
-diff --git a/include/linux/mfd/mt6323/core.h b/include/linux/mfd/mt6323/core.h
-new file mode 100644
-index 0000000..06d0ec3
--- /dev/null
+++ b/include/linux/mfd/mt6323/core.h
@@ -0,0 +1,36 @@
@@ -111,9 +106,6 @@ index 0000000..06d0ec3
+};
+
+#endif /* __MFD_MT6323_CORE_H__ */
-diff --git a/include/linux/mfd/mt6323/registers.h b/include/linux/mfd/mt6323/registers.h
-new file mode 100644
-index 0000000..160f3c0
--- /dev/null
+++ b/include/linux/mfd/mt6323/registers.h
@@ -0,0 +1,408 @@
@@ -525,6 +517,3 @@ index 0000000..160f3c0
+#define MT6323_ACCDET_CON16 0x079A
+
+#endif /* __MFD_MT6323_REGISTERS_H__ */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
index d389e4b47d..d70631483a 100644
--- a/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
+++ b/target/linux/mediatek/patches-4.4/0046-regulator-Add-document-for-MT6323-regulator.patch
@@ -1,7 +1,7 @@
-From 34177561c62ed881c862f9ece652ca1ca5994796 Mon Sep 17 00:00:00 2001
+From f536a600e0e20fd57475415ce5b3d909441d53b6 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/91] regulator: Add document for MT6323 regulator
+Subject: [PATCH 046/102] regulator: Add document for MT6323 regulator
Signed-off-by: John Crispin <blogic@openwrt.org>
Cc: devicetree@vger.kernel.org
@@ -10,9 +10,6 @@ Cc: devicetree@vger.kernel.org
1 file changed, 239 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-diff --git a/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-new file mode 100644
-index 0000000..9fd95e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
@@ -0,0 +1,239 @@
@@ -255,6 +252,3 @@ index 0000000..9fd95e7
+ };
+ };
+ };
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
index 170fcee452..6456c27dce 100644
--- a/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
+++ b/target/linux/mediatek/patches-4.4/0047-regulator-mt6323-Add-support-for-MT6323-regulator.patch
@@ -1,7 +1,7 @@
-From 2a33aa927dece6ac6d10caff48897c8ac6a66c1b Mon Sep 17 00:00:00 2001
+From 94c08223cd696d872cda7d9aa4e817956d0a0b84 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/91] regulator: mt6323: Add support for MT6323 regulator
+Subject: [PATCH 047/102] 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
@@ -18,11 +18,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/regulator/mt6323-regulator.c
create mode 100644 include/linux/regulator/mt6323-regulator.h
-diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
-index 8df0b0e..4aec931 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
-@@ -452,6 +452,15 @@ config REGULATOR_MT6311
+@@ -453,6 +453,15 @@ config REGULATOR_MT6311
This driver supports the control of different power rails of device
through regulator interface.
@@ -38,11 +36,9 @@ index 8df0b0e..4aec931 100644
config REGULATOR_MT6397
tristate "MediaTek MT6397 PMIC"
depends on MFD_MT6397
-diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
-index 0f81749..b42a84e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
-@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
+@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc137
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
@@ -50,9 +46,6 @@ index 0f81749..b42a84e 100644
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
-diff --git a/drivers/regulator/mt6323-regulator.c b/drivers/regulator/mt6323-regulator.c
-new file mode 100644
-index 0000000..28ebbda
--- /dev/null
+++ b/drivers/regulator/mt6323-regulator.c
@@ -0,0 +1,432 @@
@@ -488,9 +481,6 @@ index 0000000..28ebbda
+MODULE_AUTHOR("Chen Zhong <chen.zhong@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL v2");
-diff --git a/include/linux/regulator/mt6323-regulator.h b/include/linux/regulator/mt6323-regulator.h
-new file mode 100644
-index 0000000..67011cd
--- /dev/null
+++ b/include/linux/regulator/mt6323-regulator.h
@@ -0,0 +1,52 @@
@@ -546,6 +536,3 @@ index 0000000..67011cd
+#define MT6323_MAX_REGULATOR MT6323_ID_RG_MAX
+
+#endif /* __LINUX_REGULATOR_MT6323_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
index dd4ee9dac3..7d1e7422ea 100644
--- a/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
+++ b/target/linux/mediatek/patches-4.4/0048-net-next-mediatek-document-MediaTek-SoC-ethernet-bin.patch
@@ -1,7 +1,7 @@
-From caa2186644606dad07a603905ebabb8068828ebf Mon Sep 17 00:00:00 2001
+From 6efc8d9081b70dcf71d7e8efd7b51d48ee2541be 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/91] net-next: mediatek: document MediaTek SoC ethernet
+Subject: [PATCH 048/102] net-next: mediatek: document MediaTek SoC ethernet
binding
This adds the binding documentation for the MediaTek Ethernet
@@ -15,9 +15,6 @@ Cc: devicetree@vger.kernel.org
1 file changed, 77 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/mediatek-net.txt
-diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt
-new file mode 100644
-index 0000000..5ca7929
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mediatek-net.txt
@@ -0,0 +1,77 @@
@@ -98,6 +95,3 @@ index 0000000..5ca7929
+ };
+ };
+};
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
index 5e12344785..85aa93d475 100644
--- a/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
+++ b/target/linux/mediatek/patches-4.4/0049-net-next-mediatek-add-support-for-MT7623-ethernet.patch
@@ -1,7 +1,7 @@
-From 412449bacdb46b548fd08af19148019e2e979294 Mon Sep 17 00:00:00 2001
+From 8cc84aa65121135d7b120ce71b4f10f81230c818 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/91] net-next: mediatek: add support for MT7623 ethernet
+Subject: [PATCH 049/102] 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
@@ -26,9 +26,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.c
create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_soc.h
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-new file mode 100644
-index 0000000..ba3afa5
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -0,0 +1,1807 @@
@@ -1839,9 +1836,6 @@ index 0000000..ba3afa5
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC");
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-new file mode 100644
-index 0000000..48a5292
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -0,0 +1,421 @@
@@ -2266,6 +2260,3 @@ index 0000000..48a5292
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
+#endif /* MTK_ETH_H */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
index 506e3e4076..0c7a89e622 100644
--- a/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
+++ b/target/linux/mediatek/patches-4.4/0050-net-next-mediatek-add-Kconfig-and-Makefile.patch
@@ -1,7 +1,7 @@
-From 8bc8e78ddec2c93d7fe3487dfdfeedd382e3b96f Mon Sep 17 00:00:00 2001
+From 31e907e5c3c2fc1c94d005bfccdd4a32b5a05f82 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/91] net-next: mediatek: add Kconfig and Makefile
+Subject: [PATCH 050/102] net-next: mediatek: add Kconfig and Makefile
This patch adds the Makefile and Kconfig required to make the driver build.
@@ -15,8 +15,6 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
create mode 100644 drivers/net/ethernet/mediatek/Kconfig
create mode 100644 drivers/net/ethernet/mediatek/Makefile
-diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
-index 31c5e47..cd28b95 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -106,6 +106,7 @@ config LANTIQ_ETOP
@@ -27,8 +25,6 @@ index 31c5e47..cd28b95 100644
source "drivers/net/ethernet/mellanox/Kconfig"
source "drivers/net/ethernet/micrel/Kconfig"
source "drivers/net/ethernet/microchip/Kconfig"
-diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
-index 071f84e..c62191f 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_JME) += jme.o
@@ -39,9 +35,6 @@ index 071f84e..c62191f 100644
obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
-diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
-new file mode 100644
-index 0000000..b0229f4
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -0,0 +1,17 @@
@@ -62,9 +55,6 @@ index 0000000..b0229f4
+ MediaTek MT2701/MT7623 chipset family.
+
+endif #NET_VENDOR_MEDIATEK
-diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
-new file mode 100644
-index 0000000..aa3f1c8
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -0,0 +1,5 @@
@@ -73,6 +63,3 @@ index 0000000..aa3f1c8
+#
+
+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
index 4ceb356a08..0fc9b373e5 100644
--- a/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
+++ b/target/linux/mediatek/patches-4.4/0051-net-next-mediatek-add-an-entry-to-MAINTAINERS.patch
@@ -1,7 +1,7 @@
-From d9b93fb0d4021694a2b7e47981cd9de67e83aa05 Mon Sep 17 00:00:00 2001
+From 514e4ce65a5f1b5bfa3cbca153f672844f093f0e 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/91] net-next: mediatek: add an entry to MAINTAINERS
+Subject: [PATCH 051/102] net-next: mediatek: add an entry to MAINTAINERS
Add myself and Felix as the Maintainers for the MediaTek ethernet driver.
@@ -11,11 +11,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
-diff --git a/MAINTAINERS b/MAINTAINERS
-index 156e1d3..7737042 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -6908,6 +6908,13 @@ F: include/uapi/linux/meye.h
+@@ -6907,6 +6907,13 @@ F: include/uapi/linux/meye.h
F: include/uapi/linux/ivtv*
F: include/uapi/linux/uvcvideo.h
@@ -29,6 +27,3 @@ index 156e1d3..7737042 100644
MEDIATEK MT7601U WIRELESS LAN DRIVER
M: Jakub Kicinski <kubakici@wp.pl>
L: linux-wireless@vger.kernel.org
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch b/target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch
index ef425225f2..87e4a54ed3 100644
--- a/target/linux/mediatek/patches-4.4/0060-clk-dont-disable-unused-clocks.patch
+++ b/target/linux/mediatek/patches-4.4/0052-clk-dont-disable-unused-clocks.patch
@@ -1,15 +1,13 @@
-From cbcbd319d905cdcf4a71003b5634137fee03855b Mon Sep 17 00:00:00 2001
+From 5238c5d1d38661955ed3b52f45c46e00bfc9eb6e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Apr 2016 07:18:35 +0200
-Subject: [PATCH 60/91] clk: dont disable unused clocks
+Subject: [PATCH 052/102] clk: dont disable unused clocks
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/clk/clk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
-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:
@@ -21,6 +19,3 @@ index f13c3f4..5e9ddae 100644
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/0052-mtd-nand-add-an-mtd_to_nand-helper.patch b/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch
deleted file mode 100644
index 83e725a5cc..0000000000
--- a/target/linux/mediatek/patches-4.4/0052-mtd-nand-add-an-mtd_to_nand-helper.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 69a0df9dd942799651a7ec06b3cfe7fc43b2e32a 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 52/91] 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/0061-clk-mediatek-enable-critical-clocks.patch b/target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch
index b075a7465e..39939001f1 100644
--- a/target/linux/mediatek/patches-4.4/0061-clk-mediatek-enable-critical-clocks.patch
+++ b/target/linux/mediatek/patches-4.4/0053-clk-mediatek-enable-critical-clocks.patch
@@ -1,18 +1,16 @@
-From 6610fdbea393a4a8ed956b2aaf7012bea3a5069e Mon Sep 17 00:00:00 2001
+From c8fd103d6c07af5db47f061b70759b7c69169656 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 31 Mar 2016 06:46:51 +0200
-Subject: [PATCH 61/91] clk: mediatek: enable critical clocks
+Subject: [PATCH 053/102] clk: mediatek: enable critical clocks
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/clk/mediatek/clk-mt2701.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 812b347..1634288 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
-@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[] __initconst = {
+@@ -573,6 +573,20 @@ static const struct mtk_gate top_clks[]
GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", 28),
};
@@ -33,7 +31,7 @@ index 812b347..1634288 100644
static void __init mtk_topckgen_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
-@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(struct device_node *node)
+@@ -585,7 +599,7 @@ static void __init mtk_topckgen_init(str
return;
}
@@ -42,7 +40,7 @@ index 812b347..1634288 100644
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
clk_data);
-@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(struct device_node *node)
+@@ -606,6 +620,8 @@ static void __init mtk_topckgen_init(str
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -51,7 +49,7 @@ index 812b347..1634288 100644
}
CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt2701-topckgen", mtk_topckgen_init);
-@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
+@@ -1202,7 +1218,7 @@ static void __init mtk_apmixedsys_init(s
struct clk_onecell_data *clk_data;
int r;
@@ -60,7 +58,7 @@ index 812b347..1634288 100644
if (!clk_data)
return;
-@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(struct device_node *node)
+@@ -1213,6 +1229,8 @@ static void __init mtk_apmixedsys_init(s
if (r)
pr_err("%s(): could not register clock provider: %d\n",
__func__, r);
@@ -69,6 +67,3 @@ index 812b347..1634288 100644
}
CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt2701-apmixedsys",
mtk_apmixedsys_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch b/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch
deleted file mode 100644
index b103c5b539..0000000000
--- a/target/linux/mediatek/patches-4.4/0053-mtd-nand-add-nand_to_mtd-helper.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 833645b92150d74642829c24c0ca1fbbdeccfb5c 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 53/91] 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/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch b/target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
index d30f2dd48c..d5af5f0c82 100644
--- a/target/linux/mediatek/patches-4.4/0062-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
+++ b/target/linux/mediatek/patches-4.4/0054-clk-mediatek-Export-CPU-mux-clocks-for-CPU-frequency.patch
@@ -1,8 +1,8 @@
-From 2ed6efcef399d15910ff60eef72b4cf8e5265c47 Mon Sep 17 00:00:00 2001
+From 1387d4f0ebf4b48c09f2ea0d27a02936c3fa0010 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 31 Mar 2016 02:26:37 +0200
-Subject: [PATCH 62/91] clk: mediatek: Export CPU mux clocks for CPU frequency
- control
+Subject: [PATCH 054/102] clk: mediatek: Export CPU mux clocks for CPU
+ frequency control
This patch adds CPU mux clocks which are used by Mediatek cpufreq driver
for intermediate clock source switching.
@@ -20,8 +20,6 @@ Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
create mode 100644 drivers/clk/mediatek/clk-cpumux.c
create mode 100644 drivers/clk/mediatek/clk-cpumux.h
-diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
-index 5b2b91b..76bfab6 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -1,4 +1,4 @@
@@ -30,9 +28,6 @@ index 5b2b91b..76bfab6 100644
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
-diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c
-new file mode 100644
-index 0000000..91b5238
--- /dev/null
+++ b/drivers/clk/mediatek/clk-cpumux.c
@@ -0,0 +1,127 @@
@@ -163,9 +158,6 @@ index 0000000..91b5238
+
+ return 0;
+}
-diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h
-new file mode 100644
-index 0000000..52c769f
--- /dev/null
+++ b/drivers/clk/mediatek/clk-cpumux.h
@@ -0,0 +1,22 @@
@@ -191,8 +183,6 @@ index 0000000..52c769f
+ struct clk_onecell_data *clk_data);
+
+#endif /* __DRV_CLK_CPUMUX_H */
-diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c
-index 1634288..5c37fcb 100644
--- a/drivers/clk/mediatek/clk-mt2701.c
+++ b/drivers/clk/mediatek/clk-mt2701.c
@@ -18,6 +18,7 @@
@@ -203,7 +193,7 @@ index 1634288..5c37fcb 100644
#include <dt-bindings/clock/mt2701-clk.h>
-@@ -465,6 +466,10 @@ static const char * const cpu_parents[] __initconst = {
+@@ -465,6 +466,10 @@ static const char * const cpu_parents[]
"mmpll"
};
@@ -214,7 +204,7 @@ index 1634288..5c37fcb 100644
static const struct mtk_composite top_muxes[] __initconst = {
MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents,
0x0040, 0, 3, INVALID_MUX_GATE_BIT),
-@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(struct device_node *node)
+@@ -677,6 +682,9 @@ static void __init mtk_infrasys_init(str
mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs),
clk_data);
@@ -224,8 +214,6 @@ index 1634288..5c37fcb 100644
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
pr_err("%s(): could not register clock provider: %d\n",
-diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c
-index 227e356..b82c0e2 100644
--- a/drivers/clk/mediatek/clk-mt8173.c
+++ b/drivers/clk/mediatek/clk-mt8173.c
@@ -18,6 +18,7 @@
@@ -236,7 +224,7 @@ index 227e356..b82c0e2 100644
#include <dt-bindings/clock/mt8173-clk.h>
-@@ -526,6 +527,25 @@ static const char * const i2s3_b_ck_parents[] __initconst = {
+@@ -526,6 +527,25 @@ static const char * const i2s3_b_ck_pare
"apll2_div5"
};
@@ -262,7 +250,7 @@ index 227e356..b82c0e2 100644
static const struct mtk_composite top_muxes[] __initconst = {
/* CLK_CFG_0 */
MUX(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x0040, 0, 3),
-@@ -945,6 +965,9 @@ static void __init mtk_infrasys_init(struct device_node *node)
+@@ -945,6 +965,9 @@ static void __init mtk_infrasys_init(str
clk_data);
mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs), clk_data);
@@ -272,8 +260,6 @@ index 227e356..b82c0e2 100644
r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
if (r)
pr_err("%s(): could not register clock provider: %d\n",
-diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
-index 50972d1..a6c63b8 100644
--- a/include/dt-bindings/clock/mt2701-clk.h
+++ b/include/dt-bindings/clock/mt2701-clk.h
@@ -217,7 +217,8 @@
@@ -286,8 +272,6 @@ index 50972d1..a6c63b8 100644
/* PERICFG */
-diff --git a/include/dt-bindings/clock/mt8173-clk.h b/include/dt-bindings/clock/mt8173-clk.h
-index 7956ba1..c82ed7c 100644
--- a/include/dt-bindings/clock/mt8173-clk.h
+++ b/include/dt-bindings/clock/mt8173-clk.h
@@ -192,7 +192,9 @@
@@ -301,6 +285,3 @@ index 7956ba1..c82ed7c 100644
/* PERI_SYS */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch b/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch
deleted file mode 100644
index 8e32d5f919..0000000000
--- a/target/linux/mediatek/patches-4.4/0054-mtd-nand-add-helpers-to-access-priv.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From af8437ee10a6304da30ca479480102b464b39c82 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 54/91] 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/0063-cpufreq-mediatek-add-driver.patch b/target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch
index cf80540913..8b476361ff 100644
--- a/target/linux/mediatek/patches-4.4/0063-cpufreq-mediatek-add-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0055-cpufreq-mediatek-add-driver.patch
@@ -1,7 +1,7 @@
-From 668d2c777a41440daa55435c2a217e61c23e4a30 Mon Sep 17 00:00:00 2001
+From 60f4e41b367bdb29530468c91c1e613b17a37755 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2016 23:48:53 +0200
-Subject: [PATCH 63/91] cpufreq: mediatek: add driver
+Subject: [PATCH 055/102] cpufreq: mediatek: add driver
Signed-off-by: John Crispin <john@phrozen.org>
---
@@ -11,8 +11,6 @@ Signed-off-by: John Crispin <john@phrozen.org>
3 files changed, 399 insertions(+)
create mode 100644 drivers/cpufreq/mt7623-cpufreq.c
-diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
-index b1f8a73..baf945e 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -81,6 +81,15 @@ config ARM_KIRKWOOD_CPUFREQ
@@ -31,11 +29,9 @@ index b1f8a73..baf945e 100644
config ARM_MT8173_CPUFREQ
bool "Mediatek MT8173 CPUFreq support"
depends on ARCH_MEDIATEK && REGULATOR
-diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
-index c0af1a1..e198752 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
-@@ -57,6 +57,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o
+@@ -57,6 +57,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += h
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
@@ -43,9 +39,6 @@ index c0af1a1..e198752 100644
obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
-diff --git a/drivers/cpufreq/mt7623-cpufreq.c b/drivers/cpufreq/mt7623-cpufreq.c
-new file mode 100644
-index 0000000..8d154ce
--- /dev/null
+++ b/drivers/cpufreq/mt7623-cpufreq.c
@@ -0,0 +1,389 @@
@@ -438,6 +431,3 @@ index 0000000..8d154ce
+ return 0;
+}
+device_initcall(mt7623_cpufreq_driver_init);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch b/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch
deleted file mode 100644
index 0decc646f0..0000000000
--- a/target/linux/mediatek/patches-4.4/0055-mtd-nand-embed-an-mtd_info-structure-into-nand_chip.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From f18fcf4468ffdce17747f3d331f998a7e9264142 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 55/91] 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/0064-arm-mediatek-make-a7-timer-work.patch b/target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch
index bd3bf31c2c..fe81b47290 100644
--- a/target/linux/mediatek/patches-4.4/0064-arm-mediatek-make-a7-timer-work.patch
+++ b/target/linux/mediatek/patches-4.4/0056-arm-mediatek-make-a7-timer-work-Signed-off-by-John-C.patch
@@ -1,16 +1,14 @@
-From 6eeadfb48dc5e73dae115fc0be9416e3d5fed84d Mon Sep 17 00:00:00 2001
+From f8cda0bc698706413b5dd6fde827f9a2601ac61b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 31 Mar 2016 06:07:01 +0200
-Subject: [PATCH 64/91] arm: mediatek: make a7 timer work Signed-off-by: John
- Crispin <blogic@openwrt.org>
+Subject: [PATCH 056/102] arm: mediatek: make a7 timer work Signed-off-by:
+ John Crispin <blogic@openwrt.org>
---
arch/arm/mach-mediatek/Kconfig | 1 +
arch/arm/mach-mediatek/mediatek.c | 1 +
2 files changed, 2 insertions(+)
-diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
-index a7fef77..2c05bc31 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -24,6 +24,7 @@ config MACH_MT6592
@@ -21,11 +19,9 @@ index a7fef77..2c05bc31 100644
select MIGHT_HAVE_PCI
config MACH_MT8127
-diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
-index bcfca37..7553a8c 100644
--- a/arch/arm/mach-mediatek/mediatek.c
+++ b/arch/arm/mach-mediatek/mediatek.c
-@@ -29,6 +29,7 @@ static void __init mediatek_timer_init(void)
+@@ -29,6 +29,7 @@ static void __init mediatek_timer_init(v
void __iomem *gpt_base;
if (of_machine_is_compatible("mediatek,mt6589") ||
@@ -33,6 +29,3 @@ index bcfca37..7553a8c 100644
of_machine_is_compatible("mediatek,mt8135") ||
of_machine_is_compatible("mediatek,mt8127")) {
/* turn on GPT6 which ungates arch timer clocks */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch b/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch
deleted file mode 100644
index 02066f88b9..0000000000
--- a/target/linux/mediatek/patches-4.4/0056-mtd-add-get-set-of_node-flash_node-helpers.patch
+++ /dev/null
@@ -1,87 +0,0 @@
-From 59d8570d4b61af8544fc295d5e83ab7c28294bb8 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 22 Mar 2016 03:52:07 +0100
-Subject: [PATCH 56/91] 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/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
deleted file mode 100644
index edeeb96850..0000000000
--- a/target/linux/mediatek/patches-4.4/0057-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0fe612b501f1d56d76b2858d2ae779c1e766d064 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 57/91] 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-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch b/target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
index 124818ae4d..f00e9682bc 100644
--- a/target/linux/mediatek/patches-4.4/0065-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
+++ b/target/linux/mediatek/patches-4.4/0057-net-mediatek-checking-for-IS_ERR-instead-of-NULL.patch
@@ -1,7 +1,7 @@
-From 0b88e5873b97ab20566b51134123fda7050d4d08 Mon Sep 17 00:00:00 2001
+From b9f9b937dd12dc57bd54a6c89b18eb40d4508424 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 65/91] net: mediatek: checking for IS_ERR() instead of NULL
+Subject: [PATCH 057/102] net: mediatek: checking for IS_ERR() instead of NULL
of_phy_connect() returns NULL on error, it never returns error pointers.
@@ -11,11 +11,9 @@ 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,
+@@ -186,9 +186,9 @@ static int mtk_phy_connect_node(struct m
phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
mtk_phy_link_adjust, 0, phy_mode);
@@ -27,6 +25,3 @@ index ba3afa5..9759fe5 100644
}
dev_info(eth->dev,
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
deleted file mode 100644
index c868fa49b9..0000000000
--- a/target/linux/mediatek/patches-4.4/0058-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
+++ /dev/null
@@ -1,1798 +0,0 @@
-From 24db36ad20239841b897efb41442841ebf5d2f78 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 58/91] 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-mediatek-unlock-on-error-in-mtk_tx_map.patch b/target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
index 75f09d54ed..a3f861b72c 100644
--- a/target/linux/mediatek/patches-4.4/0066-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
+++ b/target/linux/mediatek/patches-4.4/0058-net-mediatek-unlock-on-error-in-mtk_tx_map.patch
@@ -1,7 +1,7 @@
-From 489994e9cb0d9f762c31e2af9205188ae8f3b013 Mon Sep 17 00:00:00 2001
+From 6c12340c0c307d18b8d6120f64a8275b6d4d3e67 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 66/91] net: mediatek: unlock on error in mtk_tx_map()
+Subject: [PATCH 058/102] net: mediatek: unlock on error in mtk_tx_map()
There was a missing unlock on the error path.
@@ -11,8 +11,6 @@ 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:
@@ -24,6 +22,3 @@ index 9759fe5..c2c2e206 100644
return -ENOMEM;
}
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch b/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch
deleted file mode 100644
index 074346a6ff..0000000000
--- a/target/linux/mediatek/patches-4.4/0059-mtd-nand-backport-fixes.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 96bddff914c0cee1b16d809220e84b470b433122 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 31 Mar 2016 02:28:08 +0200
-Subject: [PATCH 59/91] mtd: nand: backport fixes
-
----
- drivers/mtd/nand/mtksdg1_nand.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/mtksdg1_nand.c b/drivers/mtd/nand/mtksdg1_nand.c
-index 55dd17d..f92b949 100644
---- a/drivers/mtd/nand/mtksdg1_nand.c
-+++ b/drivers/mtd/nand/mtksdg1_nand.c
-@@ -107,6 +107,9 @@ static struct nand_ecclayout nand_4k_128 = {
- .oobfree = { {0, 32} },
- };
-
-+static const char * const part_probes[] = {
-+ "cmdlinepart", "RedBoot", "ofpart", NULL };
-+
- /* NFI register access */
- static inline void mtk_nfi_writel(struct mtk_nfc_host *host, u32 val, u32 reg)
- {
-@@ -1298,6 +1301,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
-
- chip = &host->chip;
- mtd = nand_to_mtd(chip);
-+ mtd->priv = chip;
- host->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-@@ -1428,7 +1432,10 @@ static int mtk_nfc_probe(struct platform_device *pdev)
- }
- host->switch_oob = false;
-
-- ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
-+ ret = mtd_device_parse_register(mtd, part_probes,
-+ &(struct mtd_part_parser_data) {
-+ .of_node = pdev->dev.of_node,
-+ }, NULL, 0);
- if (ret) {
- dev_err(dev, "mtd parse partition error\n");
- goto nand_free;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch b/target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch
index e86bc22544..0dd5f2d29d 100644
--- a/target/linux/mediatek/patches-4.4/0067-net-mediatek-use-dma_addr_t-correctly.patch
+++ b/target/linux/mediatek/patches-4.4/0059-net-mediatek-use-dma_addr_t-correctly.patch
@@ -1,7 +1,7 @@
-From ac345476b98f3856bbf3938e114d4be799f8bd69 Mon Sep 17 00:00:00 2001
+From a572747434b6153e75812c5466c0557e5ed69284 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Mon, 14 Mar 2016 15:07:10 +0100
-Subject: [PATCH 67/91] net: mediatek: use dma_addr_t correctly
+Subject: [PATCH 059/102] 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
@@ -17,11 +17,9 @@ 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,
+@@ -453,7 +453,7 @@ static inline void mtk_rx_get_desc(struc
/* the qdma core needs scratch memory to be setup */
static int mtk_init_fq_dma(struct mtk_eth *eth)
{
@@ -30,6 +28,3 @@ index c2c2e206..a005bc4 100644
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/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch b/target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch
index 262e5c17ba..d1df7327b1 100644
--- a/target/linux/mediatek/patches-4.4/0068-net-mediatek-remove-incorrect-dma_mask-assignment.patch
+++ b/target/linux/mediatek/patches-4.4/0060-net-mediatek-remove-incorrect-dma_mask-assignment.patch
@@ -1,7 +1,7 @@
-From 8b6bb80616460eda2e70e358c5fb70c0f4d4d02f Mon Sep 17 00:00:00 2001
+From 8473af12d5aa34613070447d6fd8f785f31301de Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Mon, 14 Mar 2016 15:07:11 +0100
-Subject: [PATCH 68/91] net: mediatek: remove incorrect dma_mask assignment
+Subject: [PATCH 060/102] 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.
@@ -17,11 +17,9 @@ 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)
+@@ -1678,9 +1678,6 @@ static int mtk_probe(struct platform_dev
struct mtk_eth *eth;
int err;
@@ -31,6 +29,3 @@ index a005bc4..fcd4ed7 100644
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/0069-net-mediatek-check-device_reset-return-code.patch b/target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch
index 30ead3800c..ebc6d9b361 100644
--- a/target/linux/mediatek/patches-4.4/0069-net-mediatek-check-device_reset-return-code.patch
+++ b/target/linux/mediatek/patches-4.4/0061-net-mediatek-check-device_reset-return-code.patch
@@ -1,7 +1,7 @@
-From cd7ea7dae994beea798115f4c34c96f45cc028d1 Mon Sep 17 00:00:00 2001
+From 99159791184752ece724b741f9fa6334fdc67123 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Mon, 14 Mar 2016 15:07:12 +0100
-Subject: [PATCH 69/91] net: mediatek: check device_reset return code
+Subject: [PATCH 061/102] 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.
@@ -18,11 +18,9 @@ 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)
+@@ -1678,7 +1678,9 @@ static int mtk_probe(struct platform_dev
struct mtk_eth *eth;
int err;
@@ -33,6 +31,3 @@ index fcd4ed7..7f2126b 100644
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/0070-net-mediatek-watchdog_timeo-was-not-set.patch b/target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch
index a4c5e9ffd6..ca2e791a37 100644
--- a/target/linux/mediatek/patches-4.4/0070-net-mediatek-watchdog_timeo-was-not-set.patch
+++ b/target/linux/mediatek/patches-4.4/0062-net-mediatek-watchdog_timeo-was-not-set.patch
@@ -1,7 +1,7 @@
-From 5fac03871435c52f7f9b7f34aefb2774089d32f9 Mon Sep 17 00:00:00 2001
+From 387257cbd6f3f92de71e2f578d3a9414d0dada27 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 30 Mar 2016 03:18:17 +0200
-Subject: [PATCH 70/91] net: mediatek: watchdog_timeo was not set
+Subject: [PATCH 062/102] net: mediatek: watchdog_timeo was not set
The original commit failed to set watchdog_timeo. This patch sets
watchdog_timeo to HZ.
@@ -11,11 +11,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
1 file changed, 1 insertion(+)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 7f2126b..7e6d2e2 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1645,6 +1645,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1645,6 +1645,7 @@ static int mtk_add_mac(struct mtk_eth *e
mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
SET_NETDEV_DEV(eth->netdev[id], eth->dev);
@@ -23,6 +21,3 @@ index 7f2126b..7e6d2e2 100644
eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
eth->netdev[id]->base_addr = (unsigned long)eth->base;
eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch b/target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
index c18fa0c996..a81f165980 100644
--- a/target/linux/mediatek/patches-4.4/0071-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
+++ b/target/linux/mediatek/patches-4.4/0063-net-mediatek-mtk_cal_txd_req-returns-bad-value.patch
@@ -1,7 +1,7 @@
-From ca0d5851de3763fe309d3083693f1a438c6e98c9 Mon Sep 17 00:00:00 2001
+From d8f3e96943334c91ecc0827ed0d3232068c389e6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 22 Mar 2016 04:42:27 +0100
-Subject: [PATCH 71/91] net: mediatek: mtk_cal_txd_req() returns bad value
+Subject: [PATCH 063/102] net: mediatek: mtk_cal_txd_req() returns bad value
The code used to also support the PDMA engine, which had 2 packet pointers
per descriptor. Because of this we have to divide the result by 2 and round
@@ -12,11 +12,9 @@ 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 7e6d2e2..4d8d0a3 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -681,7 +681,7 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
+@@ -681,7 +681,7 @@ static inline int mtk_cal_txd_req(struct
nfrags += skb_shinfo(skb)->nr_frags;
}
@@ -25,6 +23,3 @@ index 7e6d2e2..4d8d0a3 100644
}
static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch b/target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch
index c2b5fdafa6..434a6e38ed 100644
--- a/target/linux/mediatek/patches-4.4/0072-net-mediatek-remove-superflous-reset-call.patch
+++ b/target/linux/mediatek/patches-4.4/0064-net-mediatek-remove-superflous-reset-call.patch
@@ -1,7 +1,7 @@
-From 51dc0a2114c3d6e51bf2acde415fccdec031e480 Mon Sep 17 00:00:00 2001
+From 2597d2cedba62b2a3fdca9c044187705f98a0372 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 25 Mar 2016 04:24:27 +0100
-Subject: [PATCH 72/91] net: mediatek: remove superflous reset call
+Subject: [PATCH 064/102] net: mediatek: remove superflous reset call
HW reset is triggered int he mtk_hw_init() function. There is no need to
reset the core during probe.
@@ -11,11 +11,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ----
1 file changed, 4 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 4d8d0a3..293ea59 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1679,10 +1679,6 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1679,10 +1679,6 @@ static int mtk_probe(struct platform_dev
struct mtk_eth *eth;
int err;
@@ -26,6 +24,3 @@ index 4d8d0a3..293ea59 100644
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/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch b/target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch
index b14b67acf0..1660e4204d 100644
--- a/target/linux/mediatek/patches-4.4/0073-net-mediatek-fix-stop-and-wakeup-of-queue.patch
+++ b/target/linux/mediatek/patches-4.4/0065-net-mediatek-fix-stop-and-wakeup-of-queue.patch
@@ -1,7 +1,7 @@
-From 868eb5a3d0217e1ecdc2f628c6dc4fcd18562a71 Mon Sep 17 00:00:00 2001
+From afc838dde560ab584d3fb0e4b011e4a6770dab3d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 29 Mar 2016 16:41:07 +0200
-Subject: [PATCH 73/91] net: mediatek: fix stop and wakeup of queue
+Subject: [PATCH 065/102] net: mediatek: fix stop and wakeup of queue
The driver supports 2 MACs. Both run on the same DMA ring. If we go
above/below the TX rings thershold value, we always need to wake/stop
@@ -13,11 +13,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++--------
1 file changed, 27 insertions(+), 10 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 293ea59..04bdb9d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -684,6 +684,28 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
+@@ -684,6 +684,28 @@ static inline int mtk_cal_txd_req(struct
return nfrags;
}
@@ -46,7 +44,7 @@ index 293ea59..04bdb9d 100644
static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mtk_mac *mac = netdev_priv(dev);
-@@ -695,7 +717,7 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -695,7 +717,7 @@ static int mtk_start_xmit(struct sk_buff
tx_num = mtk_cal_txd_req(skb);
if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
@@ -55,7 +53,7 @@ index 293ea59..04bdb9d 100644
netif_err(eth, tx_queued, dev,
"Tx Ring full when queue awake!\n");
return NETDEV_TX_BUSY;
-@@ -720,10 +742,10 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -720,10 +742,10 @@ static int mtk_start_xmit(struct sk_buff
goto drop;
if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
@@ -68,7 +66,7 @@ index 293ea59..04bdb9d 100644
}
return NETDEV_TX_OK;
-@@ -897,13 +919,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+@@ -897,13 +919,8 @@ static int mtk_poll_tx(struct mtk_eth *e
if (!total)
return 0;
@@ -84,6 +82,3 @@ index 293ea59..04bdb9d 100644
return total;
}
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch b/target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch
index 1a2ce6f873..b233578106 100644
--- a/target/linux/mediatek/patches-4.4/0074-net-mediatek-fix-mtk_pending_work.patch
+++ b/target/linux/mediatek/patches-4.4/0066-net-mediatek-fix-mtk_pending_work.patch
@@ -1,7 +1,7 @@
-From 300ca8c6b5dcee2593f22d5bf8f13bb4da8c19c5 Mon Sep 17 00:00:00 2001
+From e2cc73e6ddb0cc39b8f58654a449651a621916a9 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 29 Mar 2016 17:00:47 +0200
-Subject: [PATCH 74/91] net: mediatek: fix mtk_pending_work
+Subject: [PATCH 066/102] net: mediatek: fix mtk_pending_work
The driver supports 2 MACs. Both run on the same DMA ring. If we hit a TX
timeout we need to stop both netdevs before retarting them again. If we
@@ -13,11 +13,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++--------
1 file changed, 21 insertions(+), 9 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 04bdb9d..26eeb1a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1430,19 +1430,31 @@ static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+@@ -1430,19 +1430,31 @@ static int mtk_do_ioctl(struct net_devic
static void mtk_pending_work(struct work_struct *work)
{
@@ -58,6 +56,3 @@ index 04bdb9d..26eeb1a 100644
}
rtnl_unlock();
}
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch b/target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch
index 0c68499827..d750de6af1 100644
--- a/target/linux/mediatek/patches-4.4/0075-net-mediatek-fix-TX-locking.patch
+++ b/target/linux/mediatek/patches-4.4/0067-net-mediatek-fix-TX-locking.patch
@@ -1,7 +1,7 @@
-From 506c56fe0c3986c13fbca474ee91b061fbc850ca Mon Sep 17 00:00:00 2001
+From 6f152b2bdb295d86beb746494ef6fddf17986f8e Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 29 Mar 2016 17:20:01 +0200
-Subject: [PATCH 75/91] net: mediatek: fix TX locking
+Subject: [PATCH 067/102] net: mediatek: fix TX locking
Inside the TX path there is a lock inside the tx_map function. This is
however too late. The patch moves the lock to the start of the xmit
@@ -15,11 +15,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 26eeb1a..67b18f9 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -536,7 +536,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+@@ -536,7 +536,6 @@ static int mtk_tx_map(struct sk_buff *sk
struct mtk_eth *eth = mac->hw;
struct mtk_tx_dma *itxd, *txd;
struct mtk_tx_buf *tx_buf;
@@ -27,7 +25,7 @@ index 26eeb1a..67b18f9 100644
dma_addr_t mapped_addr;
unsigned int nr_frags;
int i, n_desc = 1;
-@@ -568,11 +567,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+@@ -568,11 +567,6 @@ static int mtk_tx_map(struct sk_buff *sk
if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
return -ENOMEM;
@@ -39,7 +37,7 @@ index 26eeb1a..67b18f9 100644
WRITE_ONCE(itxd->txd1, mapped_addr);
tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
-@@ -632,8 +626,6 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+@@ -632,8 +626,6 @@ static int mtk_tx_map(struct sk_buff *sk
WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
(!nr_frags * TX_DMA_LS0)));
@@ -57,7 +55,7 @@ index 26eeb1a..67b18f9 100644
return -ENOMEM;
}
-@@ -712,14 +702,22 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -712,14 +702,22 @@ static int mtk_start_xmit(struct sk_buff
struct mtk_eth *eth = mac->hw;
struct mtk_tx_ring *ring = &eth->tx_ring;
struct net_device_stats *stats = &dev->stats;
@@ -80,7 +78,7 @@ index 26eeb1a..67b18f9 100644
return NETDEV_TX_BUSY;
}
-@@ -747,10 +745,12 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+@@ -747,10 +745,12 @@ static int mtk_start_xmit(struct sk_buff
ring->thresh))
mtk_wake_queue(eth);
}
@@ -93,6 +91,3 @@ index 26eeb1a..67b18f9 100644
stats->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch b/target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
index 4dd0d45b0e..497309144c 100644
--- a/target/linux/mediatek/patches-4.4/0076-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
+++ b/target/linux/mediatek/patches-4.4/0068-net-mediatek-move-the-pending_work-struct-to-the-dev.patch
@@ -1,7 +1,7 @@
-From d42de6ec9325c29d0f59c5df74a5cbceb00ddd9d Mon Sep 17 00:00:00 2001
+From 29bc7a1e374425937b5dd2f316dbeef343d4c68a Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 29 Mar 2016 17:24:24 +0200
-Subject: [PATCH 76/91] net: mediatek: move the pending_work struct to the
+Subject: [PATCH 068/102] net: mediatek: move the pending_work struct to the
device generic struct
The worker always touches both netdevs. It is ethernet core and not MAC
@@ -13,11 +13,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++--
2 files changed, 6 insertions(+), 8 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 67b18f9..bbcd607 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1193,7 +1193,7 @@ static void mtk_tx_timeout(struct net_device *dev)
+@@ -1193,7 +1193,7 @@ static void mtk_tx_timeout(struct net_de
eth->netdev[mac->id]->stats.tx_errors++;
netif_err(eth, tx_err, dev,
"transmit timed out\n");
@@ -26,7 +24,7 @@ index 67b18f9..bbcd607 100644
}
static irqreturn_t mtk_handle_irq(int irq, void *_eth)
-@@ -1438,7 +1438,7 @@ static void mtk_pending_work(struct work_struct *work)
+@@ -1438,7 +1438,7 @@ static void mtk_pending_work(struct work
/* stop all devices to make sure that dma is properly shut down */
for (i = 0; i < MTK_MAC_COUNT; i++) {
@@ -35,7 +33,7 @@ index 67b18f9..bbcd607 100644
continue;
mtk_stop(eth->netdev[i]);
__set_bit(i, &restart);
-@@ -1464,15 +1464,13 @@ static int mtk_cleanup(struct mtk_eth *eth)
+@@ -1464,15 +1464,13 @@ static int mtk_cleanup(struct mtk_eth *e
int i;
for (i = 0; i < MTK_MAC_COUNT; i++) {
@@ -52,7 +50,7 @@ index 67b18f9..bbcd607 100644
return 0;
}
-@@ -1660,7 +1658,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1660,7 +1658,6 @@ static int mtk_add_mac(struct mtk_eth *e
mac->id = id;
mac->hw = eth;
mac->of_node = np;
@@ -60,7 +58,7 @@ index 67b18f9..bbcd607 100644
mac->hw_stats = devm_kzalloc(eth->dev,
sizeof(*mac->hw_stats),
-@@ -1762,6 +1759,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1762,6 +1759,7 @@ static int mtk_probe(struct platform_dev
eth->dev = &pdev->dev;
eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
@@ -68,8 +66,6 @@ index 67b18f9..bbcd607 100644
err = mtk_hw_init(eth);
if (err)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 48a5292..eed626d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -363,6 +363,7 @@ struct mtk_rx_ring {
@@ -104,6 +100,3 @@ index 48a5292..eed626d 100644
};
/* the struct describing the SoC. these are declared in the soc_xyz.c files */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch b/target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
index 1038faf5c1..72f96e2174 100644
--- a/target/linux/mediatek/patches-4.4/0077-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
+++ b/target/linux/mediatek/patches-4.4/0069-net-mediatek-do-not-set-the-QID-field-in-the-TX-DMA-.patch
@@ -1,8 +1,8 @@
-From 2675e2a40d78c55fc2d578ec71cc990170cacc42 Mon Sep 17 00:00:00 2001
+From 4742349c1595d38b3e3b463e66cf21af4217c869 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Apr 2016 17:36:23 +0200
-Subject: [PATCH 77/91] net: mediatek: do not set the QID field in the TX DMA
- descriptors
+Subject: [PATCH 069/102] net: mediatek: do not set the QID field in the TX
+ DMA descriptors
The QID field gets set to the mac id. This made the DMA linked list queue
the traffic of each MAC on a different internal queue. However during long
@@ -18,11 +18,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bbcd607..bab5d45 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -603,8 +603,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+@@ -603,8 +603,7 @@ static int mtk_tx_map(struct sk_buff *sk
WRITE_ONCE(txd->txd1, mapped_addr);
WRITE_ONCE(txd->txd3, (TX_DMA_SWC |
TX_DMA_PLEN0(frag_map_size) |
@@ -32,6 +30,3 @@ index bbcd607..bab5d45 100644
WRITE_ONCE(txd->txd4, 0);
tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch b/target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
index 8104ef2872..efc59c06f2 100644
--- a/target/linux/mediatek/patches-4.4/0078-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
+++ b/target/linux/mediatek/patches-4.4/0070-net-mediatek-update-the-IRQ-part-of-the-binding-docu.patch
@@ -1,7 +1,7 @@
-From 289e6b23aa394126f50048f673ac266686bbf65e Mon Sep 17 00:00:00 2001
+From 297ef52cd21e28da671996d7b4f39f268d2d0ec1 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 29 Mar 2016 14:32:07 +0200
-Subject: [PATCH 78/91] net: mediatek: update the IRQ part of the binding
+Subject: [PATCH 070/102] net: mediatek: update the IRQ part of the binding
document
The current binding document only describes a single interrupt. Update the
@@ -16,11 +16,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
Documentation/devicetree/bindings/net/mediatek-net.txt | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
-diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt
-index 5ca7929..32eaaca 100644
--- a/Documentation/devicetree/bindings/net/mediatek-net.txt
+++ b/Documentation/devicetree/bindings/net/mediatek-net.txt
-@@ -9,7 +9,8 @@ have dual GMAC each represented by a child node..
+@@ -9,7 +9,8 @@ have dual GMAC each represented by a chi
Required properties:
- compatible: Should be "mediatek,mt7623-eth"
- reg: Address and length of the register set for the device
@@ -41,6 +39,3 @@ index 5ca7929..32eaaca 100644
power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
resets = <&ethsys MT2701_ETHSYS_ETH_RST>;
reset-names = "eth";
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch
new file mode 100644
index 0000000000..8ca6c491e9
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0071-pwm-add-pwm-mediatek.patch
@@ -0,0 +1,337 @@
+From 6f5941c93bdf7649f392f1263b9068d360ceab4d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 6 May 2016 02:55:48 +0200
+Subject: [PATCH 071/102] pwm: add pwm-mediatek
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ arch/arm/boot/dts/mt7623-evb.dts | 17 +++
+ arch/arm/boot/dts/mt7623.dtsi | 22 ++++
+ drivers/pwm/Kconfig | 9 ++
+ drivers/pwm/Makefile | 1 +
+ drivers/pwm/pwm-mediatek.c | 230 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 279 insertions(+)
+ create mode 100644 drivers/pwm/pwm-mediatek.c
+
+--- a/arch/arm/boot/dts/mt7623-evb.dts
++++ b/arch/arm/boot/dts/mt7623-evb.dts
+@@ -341,6 +341,17 @@
+ output-low;
+ };
+ };
++
++ pwm_pins: pwm {
++ pins_pwm1 {
++ pinmux = <MT7623_PIN_204_PWM1_FUNC_PWM1>;
++ };
++
++ pins_pwm2 {
++ pinmux = <MT7623_PIN_205_PWM2_FUNC_PWM2>;
++ };
++ };
++
+ };
+
+ &nandc {
+@@ -419,3 +430,9 @@
+ mediatek,reset-pin = <&pio 15 0>;
+ status = "okay";
+ };
++
++&pwm {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pwm_pins>;
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/mt7623.dtsi
++++ b/arch/arm/boot/dts/mt7623.dtsi
+@@ -324,6 +324,28 @@
+ status = "disabled";
+ };
+
++ pwm: pwm@11006000 {
++ compatible = "mediatek,mt7623-pwm";
++
++ reg = <0 0x11006000 0 0x1000>;
++
++ resets = <&pericfg MT2701_PERI_PWM_SW_RST>;
++ reset-names = "pwm";
++
++ #pwm-cells = <2>;
++ clocks = <&topckgen CLK_TOP_PWM_SEL>,
++ <&pericfg CLK_PERI_PWM>,
++ <&pericfg CLK_PERI_PWM1>,
++ <&pericfg CLK_PERI_PWM2>,
++ <&pericfg CLK_PERI_PWM3>,
++ <&pericfg CLK_PERI_PWM4>,
++ <&pericfg CLK_PERI_PWM5>;
++ clock-names = "top", "main", "pwm1", "pwm2",
++ "pwm3", "pwm4", "pwm5";
++
++ status = "disabled";
++ };
++
+ spi: spi@1100a000 {
+ compatible = "mediatek,mt7623-spi", "mediatek,mt6589-spi";
+ reg = <0 0x1100a000 0 0x1000>;
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -260,6 +260,15 @@ config PWM_MTK_DISP
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-mtk-disp.
+
++config PWM_MEDIATEK
++ tristate "MediaTek PWM support"
++ depends on ARCH_MEDIATEK || COMPILE_TEST
++ help
++ Generic PWM framework driver for Mediatek ARM SoC.
++
++ To compile this driver as a module, choose M here: the module
++ will be called pwm-mxs.
++
+ config PWM_MXS
+ tristate "Freescale MXS PWM support"
+ depends on ARCH_MXS && OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx
+ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
+ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
+ obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
++obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
+ obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
+ obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
+--- /dev/null
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -0,0 +1,230 @@
++/*
++ * Mediatek Pulse Width Modulator driver
++ *
++ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#define NUM_PWM 5
++
++/* PWM registers and bits definitions */
++#define PWMCON 0x00
++#define PWMHDUR 0x04
++#define PWMLDUR 0x08
++#define PWMGDUR 0x0c
++#define PWMWAVENUM 0x28
++#define PWMDWIDTH 0x2c
++#define PWMTHRES 0x30
++
++/**
++ * struct mtk_pwm_chip - struct representing pwm chip
++ *
++ * @mmio_base: base address of pwm chip
++ * @chip: linux pwm chip representation
++ */
++struct mtk_pwm_chip {
++ void __iomem *mmio_base;
++ struct pwm_chip chip;
++ struct clk *clk_top;
++ struct clk *clk_main;
++ struct clk *clk_pwm[NUM_PWM];
++};
++
++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
++{
++ return container_of(chip, struct mtk_pwm_chip, chip);
++}
++
++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
++ unsigned long offset)
++{
++ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
++ unsigned int num, unsigned long offset,
++ unsigned long val)
++{
++ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 resolution = 100 / 4;
++ u32 clkdiv = 0;
++
++ resolution = 1000000000 / (clk_get_rate(pc->clk_pwm[pwm->hwpwm]));
++
++ while (period_ns / resolution > 8191) {
++ clkdiv++;
++ resolution *= 2;
++ }
++
++ if (clkdiv > 7)
++ return -1;
++
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
++ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
++ return 0;
++}
++
++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 val;
++ int ret;
++
++ ret = clk_prepare(pc->clk_pwm[pwm->hwpwm]);
++ if (ret < 0)
++ return ret;
++
++ val = ioread32(pc->mmio_base);
++ val |= BIT(pwm->hwpwm);
++ iowrite32(val, pc->mmio_base);
++
++ return 0;
++}
++
++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++ u32 val;
++
++ val = ioread32(pc->mmio_base);
++ val &= ~BIT(pwm->hwpwm);
++ iowrite32(val, pc->mmio_base);
++ clk_unprepare(pc->clk_pwm[pwm->hwpwm]);
++}
++
++static const struct pwm_ops mtk_pwm_ops = {
++ .config = mtk_pwm_config,
++ .enable = mtk_pwm_enable,
++ .disable = mtk_pwm_disable,
++ .owner = THIS_MODULE,
++};
++
++static int mtk_pwm_probe(struct platform_device *pdev)
++{
++ struct mtk_pwm_chip *pc;
++ struct resource *r;
++ int ret;
++
++ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++ if (!pc)
++ return -ENOMEM;
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++ if (IS_ERR(pc->mmio_base))
++ return PTR_ERR(pc->mmio_base);
++
++ pc->clk_main = devm_clk_get(&pdev->dev, "main");
++ if (IS_ERR(pc->clk_main))
++ return PTR_ERR(pc->clk_main);
++
++ pc->clk_top = devm_clk_get(&pdev->dev, "top");
++ if (IS_ERR(pc->clk_top))
++ return PTR_ERR(pc->clk_top);
++
++ pc->clk_pwm[0] = devm_clk_get(&pdev->dev, "pwm1");
++ if (IS_ERR(pc->clk_pwm[0]))
++ return PTR_ERR(pc->clk_pwm[0]);
++
++ pc->clk_pwm[1] = devm_clk_get(&pdev->dev, "pwm2");
++ if (IS_ERR(pc->clk_pwm[1]))
++ return PTR_ERR(pc->clk_pwm[1]);
++
++ pc->clk_pwm[2] = devm_clk_get(&pdev->dev, "pwm3");
++ if (IS_ERR(pc->clk_pwm[2]))
++ return PTR_ERR(pc->clk_pwm[2]);
++
++ pc->clk_pwm[3] = devm_clk_get(&pdev->dev, "pwm4");
++ if (IS_ERR(pc->clk_pwm[3]))
++ return PTR_ERR(pc->clk_pwm[3]);
++
++ pc->clk_pwm[4] = devm_clk_get(&pdev->dev, "pwm5");
++ if (IS_ERR(pc->clk_pwm[4]))
++ return PTR_ERR(pc->clk_pwm[4]);
++
++ ret = clk_prepare(pc->clk_top);
++ if (ret < 0)
++ return ret;
++
++ ret = clk_prepare(pc->clk_main);
++ if (ret < 0)
++ goto disable_clk_top;
++
++ platform_set_drvdata(pdev, pc);
++
++ pc->chip.dev = &pdev->dev;
++ pc->chip.ops = &mtk_pwm_ops;
++ pc->chip.base = -1;
++ pc->chip.npwm = NUM_PWM;
++
++ ret = pwmchip_add(&pc->chip);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
++ goto disable_clk_main;
++ }
++
++ return 0;
++
++disable_clk_main:
++ clk_unprepare(pc->clk_main);
++disable_clk_top:
++ clk_unprepare(pc->clk_top);
++
++ return ret;
++}
++
++static int mtk_pwm_remove(struct platform_device *pdev)
++{
++ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < NUM_PWM; i++)
++ pwm_disable(&pc->chip.pwms[i]);
++
++ return pwmchip_remove(&pc->chip);
++}
++
++static const struct of_device_id mtk_pwm_of_match[] = {
++ { .compatible = "mediatek,mt7623-pwm" },
++ { }
++};
++
++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
++
++static struct platform_driver mtk_pwm_driver = {
++ .driver = {
++ .name = "mtk-pwm",
++ .owner = THIS_MODULE,
++ .of_match_table = mtk_pwm_of_match,
++ },
++ .probe = mtk_pwm_probe,
++ .remove = mtk_pwm_remove,
++};
++
++module_platform_driver(mtk_pwm_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch b/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch
new file mode 100644
index 0000000000..ccbf8d0fb2
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0072-mtd-backport-v4.7-0day-patches-from-Boris.patch
@@ -0,0 +1,5489 @@
+From a369af5149e6eb442b22ce89b564dd7a76e03638 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 26 Apr 2016 19:05:01 +0200
+Subject: [PATCH 072/102] mtd: backport v4.7-0day patches from Boris
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/mtd/Kconfig | 4 +-
+ drivers/mtd/cmdlinepart.c | 3 +-
+ drivers/mtd/devices/m25p80.c | 44 +--
+ drivers/mtd/maps/physmap_of.c | 6 +-
+ drivers/mtd/mtdchar.c | 123 ++++++--
+ drivers/mtd/mtdconcat.c | 2 +-
+ drivers/mtd/mtdcore.c | 428 ++++++++++++++++++++++++--
+ drivers/mtd/mtdcore.h | 7 +-
+ drivers/mtd/mtdpart.c | 161 ++++++----
+ drivers/mtd/mtdswap.c | 24 +-
+ drivers/mtd/nand/Kconfig | 21 +-
+ drivers/mtd/nand/Makefile | 2 +
+ drivers/mtd/nand/nand_base.c | 571 +++++++++++++++++++----------------
+ drivers/mtd/nand/nand_bbt.c | 34 +--
+ drivers/mtd/nand/nand_bch.c | 52 ++--
+ drivers/mtd/nand/nand_ecc.c | 6 +-
+ drivers/mtd/nand/nand_ids.c | 4 +-
+ drivers/mtd/nand/nandsim.c | 43 +--
+ drivers/mtd/ofpart.c | 53 ++--
+ drivers/mtd/spi-nor/Kconfig | 10 +-
+ drivers/mtd/spi-nor/Makefile | 1 +
+ drivers/mtd/spi-nor/mtk-quadspi.c | 485 +++++++++++++++++++++++++++++
+ drivers/mtd/spi-nor/spi-nor.c | 321 +++++++++++++-------
+ drivers/mtd/tests/mtd_nandecctest.c | 2 +-
+ drivers/mtd/tests/oobtest.c | 49 ++-
+ drivers/mtd/tests/pagetest.c | 3 +-
+ drivers/mtd/ubi/cdev.c | 4 +-
+ drivers/mtd/ubi/misc.c | 49 +++
+ drivers/mtd/ubi/ubi.h | 16 +-
+ drivers/mtd/ubi/upd.c | 2 +-
+ drivers/mtd/ubi/wl.c | 21 +-
+ include/linux/mtd/bbm.h | 1 -
+ include/linux/mtd/fsmc.h | 18 --
+ include/linux/mtd/inftl.h | 1 -
+ include/linux/mtd/map.h | 9 +-
+ include/linux/mtd/mtd.h | 80 ++++-
+ include/linux/mtd/nand.h | 94 ++++--
+ include/linux/mtd/nand_bch.h | 10 +-
+ include/linux/mtd/nftl.h | 1 -
+ include/linux/mtd/onenand.h | 2 -
+ include/linux/mtd/partitions.h | 27 +-
+ include/linux/mtd/sh_flctl.h | 4 +-
+ include/linux/mtd/sharpsl.h | 2 +-
+ include/linux/mtd/spi-nor.h | 23 +-
+ include/uapi/mtd/mtd-abi.h | 2 +-
+ 45 files changed, 2077 insertions(+), 748 deletions(-)
+ create mode 100644 drivers/mtd/spi-nor/mtk-quadspi.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -131,7 +131,7 @@ config MTD_CMDLINE_PARTS
+
+ config MTD_AFS_PARTS
+ tristate "ARM Firmware Suite partition parsing"
+- depends on ARM
++ depends on (ARM || ARM64)
+ ---help---
+ The ARM Firmware Suite allows the user to divide flash devices into
+ multiple 'images'. Each such image has a header containing its name
+@@ -161,7 +161,7 @@ config MTD_AR7_PARTS
+
+ config MTD_BCM63XX_PARTS
+ tristate "BCM63XX CFE partitioning support"
+- depends on BCM63XX
++ depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
+ select CRC32
+ help
+ This provides partions parsing for BCM63xx devices with CFE
+--- a/drivers/mtd/cmdlinepart.c
++++ b/drivers/mtd/cmdlinepart.c
+@@ -304,7 +304,7 @@ static int mtdpart_setup_real(char *s)
+ * the first one in the chain if a NULL mtd_id is passed in.
+ */
+ static int parse_cmdline_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
+ unsigned long long offset;
+@@ -382,7 +382,6 @@ static int __init mtdpart_setup(char *s)
+ __setup("mtdparts=", mtdpart_setup);
+
+ static struct mtd_part_parser cmdline_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_cmdline_partitions,
+ .name = "cmdlinepart",
+ };
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -174,22 +174,6 @@ static int m25p80_read(struct spi_nor *n
+ return 0;
+ }
+
+-static int m25p80_erase(struct spi_nor *nor, loff_t offset)
+-{
+- struct m25p *flash = nor->priv;
+-
+- dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
+- flash->spi_nor.mtd.erasesize / 1024, (u32)offset);
+-
+- /* Set up command buffer. */
+- flash->command[0] = nor->erase_opcode;
+- m25p_addr2cmd(nor, offset, flash->command);
+-
+- spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
+-
+- return 0;
+-}
+-
+ /*
+ * board specific setup should have ensured the SPI clock used here
+ * matches what the READ command supports, at least until this driver
+@@ -197,12 +181,11 @@ static int m25p80_erase(struct spi_nor *
+ */
+ static int m25p_probe(struct spi_device *spi)
+ {
+- struct mtd_part_parser_data ppdata;
+ struct flash_platform_data *data;
+ struct m25p *flash;
+ struct spi_nor *nor;
+ enum read_mode mode = SPI_NOR_NORMAL;
+- char *flash_name = NULL;
++ char *flash_name;
+ int ret;
+
+ data = dev_get_platdata(&spi->dev);
+@@ -216,12 +199,11 @@ static int m25p_probe(struct spi_device
+ /* install the hooks */
+ nor->read = m25p80_read;
+ nor->write = m25p80_write;
+- nor->erase = m25p80_erase;
+ nor->write_reg = m25p80_write_reg;
+ nor->read_reg = m25p80_read_reg;
+
+ nor->dev = &spi->dev;
+- nor->flash_node = spi->dev.of_node;
++ spi_nor_set_flash_node(nor, spi->dev.of_node);
+ nor->priv = flash;
+
+ spi_set_drvdata(spi, flash);
+@@ -242,6 +224,8 @@ static int m25p_probe(struct spi_device
+ */
+ if (data && data->type)
+ flash_name = data->type;
++ else if (!strcmp(spi->modalias, "spi-nor"))
++ flash_name = NULL; /* auto-detect */
+ else
+ flash_name = spi->modalias;
+
+@@ -249,11 +233,8 @@ static int m25p_probe(struct spi_device
+ if (ret)
+ return ret;
+
+- ppdata.of_node = spi->dev.of_node;
+-
+- return mtd_device_parse_register(&nor->mtd, NULL, &ppdata,
+- data ? data->parts : NULL,
+- data ? data->nr_parts : 0);
++ return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
++ data ? data->nr_parts : 0);
+ }
+
+
+@@ -279,14 +260,21 @@ static int m25p_remove(struct spi_device
+ */
+ static const struct spi_device_id m25p_ids[] = {
+ /*
++ * Allow non-DT platform devices to bind to the "spi-nor" modalias, and
++ * hack around the fact that the SPI core does not provide uevent
++ * matching for .of_match_table
++ */
++ {"spi-nor"},
++
++ /*
+ * Entries not used in DTs that should be safe to drop after replacing
+- * them with "nor-jedec" in platform data.
++ * them with "spi-nor" in platform data.
+ */
+ {"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
+
+ /*
+- * Entries that were used in DTs without "nor-jedec" fallback and should
+- * be kept for backward compatibility.
++ * Entries that were used in DTs without "jedec,spi-nor" fallback and
++ * should be kept for backward compatibility.
+ */
+ {"at25df321a"}, {"at25df641"}, {"at26df081a"},
+ {"mr25h256"},
+--- a/drivers/mtd/maps/physmap_of.c
++++ b/drivers/mtd/maps/physmap_of.c
+@@ -128,7 +128,6 @@ static int of_flash_probe(struct platfor
+ int reg_tuple_size;
+ struct mtd_info **mtd_list = NULL;
+ resource_size_t res_size;
+- struct mtd_part_parser_data ppdata;
+ bool map_indirect;
+ const char *mtd_name = NULL;
+
+@@ -272,8 +271,9 @@ static int of_flash_probe(struct platfor
+ if (err)
+ goto err_out;
+
+- ppdata.of_node = dp;
+- mtd_device_parse_register(info->cmtd, part_probe_types_def, &ppdata,
++ info->cmtd->dev.parent = &dev->dev;
++ mtd_set_of_node(info->cmtd, dp);
++ mtd_device_parse_register(info->cmtd, part_probe_types_def, NULL,
+ NULL, 0);
+
+ kfree(mtd_list);
+--- a/drivers/mtd/mtdchar.c
++++ b/drivers/mtd/mtdchar.c
+@@ -465,38 +465,111 @@ static int mtdchar_readoob(struct file *
+ }
+
+ /*
+- * Copies (and truncates, if necessary) data from the larger struct,
+- * nand_ecclayout, to the smaller, deprecated layout struct,
+- * nand_ecclayout_user. This is necessary only to support the deprecated
+- * API ioctl ECCGETLAYOUT while allowing all new functionality to use
+- * nand_ecclayout flexibly (i.e. the struct may change size in new
+- * releases without requiring major rewrites).
++ * Copies (and truncates, if necessary) OOB layout information to the
++ * deprecated layout struct, nand_ecclayout_user. This is necessary only to
++ * support the deprecated API ioctl ECCGETLAYOUT while allowing all new
++ * functionality to use mtd_ooblayout_ops flexibly (i.e. mtd_ooblayout_ops
++ * can describe any kind of OOB layout with almost zero overhead from a
++ * memory usage point of view).
+ */
+-static int shrink_ecclayout(const struct nand_ecclayout *from,
+- struct nand_ecclayout_user *to)
++static int shrink_ecclayout(struct mtd_info *mtd,
++ struct nand_ecclayout_user *to)
+ {
+- int i;
++ struct mtd_oob_region oobregion;
++ int i, section = 0, ret;
+
+- if (!from || !to)
++ if (!mtd || !to)
+ return -EINVAL;
+
+ memset(to, 0, sizeof(*to));
+
+- to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
+- for (i = 0; i < to->eccbytes; i++)
+- to->eccpos[i] = from->eccpos[i];
++ to->eccbytes = 0;
++ for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) {
++ u32 eccpos;
++
++ ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ eccpos = oobregion.offset;
++ for (; i < MTD_MAX_ECCPOS_ENTRIES &&
++ eccpos < oobregion.offset + oobregion.length; i++) {
++ to->eccpos[i] = eccpos++;
++ to->eccbytes++;
++ }
++ }
+
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
+- if (from->oobfree[i].length == 0 &&
+- from->oobfree[i].offset == 0)
++ ret = mtd_ooblayout_free(mtd, i, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
+ break;
+- to->oobavail += from->oobfree[i].length;
+- to->oobfree[i] = from->oobfree[i];
++ }
++
++ to->oobfree[i].offset = oobregion.offset;
++ to->oobfree[i].length = oobregion.length;
++ to->oobavail += to->oobfree[i].length;
+ }
+
+ return 0;
+ }
+
++static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
++{
++ struct mtd_oob_region oobregion;
++ int i, section = 0, ret;
++
++ if (!mtd || !to)
++ return -EINVAL;
++
++ memset(to, 0, sizeof(*to));
++
++ to->eccbytes = 0;
++ for (i = 0; i < ARRAY_SIZE(to->eccpos);) {
++ u32 eccpos;
++
++ ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ if (oobregion.length + i > ARRAY_SIZE(to->eccpos))
++ return -EINVAL;
++
++ eccpos = oobregion.offset;
++ for (; eccpos < oobregion.offset + oobregion.length; i++) {
++ to->eccpos[i] = eccpos++;
++ to->eccbytes++;
++ }
++ }
++
++ for (i = 0; i < 8; i++) {
++ ret = mtd_ooblayout_free(mtd, i, &oobregion);
++ if (ret < 0) {
++ if (ret != -ERANGE)
++ return ret;
++
++ break;
++ }
++
++ to->oobfree[i][0] = oobregion.offset;
++ to->oobfree[i][1] = oobregion.length;
++ }
++
++ to->useecc = MTD_NANDECC_AUTOPLACE;
++
++ return 0;
++}
++
+ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
+ struct blkpg_ioctl_arg *arg)
+ {
+@@ -815,16 +888,12 @@ static int mtdchar_ioctl(struct file *fi
+ {
+ struct nand_oobinfo oi;
+
+- if (!mtd->ecclayout)
++ if (!mtd->ooblayout)
+ return -EOPNOTSUPP;
+- if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
+- return -EINVAL;
+
+- oi.useecc = MTD_NANDECC_AUTOPLACE;
+- memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
+- memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
+- sizeof(oi.oobfree));
+- oi.eccbytes = mtd->ecclayout->eccbytes;
++ ret = get_oobinfo(mtd, &oi);
++ if (ret)
++ return ret;
+
+ if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
+ return -EFAULT;
+@@ -913,14 +982,14 @@ static int mtdchar_ioctl(struct file *fi
+ {
+ struct nand_ecclayout_user *usrlay;
+
+- if (!mtd->ecclayout)
++ if (!mtd->ooblayout)
+ return -EOPNOTSUPP;
+
+ usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
+ if (!usrlay)
+ return -ENOMEM;
+
+- shrink_ecclayout(mtd->ecclayout, usrlay);
++ shrink_ecclayout(mtd, usrlay);
+
+ if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
+ ret = -EFAULT;
+--- a/drivers/mtd/mtdconcat.c
++++ b/drivers/mtd/mtdconcat.c
+@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struc
+
+ }
+
+- concat->mtd.ecclayout = subdev[0]->ecclayout;
++ mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);
+
+ concat->num_subdev = num_devs;
+ concat->mtd.name = name;
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -32,6 +32,7 @@
+ #include <linux/err.h>
+ #include <linux/ioctl.h>
+ #include <linux/init.h>
++#include <linux/of.h>
+ #include <linux/proc_fs.h>
+ #include <linux/idr.h>
+ #include <linux/backing-dev.h>
+@@ -446,6 +447,7 @@ int add_mtd_device(struct mtd_info *mtd)
+ mtd->dev.devt = MTD_DEVT(i);
+ dev_set_name(&mtd->dev, "mtd%d", i);
+ dev_set_drvdata(&mtd->dev, mtd);
++ of_node_get(mtd_get_of_node(mtd));
+ error = device_register(&mtd->dev);
+ if (error)
+ goto fail_added;
+@@ -477,6 +479,7 @@ int add_mtd_device(struct mtd_info *mtd)
+ return 0;
+
+ fail_added:
++ of_node_put(mtd_get_of_node(mtd));
+ idr_remove(&mtd_idr, i);
+ fail_locked:
+ mutex_unlock(&mtd_table_mutex);
+@@ -518,6 +521,7 @@ int del_mtd_device(struct mtd_info *mtd)
+ device_unregister(&mtd->dev);
+
+ idr_remove(&mtd_idr, mtd->index);
++ of_node_put(mtd_get_of_node(mtd));
+
+ module_put(THIS_MODULE);
+ ret = 0;
+@@ -529,9 +533,10 @@ out_error:
+ }
+
+ static int mtd_add_device_partitions(struct mtd_info *mtd,
+- struct mtd_partition *real_parts,
+- int nbparts)
++ struct mtd_partitions *parts)
+ {
++ const struct mtd_partition *real_parts = parts->parts;
++ int nbparts = parts->nr_parts;
+ int ret;
+
+ if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
+@@ -600,29 +605,29 @@ int mtd_device_parse_register(struct mtd
+ const struct mtd_partition *parts,
+ int nr_parts)
+ {
++ struct mtd_partitions parsed;
+ int ret;
+- struct mtd_partition *real_parts = NULL;
+
+ mtd_set_dev_defaults(mtd);
+
+- ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
+- if (ret <= 0 && nr_parts && parts) {
+- real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
+- GFP_KERNEL);
+- if (!real_parts)
+- ret = -ENOMEM;
+- else
+- ret = nr_parts;
+- }
+- /* Didn't come up with either parsed OR fallback partitions */
+- if (ret < 0) {
+- pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
++ memset(&parsed, 0, sizeof(parsed));
++
++ ret = parse_mtd_partitions(mtd, types, &parsed, parser_data);
++ if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) {
++ /* Fall back to driver-provided partitions */
++ parsed = (struct mtd_partitions){
++ .parts = parts,
++ .nr_parts = nr_parts,
++ };
++ } else if (ret < 0) {
++ /* Didn't come up with parsed OR fallback partitions */
++ pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n",
+ ret);
+ /* Don't abort on errors; we can still use unpartitioned MTD */
+- ret = 0;
++ memset(&parsed, 0, sizeof(parsed));
+ }
+
+- ret = mtd_add_device_partitions(mtd, real_parts, ret);
++ ret = mtd_add_device_partitions(mtd, &parsed);
+ if (ret)
+ goto out;
+
+@@ -642,7 +647,8 @@ int mtd_device_parse_register(struct mtd
+ }
+
+ out:
+- kfree(real_parts);
++ /* Cleanup any parsed partitions */
++ mtd_part_parser_cleanup(&parsed);
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(mtd_device_parse_register);
+@@ -767,7 +773,6 @@ out:
+ }
+ EXPORT_SYMBOL_GPL(get_mtd_device);
+
+-
+ int __get_mtd_device(struct mtd_info *mtd)
+ {
+ int err;
+@@ -1001,6 +1006,366 @@ int mtd_read_oob(struct mtd_info *mtd, l
+ }
+ EXPORT_SYMBOL_GPL(mtd_read_oob);
+
++/**
++ * mtd_ooblayout_ecc - Get the OOB region definition of a specific ECC section
++ * @mtd: MTD device structure
++ * @section: ECC section. Depending on the layout you may have all the ECC
++ * bytes stored in a single contiguous section, or one section
++ * per ECC chunk (and sometime several sections for a single ECC
++ * ECC chunk)
++ * @oobecc: OOB region struct filled with the appropriate ECC position
++ * information
++ *
++ * This functions return ECC section information in the OOB area. I you want
++ * to get all the ECC bytes information, then you should call
++ * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc)
++{
++ memset(oobecc, 0, sizeof(*oobecc));
++
++ if (!mtd || section < 0)
++ return -EINVAL;
++
++ if (!mtd->ooblayout || !mtd->ooblayout->ecc)
++ return -ENOTSUPP;
++
++ return mtd->ooblayout->ecc(mtd, section, oobecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
++
++/**
++ * mtd_ooblayout_free - Get the OOB region definition of a specific free
++ * section
++ * @mtd: MTD device structure
++ * @section: Free section you are interested in. Depending on the layout
++ * you may have all the free bytes stored in a single contiguous
++ * section, or one section per ECC chunk plus an extra section
++ * for the remaining bytes (or other funky layout).
++ * @oobfree: OOB region struct filled with the appropriate free position
++ * information
++ *
++ * This functions return free bytes position in the OOB area. I you want
++ * to get all the free bytes information, then you should call
++ * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree)
++{
++ memset(oobfree, 0, sizeof(*oobfree));
++
++ if (!mtd || section < 0)
++ return -EINVAL;
++
++ if (!mtd->ooblayout || !mtd->ooblayout->free)
++ return -ENOTSUPP;
++
++ return mtd->ooblayout->free(mtd, section, oobfree);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
++
++/**
++ * mtd_ooblayout_find_region - Find the region attached to a specific byte
++ * @mtd: mtd info structure
++ * @byte: the byte we are searching for
++ * @sectionp: pointer where the section id will be stored
++ * @oobregion: used to retrieve the ECC position
++ * @iter: iterator function. Should be either mtd_ooblayout_free or
++ * mtd_ooblayout_ecc depending on the region type you're searching for
++ *
++ * This functions returns the section id and oobregion information of a
++ * specific byte. For example, say you want to know where the 4th ECC byte is
++ * stored, you'll use:
++ *
++ * mtd_ooblayout_find_region(mtd, 3, &section, &oobregion, mtd_ooblayout_ecc);
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_find_region(struct mtd_info *mtd, int byte,
++ int *sectionp, struct mtd_oob_region *oobregion,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ int pos = 0, ret, section = 0;
++
++ memset(oobregion, 0, sizeof(*oobregion));
++
++ while (1) {
++ ret = iter(mtd, section, oobregion);
++ if (ret)
++ return ret;
++
++ if (pos + oobregion->length > byte)
++ break;
++
++ pos += oobregion->length;
++ section++;
++ }
++
++ /*
++ * Adjust region info to make it start at the beginning at the
++ * 'start' ECC byte.
++ */
++ oobregion->offset += byte - pos;
++ oobregion->length -= byte - pos;
++ *sectionp = section;
++
++ return 0;
++}
++
++/**
++ * mtd_ooblayout_find_eccregion - Find the ECC region attached to a specific
++ * ECC byte
++ * @mtd: mtd info structure
++ * @eccbyte: the byte we are searching for
++ * @sectionp: pointer where the section id will be stored
++ * @oobregion: OOB region information
++ *
++ * Works like mtd_ooblayout_find_region() except it searches for a specific ECC
++ * byte.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
++ int *section,
++ struct mtd_oob_region *oobregion)
++{
++ return mtd_ooblayout_find_region(mtd, eccbyte, section, oobregion,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_find_eccregion);
++
++/**
++ * mtd_ooblayout_get_bytes - Extract OOB bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @buf: destination buffer to store OOB bytes
++ * @oobbuf: OOB buffer
++ * @start: first byte to retrieve
++ * @nbytes: number of bytes to retrieve
++ * @iter: section iterator
++ *
++ * Extract bytes attached to a specific category (ECC or free)
++ * from the OOB buffer and copy them into buf.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf,
++ const u8 *oobbuf, int start, int nbytes,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret;
++
++ ret = mtd_ooblayout_find_region(mtd, start, &section,
++ &oobregion, iter);
++
++ while (!ret) {
++ int cnt;
++
++ cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
++ memcpy(buf, oobbuf + oobregion.offset, cnt);
++ buf += cnt;
++ nbytes -= cnt;
++
++ if (!nbytes)
++ break;
++
++ ret = iter(mtd, ++section, &oobregion);
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_set_bytes - put OOB bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @buf: source buffer to get OOB bytes from
++ * @oobbuf: OOB buffer
++ * @start: first OOB byte to set
++ * @nbytes: number of OOB bytes to set
++ * @iter: section iterator
++ *
++ * Fill the OOB buffer with data provided in buf. The category (ECC or free)
++ * is selected by passing the appropriate iterator.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf,
++ u8 *oobbuf, int start, int nbytes,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret;
++
++ ret = mtd_ooblayout_find_region(mtd, start, &section,
++ &oobregion, iter);
++
++ while (!ret) {
++ int cnt;
++
++ cnt = oobregion.length > nbytes ? nbytes : oobregion.length;
++ memcpy(oobbuf + oobregion.offset, buf, cnt);
++ buf += cnt;
++ nbytes -= cnt;
++
++ if (!nbytes)
++ break;
++
++ ret = iter(mtd, ++section, &oobregion);
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_count_bytes - count the number of bytes in a OOB category
++ * @mtd: mtd info structure
++ * @iter: category iterator
++ *
++ * Count the number of bytes in a given category.
++ *
++ * Returns a positive value on success, a negative error code otherwise.
++ */
++static int mtd_ooblayout_count_bytes(struct mtd_info *mtd,
++ int (*iter)(struct mtd_info *,
++ int section,
++ struct mtd_oob_region *oobregion))
++{
++ struct mtd_oob_region oobregion = { };
++ int section = 0, ret, nbytes = 0;
++
++ while (1) {
++ ret = iter(mtd, section++, &oobregion);
++ if (ret) {
++ if (ret == -ERANGE)
++ ret = nbytes;
++ break;
++ }
++
++ nbytes += oobregion.length;
++ }
++
++ return ret;
++}
++
++/**
++ * mtd_ooblayout_get_eccbytes - extract ECC bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: destination buffer to store ECC bytes
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to retrieve
++ * @nbytes: number of ECC bytes to retrieve
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
++ const u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_get_bytes(mtd, eccbuf, oobbuf, start, nbytes,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_get_eccbytes);
++
++/**
++ * mtd_ooblayout_set_eccbytes - set ECC bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: source buffer to get ECC bytes from
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to set
++ * @nbytes: number of ECC bytes to set
++ *
++ * Works like mtd_ooblayout_set_bytes(), except it acts on ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
++ u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_set_bytes(mtd, eccbuf, oobbuf, start, nbytes,
++ mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_set_eccbytes);
++
++/**
++ * mtd_ooblayout_get_databytes - extract data bytes from the oob buffer
++ * @mtd: mtd info structure
++ * @databuf: destination buffer to store ECC bytes
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to retrieve
++ * @nbytes: number of ECC bytes to retrieve
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
++ const u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_get_bytes(mtd, databuf, oobbuf, start, nbytes,
++ mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_get_databytes);
++
++/**
++ * mtd_ooblayout_get_eccbytes - set data bytes into the oob buffer
++ * @mtd: mtd info structure
++ * @eccbuf: source buffer to get data bytes from
++ * @oobbuf: OOB buffer
++ * @start: first ECC byte to set
++ * @nbytes: number of ECC bytes to set
++ *
++ * Works like mtd_ooblayout_get_bytes(), except it acts on free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
++ u8 *oobbuf, int start, int nbytes)
++{
++ return mtd_ooblayout_set_bytes(mtd, databuf, oobbuf, start, nbytes,
++ mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_set_databytes);
++
++/**
++ * mtd_ooblayout_count_freebytes - count the number of free bytes in OOB
++ * @mtd: mtd info structure
++ *
++ * Works like mtd_ooblayout_count_bytes(), except it count free bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_count_freebytes(struct mtd_info *mtd)
++{
++ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_free);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_count_freebytes);
++
++/**
++ * mtd_ooblayout_count_freebytes - count the number of ECC bytes in OOB
++ * @mtd: mtd info structure
++ *
++ * Works like mtd_ooblayout_count_bytes(), except it count ECC bytes.
++ *
++ * Returns zero on success, a negative error code otherwise.
++ */
++int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
++{
++ return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc);
++}
++EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
++
+ /*
+ * Method to access the protection register area, present in some flash
+ * devices. The user data is one time programmable but the factory data is read
+--- a/drivers/mtd/mtdcore.h
++++ b/drivers/mtd/mtdcore.h
+@@ -10,10 +10,15 @@ int add_mtd_device(struct mtd_info *mtd)
+ int del_mtd_device(struct mtd_info *mtd);
+ int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
+ int del_mtd_partitions(struct mtd_info *);
++
++struct mtd_partitions;
++
+ int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
+- struct mtd_partition **pparts,
++ struct mtd_partitions *pparts,
+ struct mtd_part_parser_data *data);
+
++void mtd_part_parser_cleanup(struct mtd_partitions *parts);
++
+ int __init init_mtdchar(void);
+ void __exit cleanup_mtdchar(void);
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -55,9 +55,12 @@ static void mtd_partition_split(struct m
+
+ /*
+ * Given a pointer to the MTD object in the mtd_part structure, we can retrieve
+- * the pointer to that structure with this macro.
++ * the pointer to that structure.
+ */
+-#define PART(x) ((struct mtd_part *)(x))
++static inline struct mtd_part *mtd_to_part(const struct mtd_info *mtd)
++{
++ return container_of(mtd, struct mtd_part, mtd);
++}
+
+
+ /*
+@@ -68,7 +71,7 @@ static void mtd_partition_split(struct m
+ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ struct mtd_ecc_stats stats;
+ int res;
+
+@@ -87,7 +90,7 @@ static int part_read(struct mtd_info *mt
+ static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ return part->master->_point(part->master, from + part->offset, len,
+ retlen, virt, phys);
+@@ -95,7 +98,7 @@ static int part_point(struct mtd_info *m
+
+ static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ return part->master->_unpoint(part->master, from + part->offset, len);
+ }
+@@ -105,7 +108,7 @@ static unsigned long part_get_unmapped_a
+ unsigned long offset,
+ unsigned long flags)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ offset += part->offset;
+ return part->master->_get_unmapped_area(part->master, len, offset,
+@@ -115,7 +118,7 @@ static unsigned long part_get_unmapped_a
+ static int part_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int res;
+
+ if (from >= mtd->size)
+@@ -130,10 +133,7 @@ static int part_read_oob(struct mtd_info
+ if (ops->oobbuf) {
+ size_t len, pages;
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = mtd->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+ pages = mtd_div_by_ws(mtd->size, mtd);
+ pages -= mtd_div_by_ws(from, mtd);
+ if (ops->ooboffs + ops->ooblen > pages * len)
+@@ -153,7 +153,7 @@ static int part_read_oob(struct mtd_info
+ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_read_user_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -161,7 +161,7 @@ static int part_read_user_prot_reg(struc
+ static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_get_user_prot_info(part->master, len, retlen,
+ buf);
+ }
+@@ -169,7 +169,7 @@ static int part_get_user_prot_info(struc
+ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_read_fact_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -177,7 +177,7 @@ static int part_read_fact_prot_reg(struc
+ static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
+ size_t *retlen, struct otp_info *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_get_fact_prot_info(part->master, len, retlen,
+ buf);
+ }
+@@ -185,7 +185,7 @@ static int part_get_fact_prot_info(struc
+ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_write(part->master, to + part->offset, len,
+ retlen, buf);
+ }
+@@ -193,7 +193,7 @@ static int part_write(struct mtd_info *m
+ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_panic_write(part->master, to + part->offset, len,
+ retlen, buf);
+ }
+@@ -201,7 +201,7 @@ static int part_panic_write(struct mtd_i
+ static int part_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ if (to >= mtd->size)
+ return -EINVAL;
+@@ -213,7 +213,7 @@ static int part_write_oob(struct mtd_inf
+ static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen, u_char *buf)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_write_user_prot_reg(part->master, from, len,
+ retlen, buf);
+ }
+@@ -221,21 +221,21 @@ static int part_write_user_prot_reg(stru
+ static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_lock_user_prot_reg(part->master, from, len);
+ }
+
+ static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_writev(part->master, vecs, count,
+ to + part->offset, retlen);
+ }
+
+ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int ret;
+
+
+@@ -299,7 +299,7 @@ static int part_erase(struct mtd_info *m
+ void mtd_erase_callback(struct erase_info *instr)
+ {
+ if (instr->mtd->_erase == part_erase) {
+- struct mtd_part *part = PART(instr->mtd);
++ struct mtd_part *part = mtd_to_part(instr->mtd);
+ size_t wrlen = 0;
+
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+@@ -330,13 +330,13 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
+
+ static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_lock(part->master, ofs + part->offset, len);
+ }
+
+ static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+
+ ofs += part->offset;
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
+@@ -349,45 +349,45 @@ static int part_unlock(struct mtd_info *
+
+ static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_is_locked(part->master, ofs + part->offset, len);
+ }
+
+ static void part_sync(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ part->master->_sync(part->master);
+ }
+
+ static int part_suspend(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return part->master->_suspend(part->master);
+ }
+
+ static void part_resume(struct mtd_info *mtd)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ part->master->_resume(part->master);
+ }
+
+ static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ ofs += part->offset;
+ return part->master->_block_isreserved(part->master, ofs);
+ }
+
+ static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ ofs += part->offset;
+ return part->master->_block_isbad(part->master, ofs);
+ }
+
+ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ int res;
+
+ ofs += part->offset;
+@@ -397,6 +397,27 @@ static int part_block_markbad(struct mtd
+ return res;
+ }
+
++static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct mtd_part *part = mtd_to_part(mtd);
++
++ return mtd_ooblayout_ecc(part->master, section, oobregion);
++}
++
++static int part_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct mtd_part *part = mtd_to_part(mtd);
++
++ return mtd_ooblayout_free(part->master, section, oobregion);
++}
++
++static const struct mtd_ooblayout_ops part_ooblayout_ops = {
++ .ecc = part_ooblayout_ecc,
++ .free = part_ooblayout_free,
++};
++
+ static inline void free_partition(struct mtd_part *p)
+ {
+ kfree(p->mtd.name);
+@@ -614,7 +635,7 @@ static struct mtd_part *allocate_partiti
+ slave->mtd.erasesize = slave->mtd.size;
+ }
+
+- slave->mtd.ecclayout = master->ecclayout;
++ mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
+ slave->mtd.ecc_step_size = master->ecc_step_size;
+ slave->mtd.ecc_strength = master->ecc_strength;
+ slave->mtd.bitflip_threshold = master->bitflip_threshold;
+@@ -639,7 +660,7 @@ static ssize_t mtd_partition_offset_show
+ struct device_attribute *attr, char *buf)
+ {
+ struct mtd_info *mtd = dev_get_drvdata(dev);
+- struct mtd_part *part = PART(mtd);
++ struct mtd_part *part = mtd_to_part(mtd);
+ return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset);
+ }
+
+@@ -677,11 +698,10 @@ int mtd_add_partition(struct mtd_info *m
+ if (length <= 0)
+ return -EINVAL;
+
++ memset(&part, 0, sizeof(part));
+ part.name = name;
+ part.size = length;
+ part.offset = offset;
+- part.mask_flags = 0;
+- part.ecclayout = NULL;
+
+ new = allocate_partition(master, &part, -1, offset);
+ if (IS_ERR(new))
+@@ -845,7 +865,7 @@ int add_mtd_partitions(struct mtd_info *
+ static DEFINE_SPINLOCK(part_parser_lock);
+ static LIST_HEAD(part_parsers);
+
+-static struct mtd_part_parser *get_partition_parser(const char *name)
++static struct mtd_part_parser *mtd_part_parser_get(const char *name)
+ {
+ struct mtd_part_parser *p, *ret = NULL;
+
+@@ -862,7 +882,20 @@ static struct mtd_part_parser *get_parti
+ return ret;
+ }
+
+-#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
++static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
++{
++ module_put(p->owner);
++}
++
++/*
++ * Many partition parsers just expected the core to kfree() all their data in
++ * one chunk. Do that by default.
++ */
++static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts,
++ int nr_parts)
++{
++ kfree(pparts);
++}
+
+ static struct mtd_part_parser *
+ get_partition_parser_by_type(enum mtd_parser_type type,
+@@ -874,7 +907,7 @@ get_partition_parser_by_type(enum mtd_pa
+
+ p = list_prepare_entry(start, &part_parsers, list);
+ if (start)
+- put_partition_parser(start);
++ mtd_part_parser_put(start);
+
+ list_for_each_entry_continue(p, &part_parsers, list) {
+ if (p->type == type && try_module_get(p->owner)) {
+@@ -888,13 +921,19 @@ get_partition_parser_by_type(enum mtd_pa
+ return ret;
+ }
+
+-void register_mtd_parser(struct mtd_part_parser *p)
+-{
++int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner)
++ {
++ p->owner = owner;
++
++ if (!p->cleanup)
++ p->cleanup = &mtd_part_parser_cleanup_default;
++
+ spin_lock(&part_parser_lock);
+ list_add(&p->list, &part_parsers);
+ spin_unlock(&part_parser_lock);
++ return 0;
+ }
+-EXPORT_SYMBOL_GPL(register_mtd_parser);
++EXPORT_SYMBOL_GPL(__register_mtd_parser);
+
+ void deregister_mtd_parser(struct mtd_part_parser *p)
+ {
+@@ -954,7 +993,7 @@ static const char * const default_mtd_pa
+ * parse_mtd_partitions - parse MTD partitions
+ * @master: the master partition (describes whole MTD device)
+ * @types: names of partition parsers to try or %NULL
+- * @pparts: array of partitions found is returned here
++ * @pparts: info about partitions found is returned here
+ * @data: MTD partition parser-specific data
+ *
+ * This function tries to find partition on MTD device @master. It uses MTD
+@@ -966,45 +1005,42 @@ static const char * const default_mtd_pa
+ *
+ * This function may return:
+ * o a negative error code in case of failure
+- * o zero if no partitions were found
+- * o a positive number of found partitions, in which case on exit @pparts will
+- * point to an array containing this number of &struct mtd_info objects.
++ * o zero otherwise, and @pparts will describe the partitions, number of
++ * partitions, and the parser which parsed them. Caller must release
++ * resources with mtd_part_parser_cleanup() when finished with the returned
++ * data.
+ */
+ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
+- struct mtd_partition **pparts,
++ struct mtd_partitions *pparts,
+ struct mtd_part_parser_data *data)
+ {
+ struct mtd_part_parser *parser;
+ int ret, err = 0;
+ const char *const *types_of = NULL;
+
+- if (data && data->of_node) {
+- types_of = of_get_probes(data->of_node);
+- if (types_of != NULL)
+- types = types_of;
+- }
+-
+ if (!types)
+ types = default_mtd_part_types;
+
+ for ( ; *types; types++) {
+ pr_debug("%s: parsing partitions %s\n", master->name, *types);
+- parser = get_partition_parser(*types);
++ parser = mtd_part_parser_get(*types);
+ if (!parser && !request_module("%s", *types))
+- parser = get_partition_parser(*types);
++ parser = mtd_part_parser_get(*types);
+ pr_debug("%s: got parser %s\n", master->name,
+ parser ? parser->name : NULL);
+ if (!parser)
+ continue;
+- ret = (*parser->parse_fn)(master, pparts, data);
++ ret = (*parser->parse_fn)(master, &pparts->parts, data);
+ pr_debug("%s: parser %s: %i\n",
+ master->name, parser->name, ret);
+- put_partition_parser(parser);
+ if (ret > 0) {
+ printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+- return ret;
++ pparts->nr_parts = ret;
++ pparts->parser = parser;
++ return 0;
+ }
++ mtd_part_parser_put(parser);
+ /*
+ * Stash the first error we see; only report it if no parser
+ * succeeds
+@@ -1034,7 +1070,7 @@ int parse_mtd_partitions_by_type(struct
+ ret = (*parser->parse_fn)(master, pparts, data);
+
+ if (ret > 0) {
+- put_partition_parser(parser);
++ mtd_part_parser_put(parser);
+ printk(KERN_NOTICE
+ "%d %s partitions found on MTD device %s\n",
+ ret, parser->name, master->name);
+@@ -1048,6 +1084,22 @@ int parse_mtd_partitions_by_type(struct
+ }
+ EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
+
++void mtd_part_parser_cleanup(struct mtd_partitions *parts)
++{
++ const struct mtd_part_parser *parser;
++
++ if (!parts)
++ return;
++
++ parser = parts->parser;
++ if (parser) {
++ if (parser->cleanup)
++ parser->cleanup(parts->parts, parts->nr_parts);
++
++ mtd_part_parser_put(parser);
++ }
++}
++
+ int mtd_is_partition(const struct mtd_info *mtd)
+ {
+ struct mtd_part *part;
+@@ -1070,7 +1122,7 @@ struct mtd_info *mtdpart_get_master(cons
+ if (!mtd_is_partition(mtd))
+ return (struct mtd_info *)mtd;
+
+- return PART(mtd)->master;
++ return mtd_to_part(mtd)->master;
+ }
+ EXPORT_SYMBOL_GPL(mtdpart_get_master);
+
+@@ -1079,7 +1131,7 @@ uint64_t mtdpart_get_offset(const struct
+ if (!mtd_is_partition(mtd))
+ return 0;
+
+- return PART(mtd)->offset;
++ return mtd_to_part(mtd)->offset;
+ }
+ EXPORT_SYMBOL_GPL(mtdpart_get_offset);
+
+@@ -1089,6 +1141,6 @@ uint64_t mtd_get_device_size(const struc
+ if (!mtd_is_partition(mtd))
+ return mtd->size;
+
+- return PART(mtd)->master->size;
++ return mtd_to_part(mtd)->master->size;
+ }
+ EXPORT_SYMBOL_GPL(mtd_get_device_size);
+--- a/drivers/mtd/mtdswap.c
++++ b/drivers/mtd/mtdswap.c
+@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct m
+ if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset))
+ return MTDSWAP_SCANNED_BAD;
+
+- ops.ooblen = 2 * d->mtd->ecclayout->oobavail;
++ ops.ooblen = 2 * d->mtd->oobavail;
+ ops.oobbuf = d->oob_buf;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct m
+
+ data = (struct mtdswap_oobdata *)d->oob_buf;
+ data2 = (struct mtdswap_oobdata *)
+- (d->oob_buf + d->mtd->ecclayout->oobavail);
++ (d->oob_buf + d->mtd->oobavail);
+
+ if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
+ eb->erase_count = le32_to_cpu(data->count);
+@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = mtd->writesize;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.ooboffs = 0;
+ ops.datbuf = d->page_buf;
+ ops.oobbuf = d->oob_buf;
+@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(
+ for (i = 0; i < mtd_pages; i++) {
+ patt = mtdswap_test_patt(test + i);
+ memset(d->page_buf, patt, mtd->writesize);
+- memset(d->oob_buf, patt, mtd->ecclayout->oobavail);
++ memset(d->oob_buf, patt, mtd->oobavail);
+ ret = mtd_write_oob(mtd, pos, &ops);
+ if (ret)
+ goto error;
+@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(
+ if (p1[j] != patt)
+ goto error;
+
+- for (j = 0; j < mtd->ecclayout->oobavail; j++)
++ for (j = 0; j < mtd->oobavail; j++)
+ if (p2[j] != (unsigned char)patt)
+ goto error;
+
+@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_d
+ if (!d->page_buf)
+ goto page_buf_fail;
+
+- d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL);
++ d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL);
+ if (!d->oob_buf)
+ goto oob_buf_fail;
+
+@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_b
+ unsigned long part;
+ unsigned int eblocks, eavailable, bad_blocks, spare_cnt;
+ uint64_t swap_size, use_size, size_limit;
+- struct nand_ecclayout *oinfo;
+ int ret;
+
+ parts = &partitions[0];
+@@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_b
+ return;
+ }
+
+- oinfo = mtd->ecclayout;
+- if (!oinfo) {
+- printk(KERN_ERR "%s: mtd%d does not have OOB\n",
+- MTDSWAP_PREFIX, mtd->index);
+- return;
+- }
+-
+- if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
++ if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
+ printk(KERN_ERR "%s: Not enough free bytes in OOB, "
+ "%d available, %zu needed.\n",
+- MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE);
++ MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
+ return;
+ }
+
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -55,7 +55,7 @@ config MTD_NAND_DENALI_PCI
+ config MTD_NAND_DENALI_DT
+ tristate "Support Denali NAND controller as a DT device"
+ select MTD_NAND_DENALI
+- depends on HAS_DMA && HAVE_CLK
++ depends on HAS_DMA && HAVE_CLK && OF
+ help
+ Enable the driver for NAND flash on platforms using a Denali NAND
+ controller as a DT device.
+@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
+ config MTD_NAND_GPIO
+ tristate "GPIO assisted NAND Flash driver"
+ depends on GPIOLIB || COMPILE_TEST
++ depends on HAS_IOMEM
+ help
+ This enables a NAND flash driver where control signals are
+ connected to GPIO pins, and commands and data are communicated
+@@ -310,6 +311,7 @@ config MTD_NAND_CAFE
+ config MTD_NAND_CS553X
+ tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
+ depends on X86_32
++ depends on !UML && HAS_IOMEM
+ help
+ The CS553x companion chips for the AMD Geode processor
+ include NAND flash controllers with built-in hardware ECC
+@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC
+ config MTD_NAND_VF610_NFC
+ tristate "Support for Freescale NFC for VF610/MPC5125"
+ depends on (SOC_VF610 || COMPILE_TEST)
++ depends on HAS_IOMEM
+ help
+ Enables support for NAND Flash Controller on some Freescale
+ processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
+@@ -480,7 +483,7 @@ config MTD_NAND_MXC
+
+ config MTD_NAND_SH_FLCTL
+ tristate "Support for NAND on Renesas SuperH FLCTL"
+- depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
++ depends on SUPERH || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on HAS_DMA
+ help
+@@ -519,6 +522,13 @@ config MTD_NAND_JZ4740
+ help
+ Enables support for NAND Flash on JZ4740 SoC based boards.
+
++config MTD_NAND_JZ4780
++ tristate "Support for NAND on JZ4780 SoC"
++ depends on MACH_JZ4780 && JZ4780_NEMC
++ help
++ Enables support for NAND Flash connected to the NEMC on JZ4780 SoC
++ based boards, using the BCH controller for hardware error correction.
++
+ config MTD_NAND_FSMC
+ tristate "Support for NAND on ST Micros FSMC"
+ depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300
+@@ -546,4 +556,11 @@ config MTD_NAND_HISI504
+ help
+ Enables support for NAND controller on Hisilicon SoC Hip04.
+
++config MTD_NAND_QCOM
++ tristate "Support for NAND on QCOM SoCs"
++ depends on ARCH_QCOM
++ help
++ Enables support for NAND flash chips on SoCs containing the EBI2 NAND
++ controller. This controller is found on IPQ806x SoC.
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -49,11 +49,13 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mp
+ obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
+ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
++obj-$(CONFIG_MTD_NAND_JZ4780) += jz4780_nand.o jz4780_bch.o
+ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
+ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
+ 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_QCOM) += qcom_nandc.o
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -48,50 +48,6 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/of_mtd.h>
+
+-/* Define default oob placement schemes for large and small page devices */
+-static struct nand_ecclayout nand_oob_8 = {
+- .eccbytes = 3,
+- .eccpos = {0, 1, 2},
+- .oobfree = {
+- {.offset = 3,
+- .length = 2},
+- {.offset = 6,
+- .length = 2} }
+-};
+-
+-static struct nand_ecclayout nand_oob_16 = {
+- .eccbytes = 6,
+- .eccpos = {0, 1, 2, 3, 6, 7},
+- .oobfree = {
+- {.offset = 8,
+- . length = 8} }
+-};
+-
+-static struct nand_ecclayout nand_oob_64 = {
+- .eccbytes = 24,
+- .eccpos = {
+- 40, 41, 42, 43, 44, 45, 46, 47,
+- 48, 49, 50, 51, 52, 53, 54, 55,
+- 56, 57, 58, 59, 60, 61, 62, 63},
+- .oobfree = {
+- {.offset = 2,
+- .length = 38} }
+-};
+-
+-static struct nand_ecclayout nand_oob_128 = {
+- .eccbytes = 48,
+- .eccpos = {
+- 80, 81, 82, 83, 84, 85, 86, 87,
+- 88, 89, 90, 91, 92, 93, 94, 95,
+- 96, 97, 98, 99, 100, 101, 102, 103,
+- 104, 105, 106, 107, 108, 109, 110, 111,
+- 112, 113, 114, 115, 116, 117, 118, 119,
+- 120, 121, 122, 123, 124, 125, 126, 127},
+- .oobfree = {
+- {.offset = 2,
+- .length = 78} }
+-};
+-
+ static int nand_get_device(struct mtd_info *mtd, int new_state);
+
+ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+@@ -103,10 +59,96 @@ static int nand_do_write_oob(struct mtd_
+ */
+ DEFINE_LED_TRIGGER(nand_led_trigger);
+
++/* Define default oob placement schemes for large and small page devices */
++static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section > 1)
++ return -ERANGE;
++
++ if (!section) {
++ oobregion->offset = 0;
++ oobregion->length = 4;
++ } else {
++ oobregion->offset = 6;
++ oobregion->length = ecc->total - 4;
++ }
++
++ return 0;
++}
++
++static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ if (section > 1)
++ return -ERANGE;
++
++ if (mtd->oobsize == 16) {
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = 8;
++ oobregion->offset = 8;
++ } else {
++ oobregion->length = 2;
++ if (!section)
++ oobregion->offset = 3;
++ else
++ oobregion->offset = 6;
++ }
++
++ return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = {
++ .ecc = nand_ooblayout_ecc_sp,
++ .free = nand_ooblayout_free_sp,
++};
++EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops);
++
++static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = ecc->total;
++ oobregion->offset = mtd->oobsize - oobregion->length;
++
++ return 0;
++}
++
++static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobregion)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nand_ecc_ctrl *ecc = &chip->ecc;
++
++ if (section)
++ return -ERANGE;
++
++ oobregion->length = mtd->oobsize - ecc->total - 2;
++ oobregion->offset = 2;
++
++ return 0;
++}
++
++const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = {
++ .ecc = nand_ooblayout_ecc_lp,
++ .free = nand_ooblayout_free_lp,
++};
++EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops);
++
+ static int check_offs_len(struct mtd_info *mtd,
+ loff_t ofs, uint64_t len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+
+ /* Start address must align on block boundary */
+@@ -132,7 +174,7 @@ static int check_offs_len(struct mtd_inf
+ */
+ static void nand_release_device(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Release the controller and the chip */
+ spin_lock(&chip->controller->lock);
+@@ -150,7 +192,7 @@ static void nand_release_device(struct m
+ */
+ static uint8_t nand_read_byte(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return readb(chip->IO_ADDR_R);
+ }
+
+@@ -163,7 +205,7 @@ static uint8_t nand_read_byte(struct mtd
+ */
+ static uint8_t nand_read_byte16(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));
+ }
+
+@@ -175,7 +217,7 @@ static uint8_t nand_read_byte16(struct m
+ */
+ static u16 nand_read_word(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ return readw(chip->IO_ADDR_R);
+ }
+
+@@ -188,7 +230,7 @@ static u16 nand_read_word(struct mtd_inf
+ */
+ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ switch (chipnr) {
+ case -1:
+@@ -211,7 +253,7 @@ static void nand_select_chip(struct mtd_
+ */
+ static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ chip->write_buf(mtd, &byte, 1);
+ }
+@@ -225,7 +267,7 @@ static void nand_write_byte(struct mtd_i
+ */
+ static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint16_t word = byte;
+
+ /*
+@@ -257,7 +299,7 @@ static void nand_write_byte16(struct mtd
+ */
+ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ iowrite8_rep(chip->IO_ADDR_W, buf, len);
+ }
+@@ -272,7 +314,7 @@ static void nand_write_buf(struct mtd_in
+ */
+ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ ioread8_rep(chip->IO_ADDR_R, buf, len);
+ }
+@@ -287,7 +329,7 @@ static void nand_read_buf(struct mtd_inf
+ */
+ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 *p = (u16 *) buf;
+
+ iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
+@@ -303,7 +345,7 @@ static void nand_write_buf16(struct mtd_
+ */
+ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 *p = (u16 *) buf;
+
+ ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
+@@ -313,14 +355,13 @@ static void nand_read_buf16(struct mtd_i
+ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+- * @getchip: 0, if the chip is already selected
+ *
+ * Check, if the block is bad.
+ */
+-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
++static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
+ {
+- int page, chipnr, res = 0, i = 0;
+- struct nand_chip *chip = mtd->priv;
++ int page, res = 0, i = 0;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ u16 bad;
+
+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+@@ -328,15 +369,6 @@ static int nand_block_bad(struct mtd_inf
+
+ page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
+- if (getchip) {
+- chipnr = (int)(ofs >> chip->chip_shift);
+-
+- nand_get_device(mtd, FL_READING);
+-
+- /* Select the NAND device */
+- chip->select_chip(mtd, chipnr);
+- }
+-
+ do {
+ if (chip->options & NAND_BUSWIDTH_16) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB,
+@@ -361,11 +393,6 @@ static int nand_block_bad(struct mtd_inf
+ i++;
+ } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
+
+- if (getchip) {
+- chip->select_chip(mtd, -1);
+- nand_release_device(mtd);
+- }
+-
+ return res;
+ }
+
+@@ -380,7 +407,7 @@ static int nand_block_bad(struct mtd_inf
+ */
+ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_oob_ops ops;
+ uint8_t buf[2] = { 0, 0 };
+ int ret = 0, res, i = 0;
+@@ -430,7 +457,7 @@ static int nand_default_block_markbad(st
+ */
+ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int res, ret = 0;
+
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+@@ -471,7 +498,7 @@ static int nand_block_markbad_lowlevel(s
+ */
+ static int nand_check_wp(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Broken xD cards report WP despite being writable */
+ if (chip->options & NAND_BROKEN_XD)
+@@ -491,7 +518,7 @@ static int nand_check_wp(struct mtd_info
+ */
+ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (!chip->bbt)
+ return 0;
+@@ -503,19 +530,17 @@ static int nand_block_isreserved(struct
+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+- * @getchip: 0, if the chip is already selected
+ * @allowbbt: 1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad. Either by reading the bad block table or
+ * calling of the scan function.
+ */
+-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+- int allowbbt)
++static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (!chip->bbt)
+- return chip->block_bad(mtd, ofs, getchip);
++ return chip->block_bad(mtd, ofs);
+
+ /* Return info from the table */
+ return nand_isbad_bbt(mtd, ofs, allowbbt);
+@@ -531,7 +556,7 @@ static int nand_block_checkbad(struct mt
+ */
+ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int i;
+
+ /* Wait for the device to get ready */
+@@ -551,7 +576,7 @@ static void panic_nand_wait_ready(struct
+ */
+ void nand_wait_ready(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ unsigned long timeo = 400;
+
+ if (in_interrupt() || oops_in_progress)
+@@ -566,8 +591,8 @@ void nand_wait_ready(struct mtd_info *mt
+ cond_resched();
+ } while (time_before(jiffies, timeo));
+
+- pr_warn_ratelimited(
+- "timeout while waiting for chip to become ready\n");
++ if (!chip->dev_ready(mtd))
++ pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
+ out:
+ led_trigger_event(nand_led_trigger, LED_OFF);
+ }
+@@ -582,7 +607,7 @@ EXPORT_SYMBOL_GPL(nand_wait_ready);
+ */
+ static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+
+ timeo = jiffies + msecs_to_jiffies(timeo);
+ do {
+@@ -605,7 +630,7 @@ static void nand_wait_status_ready(struc
+ static void nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+ int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
+
+ /* Write out the command to the device */
+@@ -708,7 +733,7 @@ static void nand_command(struct mtd_info
+ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+ {
+- register struct nand_chip *chip = mtd->priv;
++ register struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+@@ -832,7 +857,7 @@ static void panic_nand_get_device(struct
+ static int
+ nand_get_device(struct mtd_info *mtd, int new_state)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ spinlock_t *lock = &chip->controller->lock;
+ wait_queue_head_t *wq = &chip->controller->wq;
+ DECLARE_WAITQUEUE(wait, current);
+@@ -952,7 +977,7 @@ static int __nand_unlock(struct mtd_info
+ {
+ int ret = 0;
+ int status, page;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ /* Submit address of first page to unlock */
+ page = ofs >> chip->page_shift;
+@@ -987,7 +1012,7 @@ int nand_unlock(struct mtd_info *mtd, lo
+ {
+ int ret = 0;
+ int chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+ __func__, (unsigned long long)ofs, len);
+@@ -1050,7 +1075,7 @@ int nand_lock(struct mtd_info *mtd, loff
+ {
+ int ret = 0;
+ int chipnr, status, page;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+ __func__, (unsigned long long)ofs, len);
+@@ -1309,13 +1334,12 @@ static int nand_read_page_raw_syndrome(s
+ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ unsigned int max_bitflips = 0;
+
+ chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
+@@ -1323,8 +1347,10 @@ static int nand_read_page_swecc(struct m
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+@@ -1356,14 +1382,14 @@ static int nand_read_subpage(struct mtd_
+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
+ int page)
+ {
+- int start_step, end_step, num_steps;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
++ int start_step, end_step, num_steps, ret;
+ uint8_t *p;
+ int data_col_addr, i, gaps = 0;
+ int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
+ int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
+- int index;
++ int index, section = 0;
+ unsigned int max_bitflips = 0;
++ struct mtd_oob_region oobregion = { };
+
+ /* Column address within the page aligned to ECC size (256bytes) */
+ start_step = data_offs / chip->ecc.size;
+@@ -1391,12 +1417,13 @@ static int nand_read_subpage(struct mtd_
+ * The performance is faster if we position offsets according to
+ * ecc.pos. Let's make sure that there are no gaps in ECC positions.
+ */
+- for (i = 0; i < eccfrag_len - 1; i++) {
+- if (eccpos[i + index] + 1 != eccpos[i + index + 1]) {
+- gaps = 1;
+- break;
+- }
+- }
++ ret = mtd_ooblayout_find_eccregion(mtd, index, &section, &oobregion);
++ if (ret)
++ return ret;
++
++ if (oobregion.length < eccfrag_len)
++ gaps = 1;
++
+ if (gaps) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+@@ -1405,20 +1432,23 @@ static int nand_read_subpage(struct mtd_
+ * Send the command to read the particular ECC bytes take care
+ * about buswidth alignment in read_buf.
+ */
+- aligned_pos = eccpos[index] & ~(busw - 1);
++ aligned_pos = oobregion.offset & ~(busw - 1);
+ aligned_len = eccfrag_len;
+- if (eccpos[index] & (busw - 1))
++ if (oobregion.offset & (busw - 1))
+ aligned_len++;
+- if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
++ if ((oobregion.offset + (num_steps * chip->ecc.bytes)) &
++ (busw - 1))
+ aligned_len++;
+
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+- mtd->writesize + aligned_pos, -1);
++ mtd->writesize + aligned_pos, -1);
+ chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+ }
+
+- for (i = 0; i < eccfrag_len; i++)
+- chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, chip->buffers->ecccode,
++ chip->oob_poi, index, eccfrag_len);
++ if (ret)
++ return ret;
+
+ p = bufpoi + data_col_addr;
+ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
+@@ -1426,6 +1456,16 @@ static int nand_read_subpage(struct mtd_
+
+ stat = chip->ecc.correct(mtd, p,
+ &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++ &chip->buffers->ecccode[i],
++ chip->ecc.bytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1449,13 +1489,12 @@ static int nand_read_subpage(struct mtd_
+ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ unsigned int max_bitflips = 0;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+@@ -1465,8 +1504,10 @@ static int nand_read_page_hwecc(struct m
+ }
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+@@ -1475,6 +1516,15 @@ static int nand_read_page_hwecc(struct m
+ int stat;
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, eccsize,
++ &ecc_code[i], eccbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1502,12 +1552,11 @@ static int nand_read_page_hwecc(struct m
+ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ unsigned int max_bitflips = 0;
+
+@@ -1516,8 +1565,10 @@ static int nand_read_page_hwecc_oob_firs
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- ecc_code[i] = chip->oob_poi[eccpos[i]];
++ ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+@@ -1527,6 +1578,15 @@ static int nand_read_page_hwecc_oob_firs
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, eccsize,
++ &ecc_code[i], eccbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
+ if (stat < 0) {
+ mtd->ecc_stats.failed++;
+ } else {
+@@ -1554,6 +1614,7 @@ static int nand_read_page_syndrome(struc
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
++ int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+ unsigned int max_bitflips = 0;
+@@ -1573,19 +1634,29 @@ static int nand_read_page_syndrome(struc
+ chip->read_buf(mtd, oob, eccbytes);
+ stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+- if (stat < 0) {
+- mtd->ecc_stats.failed++;
+- } else {
+- mtd->ecc_stats.corrected += stat;
+- max_bitflips = max_t(unsigned int, max_bitflips, stat);
+- }
+-
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->read_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
++
++ if (stat == -EBADMSG &&
++ (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
++ /* check for empty pages with bitflips */
++ stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
++ oob - eccpadbytes,
++ eccpadbytes,
++ NULL, 0,
++ chip->ecc.strength);
++ }
++
++ if (stat < 0) {
++ mtd->ecc_stats.failed++;
++ } else {
++ mtd->ecc_stats.corrected += stat;
++ max_bitflips = max_t(unsigned int, max_bitflips, stat);
++ }
+ }
+
+ /* Calculate remaining oob bytes */
+@@ -1598,14 +1669,17 @@ static int nand_read_page_syndrome(struc
+
+ /**
+ * nand_transfer_oob - [INTERN] Transfer oob to client buffer
+- * @chip: nand chip structure
++ * @mtd: mtd info structure
+ * @oob: oob destination address
+ * @ops: oob ops structure
+ * @len: size of oob to transfer
+ */
+-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
++static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
+ struct mtd_oob_ops *ops, size_t len)
+ {
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int ret;
++
+ switch (ops->mode) {
+
+ case MTD_OPS_PLACE_OOB:
+@@ -1613,31 +1687,12 @@ static uint8_t *nand_transfer_oob(struct
+ memcpy(oob, chip->oob_poi + ops->ooboffs, len);
+ return oob + len;
+
+- case MTD_OPS_AUTO_OOB: {
+- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+- uint32_t boffs = 0, roffs = ops->ooboffs;
+- size_t bytes = 0;
+-
+- for (; free->length && len; free++, len -= bytes) {
+- /* Read request not from offset 0? */
+- if (unlikely(roffs)) {
+- if (roffs >= free->length) {
+- roffs -= free->length;
+- continue;
+- }
+- boffs = free->offset + roffs;
+- bytes = min_t(size_t, len,
+- (free->length - roffs));
+- roffs = 0;
+- } else {
+- bytes = min_t(size_t, len, free->length);
+- boffs = free->offset;
+- }
+- memcpy(oob, chip->oob_poi + boffs, bytes);
+- oob += bytes;
+- }
+- return oob;
+- }
++ case MTD_OPS_AUTO_OOB:
++ ret = mtd_ooblayout_get_databytes(mtd, oob, chip->oob_poi,
++ ops->ooboffs, len);
++ BUG_ON(ret);
++ return oob + len;
++
+ default:
+ BUG();
+ }
+@@ -1655,7 +1710,7 @@ static uint8_t *nand_transfer_oob(struct
+ */
+ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("setting READ RETRY mode %d\n", retry_mode);
+
+@@ -1680,12 +1735,11 @@ static int nand_do_read_ops(struct mtd_i
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, page, realpage, col, bytes, aligned, oob_required;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ int ret = 0;
+ uint32_t readlen = ops->len;
+ uint32_t oobreadlen = ops->ooblen;
+- uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
+- mtd->oobavail : mtd->oobsize;
++ uint32_t max_oobsize = mtd_oobavail(mtd, ops);
+
+ uint8_t *bufpoi, *oob, *buf;
+ int use_bufpoi;
+@@ -1772,7 +1826,7 @@ read_retry:
+ int toread = min(oobreadlen, max_oobsize);
+
+ if (toread) {
+- oob = nand_transfer_oob(chip,
++ oob = nand_transfer_oob(mtd,
+ oob, ops, toread);
+ oobreadlen -= toread;
+ }
+@@ -2024,7 +2078,7 @@ static int nand_do_read_oob(struct mtd_i
+ struct mtd_oob_ops *ops)
+ {
+ int page, realpage, chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_ecc_stats stats;
+ int readlen = ops->ooblen;
+ int len;
+@@ -2036,10 +2090,7 @@ static int nand_do_read_oob(struct mtd_i
+
+ stats = mtd->ecc_stats;
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = chip->ecc.layout->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+
+ if (unlikely(ops->ooboffs >= len)) {
+ pr_debug("%s: attempt to start read outside oob\n",
+@@ -2073,7 +2124,7 @@ static int nand_do_read_oob(struct mtd_i
+ break;
+
+ len = min(len, readlen);
+- buf = nand_transfer_oob(chip, buf, ops, len);
++ buf = nand_transfer_oob(mtd, buf, ops, len);
+
+ if (chip->options & NAND_NEED_READRDY) {
+ /* Apply delay or wait for ready/busy pin */
+@@ -2232,19 +2283,20 @@ static int nand_write_page_swecc(struct
+ const uint8_t *buf, int oob_required,
+ int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ /* Software ECC calculation */
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ return chip->ecc.write_page_raw(mtd, chip, buf, 1, page);
+ }
+@@ -2261,12 +2313,11 @@ static int nand_write_page_hwecc(struct
+ const uint8_t *buf, int oob_required,
+ int page)
+ {
+- int i, eccsize = chip->ecc.size;
++ int i, eccsize = chip->ecc.size, ret;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+@@ -2274,8 +2325,10 @@ static int nand_write_page_hwecc(struct
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+@@ -2303,11 +2356,10 @@ static int nand_write_subpage_hwecc(stru
+ int ecc_size = chip->ecc.size;
+ int ecc_bytes = chip->ecc.bytes;
+ int ecc_steps = chip->ecc.steps;
+- uint32_t *eccpos = chip->ecc.layout->eccpos;
+ uint32_t start_step = offset / ecc_size;
+ uint32_t end_step = (offset + data_len - 1) / ecc_size;
+ int oob_bytes = mtd->oobsize / ecc_steps;
+- int step, i;
++ int step, ret;
+
+ for (step = 0; step < ecc_steps; step++) {
+ /* configure controller for WRITE access */
+@@ -2335,8 +2387,10 @@ static int nand_write_subpage_hwecc(stru
+ /* copy calculated ECC for whole page to chip->buffer->oob */
+ /* this include masked-value(0xFF) for unwritten subpages */
+ ecc_calc = chip->buffers->ecccalc;
+- for (i = 0; i < chip->ecc.total; i++)
+- chip->oob_poi[eccpos[i]] = ecc_calc[i];
++ ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0,
++ chip->ecc.total);
++ if (ret)
++ return ret;
+
+ /* write OOB buffer to NAND device */
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+@@ -2472,7 +2526,8 @@ static int nand_write_page(struct mtd_in
+ static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
+ struct mtd_oob_ops *ops)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int ret;
+
+ /*
+ * Initialise to all 0xFF, to avoid the possibility of left over OOB
+@@ -2487,31 +2542,12 @@ static uint8_t *nand_fill_oob(struct mtd
+ memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+ return oob + len;
+
+- case MTD_OPS_AUTO_OOB: {
+- struct nand_oobfree *free = chip->ecc.layout->oobfree;
+- uint32_t boffs = 0, woffs = ops->ooboffs;
+- size_t bytes = 0;
+-
+- for (; free->length && len; free++, len -= bytes) {
+- /* Write request not from offset 0? */
+- if (unlikely(woffs)) {
+- if (woffs >= free->length) {
+- woffs -= free->length;
+- continue;
+- }
+- boffs = free->offset + woffs;
+- bytes = min_t(size_t, len,
+- (free->length - woffs));
+- woffs = 0;
+- } else {
+- bytes = min_t(size_t, len, free->length);
+- boffs = free->offset;
+- }
+- memcpy(chip->oob_poi + boffs, oob, bytes);
+- oob += bytes;
+- }
+- return oob;
+- }
++ case MTD_OPS_AUTO_OOB:
++ ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi,
++ ops->ooboffs, len);
++ BUG_ON(ret);
++ return oob + len;
++
+ default:
+ BUG();
+ }
+@@ -2532,12 +2568,11 @@ static int nand_do_write_ops(struct mtd_
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, realpage, page, blockmask, column;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint32_t writelen = ops->len;
+
+ uint32_t oobwritelen = ops->ooblen;
+- uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
+- mtd->oobavail : mtd->oobsize;
++ uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
+
+ uint8_t *oob = ops->oobbuf;
+ uint8_t *buf = ops->datbuf;
+@@ -2662,7 +2697,7 @@ err_out:
+ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const uint8_t *buf)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct mtd_oob_ops ops;
+ int ret;
+
+@@ -2722,15 +2757,12 @@ static int nand_do_write_oob(struct mtd_
+ struct mtd_oob_ops *ops)
+ {
+ int chipnr, page, status, len;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ pr_debug("%s: to = 0x%08x, len = %i\n",
+ __func__, (unsigned int)to, (int)ops->ooblen);
+
+- if (ops->mode == MTD_OPS_AUTO_OOB)
+- len = chip->ecc.layout->oobavail;
+- else
+- len = mtd->oobsize;
++ len = mtd_oobavail(mtd, ops);
+
+ /* Do not allow write past end of page */
+ if ((ops->ooboffs + ops->ooblen) > len) {
+@@ -2847,7 +2879,7 @@ out:
+ */
+ static int single_erase(struct mtd_info *mtd, int page)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ /* Send commands to erase a block */
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+@@ -2879,7 +2911,7 @@ int nand_erase_nand(struct mtd_info *mtd
+ int allowbbt)
+ {
+ int page, status, pages_per_block, ret, chipnr;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ loff_t len;
+
+ pr_debug("%s: start = 0x%012llx, len = %llu\n",
+@@ -2918,7 +2950,7 @@ int nand_erase_nand(struct mtd_info *mtd
+ while (len) {
+ /* Check if we have a bad block, we do not erase bad blocks! */
+ if (nand_block_checkbad(mtd, ((loff_t) page) <<
+- chip->page_shift, 0, allowbbt)) {
++ chip->page_shift, allowbbt)) {
+ pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
+ __func__, page);
+ instr->state = MTD_ERASE_FAILED;
+@@ -3005,7 +3037,20 @@ static void nand_sync(struct mtd_info *m
+ */
+ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+ {
+- return nand_block_checkbad(mtd, offs, 1, 0);
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ int chipnr = (int)(offs >> chip->chip_shift);
++ int ret;
++
++ /* Select the NAND device */
++ nand_get_device(mtd, FL_READING);
++ chip->select_chip(mtd, chipnr);
++
++ ret = nand_block_checkbad(mtd, offs, 0);
++
++ chip->select_chip(mtd, -1);
++ nand_release_device(mtd);
++
++ return ret;
+ }
+
+ /**
+@@ -3094,7 +3139,7 @@ static int nand_suspend(struct mtd_info
+ */
+ static void nand_resume(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (chip->state == FL_PM_SUSPENDED)
+ nand_release_device(mtd);
+@@ -3266,7 +3311,7 @@ ext_out:
+
+ static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+
+ return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
+@@ -3937,10 +3982,13 @@ ident_done:
+ return type;
+ }
+
+-static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
+- struct device_node *dn)
++static int nand_dt_init(struct nand_chip *chip)
+ {
+- int ecc_mode, ecc_strength, ecc_step;
++ struct device_node *dn = nand_get_flash_node(chip);
++ int ecc_mode, ecc_algo, ecc_strength, ecc_step;
++
++ if (!dn)
++ return 0;
+
+ if (of_get_nand_bus_width(dn) == 16)
+ chip->options |= NAND_BUSWIDTH_16;
+@@ -3949,6 +3997,7 @@ static int nand_dt_init(struct mtd_info
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+ ecc_mode = of_get_nand_ecc_mode(dn);
++ ecc_algo = of_get_nand_ecc_algo(dn);
+ ecc_strength = of_get_nand_ecc_strength(dn);
+ ecc_step = of_get_nand_ecc_step_size(dn);
+
+@@ -3961,6 +4010,9 @@ static int nand_dt_init(struct mtd_info
+ if (ecc_mode >= 0)
+ chip->ecc.mode = ecc_mode;
+
++ if (ecc_algo >= 0)
++ chip->ecc.algo = ecc_algo;
++
+ if (ecc_strength >= 0)
+ chip->ecc.strength = ecc_strength;
+
+@@ -3984,15 +4036,16 @@ int nand_scan_ident(struct mtd_info *mtd
+ struct nand_flash_dev *table)
+ {
+ int i, nand_maf_id, nand_dev_id;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_flash_dev *type;
+ int ret;
+
+- if (chip->flash_node) {
+- ret = nand_dt_init(mtd, chip, chip->flash_node);
+- if (ret)
+- return ret;
+- }
++ ret = nand_dt_init(chip);
++ if (ret)
++ return ret;
++
++ if (!mtd->name && mtd->dev.parent)
++ mtd->name = dev_name(mtd->dev.parent);
+
+ if (!mtd->name && mtd->dev.parent)
+ mtd->name = dev_name(mtd->dev.parent);
+@@ -4055,7 +4108,7 @@ EXPORT_SYMBOL(nand_scan_ident);
+ */
+ static bool nand_ecc_strength_good(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ int corr, ds_corr;
+
+@@ -4083,10 +4136,10 @@ static bool nand_ecc_strength_good(struc
+ */
+ int nand_scan_tail(struct mtd_info *mtd)
+ {
+- int i;
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_buffers *nbuf;
++ int ret;
+
+ /* New bad blocks should be marked in OOB, flash-based BBT, or both */
+ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+@@ -4113,19 +4166,15 @@ int nand_scan_tail(struct mtd_info *mtd)
+ /*
+ * If no default placement scheme is given, select an appropriate one.
+ */
+- if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
++ if (!mtd->ooblayout && (ecc->mode != NAND_ECC_SOFT_BCH)) {
+ switch (mtd->oobsize) {
+ case 8:
+- ecc->layout = &nand_oob_8;
+- break;
+ case 16:
+- ecc->layout = &nand_oob_16;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+ break;
+ case 64:
+- ecc->layout = &nand_oob_64;
+- break;
+ case 128:
+- ecc->layout = &nand_oob_128;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ break;
+ default:
+ pr_warn("No oob scheme defined for oobsize %d\n",
+@@ -4168,7 +4217,7 @@ int nand_scan_tail(struct mtd_info *mtd)
+ ecc->write_oob = nand_write_oob_std;
+ if (!ecc->read_subpage)
+ ecc->read_subpage = nand_read_subpage;
+- if (!ecc->write_subpage)
++ if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
+ ecc->write_subpage = nand_write_subpage_hwecc;
+
+ case NAND_ECC_HW_SYNDROME:
+@@ -4246,10 +4295,8 @@ int nand_scan_tail(struct mtd_info *mtd)
+ }
+
+ /* See nand_bch_init() for details. */
+- ecc->bytes = DIV_ROUND_UP(
+- ecc->strength * fls(8 * ecc->size), 8);
+- ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
+- &ecc->layout);
++ ecc->bytes = 0;
++ ecc->priv = nand_bch_init(mtd);
+ if (!ecc->priv) {
+ pr_warn("BCH ECC initialization failed!\n");
+ BUG();
+@@ -4280,20 +4327,9 @@ int nand_scan_tail(struct mtd_info *mtd)
+ if (!ecc->write_oob_raw)
+ ecc->write_oob_raw = ecc->write_oob;
+
+- /*
+- * The number of bytes available for a client to place data into
+- * the out of band area.
+- */
+- ecc->layout->oobavail = 0;
+- for (i = 0; ecc->layout->oobfree[i].length
+- && i < ARRAY_SIZE(ecc->layout->oobfree); i++)
+- ecc->layout->oobavail += ecc->layout->oobfree[i].length;
+- mtd->oobavail = ecc->layout->oobavail;
+-
+- /* ECC sanity check: warn if it's too weak */
+- if (!nand_ecc_strength_good(mtd))
+- pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+- mtd->name);
++ /* propagate ecc info to mtd_info */
++ mtd->ecc_strength = ecc->strength;
++ mtd->ecc_step_size = ecc->size;
+
+ /*
+ * Set the number of read / write steps for one page depending on ECC
+@@ -4306,6 +4342,21 @@ int nand_scan_tail(struct mtd_info *mtd)
+ }
+ ecc->total = ecc->steps * ecc->bytes;
+
++ /*
++ * The number of bytes available for a client to place data into
++ * the out of band area.
++ */
++ ret = mtd_ooblayout_count_freebytes(mtd);
++ if (ret < 0)
++ ret = 0;
++
++ mtd->oobavail = ret;
++
++ /* ECC sanity check: warn if it's too weak */
++ if (!nand_ecc_strength_good(mtd))
++ pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
++ mtd->name);
++
+ /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
+ switch (ecc->steps) {
+@@ -4362,10 +4413,6 @@ int nand_scan_tail(struct mtd_info *mtd)
+ mtd->_block_markbad = nand_block_markbad;
+ mtd->writebufsize = mtd->writesize;
+
+- /* propagate ecc info to mtd_info */
+- mtd->ecclayout = ecc->layout;
+- mtd->ecc_strength = ecc->strength;
+- mtd->ecc_step_size = ecc->size;
+ /*
+ * Initialize bitflip_threshold to its default prior scan_bbt() call.
+ * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+@@ -4421,7 +4468,7 @@ EXPORT_SYMBOL(nand_scan);
+ */
+ void nand_release(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
+ nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
+--- a/drivers/mtd/nand/nand_bbt.c
++++ b/drivers/mtd/nand/nand_bbt.c
+@@ -172,7 +172,7 @@ static int read_bbt(struct mtd_info *mtd
+ struct nand_bbt_descr *td, int offs)
+ {
+ int res, ret = 0, i, j, act = 0;
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ size_t retlen, len, totlen;
+ loff_t from;
+ int bits = td->options & NAND_BBT_NRBITS_MSK;
+@@ -263,7 +263,7 @@ static int read_bbt(struct mtd_info *mtd
+ */
+ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int res = 0, i;
+
+ if (td->options & NAND_BBT_PERCHIP) {
+@@ -388,7 +388,7 @@ static u32 bbt_get_ver_offs(struct mtd_i
+ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+
+ /* Read the primary version, if available */
+ if (td->options & NAND_BBT_VERSION) {
+@@ -454,7 +454,7 @@ static int scan_block_fast(struct mtd_in
+ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *bd, int chip)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, numblocks, numpages;
+ int startblock;
+ loff_t from;
+@@ -523,7 +523,7 @@ static int create_bbt(struct mtd_info *m
+ */
+ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, chips;
+ int startblock, block, dir;
+ int scanlen = mtd->writesize + mtd->oobsize;
+@@ -618,7 +618,7 @@ static int write_bbt(struct mtd_info *mt
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md,
+ int chipsel)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ struct erase_info einfo;
+ int i, res, chip = 0;
+ int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
+@@ -819,7 +819,7 @@ static int write_bbt(struct mtd_info *mt
+ */
+ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+
+ return create_bbt(mtd, this->buffers->databuf, bd, -1);
+ }
+@@ -838,7 +838,7 @@ static inline int nand_memory_bbt(struct
+ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
+ {
+ int i, chips, writeops, create, chipsel, res, res2;
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ struct nand_bbt_descr *td = this->bbt_td;
+ struct nand_bbt_descr *md = this->bbt_md;
+ struct nand_bbt_descr *rd, *rd2;
+@@ -962,7 +962,7 @@ static int check_create(struct mtd_info
+ */
+ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int i, j, chips, block, nrblocks, update;
+ uint8_t oldval;
+
+@@ -1022,7 +1022,7 @@ static void mark_bbt_region(struct mtd_i
+ */
+ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ u32 pattern_len;
+ u32 bits;
+ u32 table_size;
+@@ -1074,7 +1074,7 @@ static void verify_bbt_descr(struct mtd_
+ */
+ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int len, res;
+ uint8_t *buf;
+ struct nand_bbt_descr *td = this->bbt_td;
+@@ -1147,7 +1147,7 @@ err:
+ */
+ static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int len, res = 0;
+ int chip, chipsel;
+ uint8_t *buf;
+@@ -1281,7 +1281,7 @@ static int nand_create_badblock_pattern(
+ */
+ int nand_default_bbt(struct mtd_info *mtd)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int ret;
+
+ /* Is a flash based bad block table requested? */
+@@ -1317,7 +1317,7 @@ int nand_default_bbt(struct mtd_info *mt
+ */
+ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1332,7 +1332,7 @@ int nand_isreserved_bbt(struct mtd_info
+ */
+ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block, res;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1359,7 +1359,7 @@ int nand_isbad_bbt(struct mtd_info *mtd,
+ */
+ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+ {
+- struct nand_chip *this = mtd->priv;
++ struct nand_chip *this = mtd_to_nand(mtd);
+ int block, ret = 0;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mt
+
+ return ret;
+ }
+-
+-EXPORT_SYMBOL(nand_scan_bbt);
+--- a/drivers/mtd/nand/nand_bch.c
++++ b/drivers/mtd/nand/nand_bch.c
+@@ -32,13 +32,11 @@
+ /**
+ * struct nand_bch_control - private NAND BCH control structure
+ * @bch: BCH control structure
+- * @ecclayout: private ecc layout for this BCH configuration
+ * @errloc: error location array
+ * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
+ */
+ struct nand_bch_control {
+ struct bch_control *bch;
+- struct nand_ecclayout ecclayout;
+ unsigned int *errloc;
+ unsigned char *eccmask;
+ };
+@@ -52,7 +50,7 @@ struct nand_bch_control {
+ int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
+ unsigned char *code)
+ {
+- const struct nand_chip *chip = mtd->priv;
++ const struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int i;
+
+@@ -79,7 +77,7 @@ EXPORT_SYMBOL(nand_bch_calculate_ecc);
+ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+- const struct nand_chip *chip = mtd->priv;
++ const struct nand_chip *chip = mtd_to_nand(mtd);
+ struct nand_bch_control *nbc = chip->ecc.priv;
+ unsigned int *errloc = nbc->errloc;
+ int i, count;
+@@ -98,7 +96,7 @@ int nand_bch_correct_data(struct mtd_inf
+ }
+ } else if (count < 0) {
+ printk(KERN_ERR "ecc unrecoverable error\n");
+- count = -1;
++ count = -EBADMSG;
+ }
+ return count;
+ }
+@@ -107,9 +105,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
+ /**
+ * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
+ * @mtd: MTD block structure
+- * @eccsize: ecc block size in bytes
+- * @eccbytes: ecc length in bytes
+- * @ecclayout: output default layout
+ *
+ * Returns:
+ * a pointer to a new NAND BCH control structure, or NULL upon failure
+@@ -123,14 +118,20 @@ EXPORT_SYMBOL(nand_bch_correct_data);
+ * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
+ * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
+ */
+-struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
+- struct nand_ecclayout **ecclayout)
++struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+ {
++ struct nand_chip *nand = mtd_to_nand(mtd);
+ unsigned int m, t, eccsteps, i;
+- struct nand_ecclayout *layout;
+ struct nand_bch_control *nbc = NULL;
+ unsigned char *erased_page;
++ unsigned int eccsize = nand->ecc.size;
++ unsigned int eccbytes = nand->ecc.bytes;
++ unsigned int eccstrength = nand->ecc.strength;
++
++ if (!eccbytes && eccstrength) {
++ eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
++ nand->ecc.bytes = eccbytes;
++ }
+
+ if (!eccsize || !eccbytes) {
+ printk(KERN_WARNING "ecc parameters not supplied\n");
+@@ -158,7 +159,7 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ eccsteps = mtd->writesize/eccsize;
+
+ /* if no ecc placement scheme was provided, build one */
+- if (!*ecclayout) {
++ if (!mtd->ooblayout) {
+
+ /* handle large page devices only */
+ if (mtd->oobsize < 64) {
+@@ -167,24 +168,7 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ goto fail;
+ }
+
+- layout = &nbc->ecclayout;
+- layout->eccbytes = eccsteps*eccbytes;
+-
+- /* reserve 2 bytes for bad block marker */
+- if (layout->eccbytes+2 > mtd->oobsize) {
+- printk(KERN_WARNING "no suitable oob scheme available "
+- "for oobsize %d eccbytes %u\n", mtd->oobsize,
+- eccbytes);
+- goto fail;
+- }
+- /* put ecc bytes at oob tail */
+- for (i = 0; i < layout->eccbytes; i++)
+- layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
+-
+- layout->oobfree[0].offset = 2;
+- layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
+-
+- *ecclayout = layout;
++ mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+ }
+
+ /* sanity checks */
+@@ -192,7 +176,8 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
+ goto fail;
+ }
+- if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
++
++ if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
+ printk(KERN_WARNING "invalid ecc layout\n");
+ goto fail;
+ }
+@@ -216,6 +201,9 @@ nand_bch_init(struct mtd_info *mtd, unsi
+ for (i = 0; i < eccbytes; i++)
+ nbc->eccmask[i] ^= 0xff;
+
++ if (!eccstrength)
++ nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
++
+ return nbc;
+ fail:
+ nand_bch_free(nbc);
+--- a/drivers/mtd/nand/nand_ecc.c
++++ b/drivers/mtd/nand/nand_ecc.c
+@@ -424,7 +424,7 @@ int nand_calculate_ecc(struct mtd_info *
+ unsigned char *code)
+ {
+ __nand_calculate_ecc(buf,
+- ((struct nand_chip *)mtd->priv)->ecc.size, code);
++ mtd_to_nand(mtd)->ecc.size, code);
+
+ return 0;
+ }
+@@ -524,7 +524,7 @@ int nand_correct_data(struct mtd_info *m
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+ return __nand_correct_data(buf, read_ecc, calc_ecc,
+- ((struct nand_chip *)mtd->priv)->ecc.size);
++ mtd_to_nand(mtd)->ecc.size);
+ }
+ EXPORT_SYMBOL(nand_correct_data);
+
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] =
+ SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
+ {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
+ { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
+- SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
+- 4 },
++ SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
++ NAND_ECC_INFO(40, SZ_1K), 4 },
+
+ LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
+ LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
+--- a/drivers/mtd/nand/nandsim.c
++++ b/drivers/mtd/nand/nandsim.c
+@@ -666,8 +666,8 @@ static char *get_partition_name(int i)
+ */
+ static int init_nandsim(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = mtd->priv;
+- struct nandsim *ns = chip->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ int i, ret = 0;
+ uint64_t remains;
+ uint64_t next_offset;
+@@ -1908,7 +1908,8 @@ static void switch_state(struct nandsim
+
+ static u_char ns_nand_read_byte(struct mtd_info *mtd)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ u_char outb = 0x00;
+
+ /* Sanity and correctness checks */
+@@ -1969,7 +1970,8 @@ static u_char ns_nand_read_byte(struct m
+
+ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Sanity and correctness checks */
+ if (!ns->lines.ce) {
+@@ -2123,7 +2125,8 @@ static void ns_nand_write_byte(struct mt
+
+ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
+ ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
+@@ -2141,7 +2144,7 @@ static int ns_device_ready(struct mtd_in
+
+ static uint16_t ns_nand_read_word(struct mtd_info *mtd)
+ {
+- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
+
+ NS_DBG("read_word\n");
+
+@@ -2150,7 +2153,8 @@ static uint16_t ns_nand_read_word(struct
+
+ static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Check that chip is expecting data input */
+ if (!(ns->state & STATE_DATAIN_MASK)) {
+@@ -2177,7 +2181,8 @@ static void ns_nand_write_buf(struct mtd
+
+ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+ {
+- struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+
+ /* Sanity and correctness checks */
+ if (!ns->lines.ce) {
+@@ -2198,7 +2203,7 @@ static void ns_nand_read_buf(struct mtd_
+ int i;
+
+ for (i = 0; i < len; i++)
+- buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd);
++ buf[i] = mtd_to_nand(mtd)->read_byte(mtd);
+
+ return;
+ }
+@@ -2236,16 +2241,15 @@ static int __init ns_init_module(void)
+ }
+
+ /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
+- nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
+- + sizeof(struct nandsim), GFP_KERNEL);
+- if (!nsmtd) {
++ chip = kzalloc(sizeof(struct nand_chip) + sizeof(struct nandsim),
++ GFP_KERNEL);
++ if (!chip) {
+ NS_ERR("unable to allocate core structures.\n");
+ return -ENOMEM;
+ }
+- chip = (struct nand_chip *)(nsmtd + 1);
+- nsmtd->priv = (void *)chip;
++ nsmtd = nand_to_mtd(chip);
+ nand = (struct nandsim *)(chip + 1);
+- chip->priv = (void *)nand;
++ nand_set_controller_data(chip, (void *)nand);
+
+ /*
+ * Register simulator's callbacks.
+@@ -2257,6 +2261,7 @@ static int __init ns_init_module(void)
+ chip->read_buf = ns_nand_read_buf;
+ chip->read_word = ns_nand_read_word;
+ chip->ecc.mode = NAND_ECC_SOFT;
++ chip->ecc.algo = NAND_ECC_HAMMING;
+ /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
+ /* and 'badblocks' parameters to work */
+ chip->options |= NAND_SKIP_BBTSCAN;
+@@ -2335,6 +2340,7 @@ static int __init ns_init_module(void)
+ goto error;
+ }
+ chip->ecc.mode = NAND_ECC_SOFT_BCH;
++ chip->ecc.algo = NAND_ECC_BCH;
+ chip->ecc.size = 512;
+ chip->ecc.strength = bch;
+ chip->ecc.bytes = eccbytes;
+@@ -2392,7 +2398,7 @@ err_exit:
+ for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i)
+ kfree(nand->partitions[i].name);
+ error:
+- kfree(nsmtd);
++ kfree(chip);
+ free_lists();
+
+ return retval;
+@@ -2405,7 +2411,8 @@ module_init(ns_init_module);
+ */
+ static void __exit ns_cleanup_module(void)
+ {
+- struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
++ struct nand_chip *chip = mtd_to_nand(nsmtd);
++ struct nandsim *ns = nand_get_controller_data(chip);
+ int i;
+
+ nandsim_debugfs_remove(ns);
+@@ -2413,7 +2420,7 @@ static void __exit ns_cleanup_module(voi
+ nand_release(nsmtd); /* Unregister driver */
+ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
+ kfree(ns->partitions[i].name);
+- kfree(nsmtd); /* Free other structures */
++ kfree(mtd_to_nand(nsmtd)); /* Free other structures */
+ free_lists();
+ }
+
+--- a/drivers/mtd/ofpart.c
++++ b/drivers/mtd/ofpart.c
+@@ -26,9 +26,10 @@ static bool node_has_compatible(struct d
+ }
+
+ static int parse_ofpart_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
++ struct mtd_partition *parts;
+ struct device_node *mtd_node;
+ struct device_node *ofpart_node;
+ const char *partname;
+@@ -37,10 +38,8 @@ static int parse_ofpart_partitions(struc
+ bool dedicated = true;
+
+
+- if (!data)
+- return 0;
+-
+- mtd_node = data->of_node;
++ /* Pull of_node from the master device node */
++ mtd_node = mtd_get_of_node(master);
+ if (!mtd_node)
+ return 0;
+
+@@ -72,8 +71,8 @@ static int parse_ofpart_partitions(struc
+ if (nr_parts == 0)
+ return 0;
+
+- *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+- if (!*pparts)
++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
++ if (!parts)
+ return -ENOMEM;
+
+ i = 0;
+@@ -107,19 +106,19 @@ static int parse_ofpart_partitions(struc
+ goto ofpart_fail;
+ }
+
+- (*pparts)[i].offset = of_read_number(reg, a_cells);
+- (*pparts)[i].size = of_read_number(reg + a_cells, s_cells);
++ parts[i].offset = of_read_number(reg, a_cells);
++ parts[i].size = of_read_number(reg + a_cells, s_cells);
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+- (*pparts)[i].name = partname;
++ parts[i].name = partname;
+
+ if (of_get_property(pp, "read-only", &len))
+- (*pparts)[i].mask_flags |= MTD_WRITEABLE;
++ parts[i].mask_flags |= MTD_WRITEABLE;
+
+ if (of_get_property(pp, "lock", &len))
+- (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
++ parts[i].mask_flags |= MTD_POWERUP_LOCK;
+
+ i++;
+ }
+@@ -127,6 +126,7 @@ static int parse_ofpart_partitions(struc
+ if (!nr_parts)
+ goto ofpart_none;
+
++ *pparts = parts;
+ return nr_parts;
+
+ ofpart_fail:
+@@ -135,21 +135,20 @@ ofpart_fail:
+ ret = -EINVAL;
+ ofpart_none:
+ of_node_put(pp);
+- kfree(*pparts);
+- *pparts = NULL;
++ kfree(parts);
+ return ret;
+ }
+
+ static struct mtd_part_parser ofpart_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_ofpart_partitions,
+ .name = "ofpart",
+ };
+
+ static int parse_ofoldpart_partitions(struct mtd_info *master,
+- struct mtd_partition **pparts,
++ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+ {
++ struct mtd_partition *parts;
+ struct device_node *dp;
+ int i, plen, nr_parts;
+ const struct {
+@@ -157,10 +156,8 @@ static int parse_ofoldpart_partitions(st
+ } *part;
+ const char *names;
+
+- if (!data)
+- return 0;
+-
+- dp = data->of_node;
++ /* Pull of_node from the master device node */
++ dp = mtd_get_of_node(master);
+ if (!dp)
+ return 0;
+
+@@ -173,37 +170,37 @@ static int parse_ofoldpart_partitions(st
+
+ nr_parts = plen / sizeof(part[0]);
+
+- *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
+- if (!*pparts)
++ parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL);
++ if (!parts)
+ return -ENOMEM;
+
+ names = of_get_property(dp, "partition-names", &plen);
+
+ for (i = 0; i < nr_parts; i++) {
+- (*pparts)[i].offset = be32_to_cpu(part->offset);
+- (*pparts)[i].size = be32_to_cpu(part->len) & ~1;
++ parts[i].offset = be32_to_cpu(part->offset);
++ parts[i].size = be32_to_cpu(part->len) & ~1;
+ /* bit 0 set signifies read only partition */
+ if (be32_to_cpu(part->len) & 1)
+- (*pparts)[i].mask_flags = MTD_WRITEABLE;
++ parts[i].mask_flags = MTD_WRITEABLE;
+
+ if (names && (plen > 0)) {
+ int len = strlen(names) + 1;
+
+- (*pparts)[i].name = names;
++ parts[i].name = names;
+ plen -= len;
+ names += len;
+ } else {
+- (*pparts)[i].name = "unnamed";
++ parts[i].name = "unnamed";
+ }
+
+ part++;
+ }
+
++ *pparts = parts;
+ return nr_parts;
+ }
+
+ static struct mtd_part_parser ofoldpart_parser = {
+- .owner = THIS_MODULE,
+ .parse_fn = parse_ofoldpart_partitions,
+ .name = "ofoldpart",
+ };
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -7,6 +7,14 @@ menuconfig MTD_SPI_NOR
+
+ if MTD_SPI_NOR
+
++config MTD_MT81xx_NOR
++ tristate "Mediatek MT81xx SPI NOR flash controller"
++ depends on HAS_IOMEM
++ help
++ This enables access to SPI NOR flash, using MT81xx SPI NOR flash
++ controller. This controller does not support generic SPI BUS, it only
++ supports SPI NOR Flash.
++
+ config MTD_SPI_NOR_USE_4K_SECTORS
+ bool "Use small 4096 B erase sectors"
+ default y
+@@ -23,7 +31,7 @@ config MTD_SPI_NOR_USE_4K_SECTORS
+
+ config SPI_FSL_QUADSPI
+ tristate "Freescale Quad SPI controller"
+- depends on ARCH_MXC || COMPILE_TEST
++ depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This enables support for the Quad SPI controller in master mode.
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,3 +1,4 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
++obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+--- /dev/null
++++ b/drivers/mtd/spi-nor/mtk-quadspi.c
+@@ -0,0 +1,485 @@
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author: Bayi Cheng <bayi.cheng@mediatek.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/iopoll.h>
++#include <linux/ioport.h>
++#include <linux/math64.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/spi-nor.h>
++
++#define MTK_NOR_CMD_REG 0x00
++#define MTK_NOR_CNT_REG 0x04
++#define MTK_NOR_RDSR_REG 0x08
++#define MTK_NOR_RDATA_REG 0x0c
++#define MTK_NOR_RADR0_REG 0x10
++#define MTK_NOR_RADR1_REG 0x14
++#define MTK_NOR_RADR2_REG 0x18
++#define MTK_NOR_WDATA_REG 0x1c
++#define MTK_NOR_PRGDATA0_REG 0x20
++#define MTK_NOR_PRGDATA1_REG 0x24
++#define MTK_NOR_PRGDATA2_REG 0x28
++#define MTK_NOR_PRGDATA3_REG 0x2c
++#define MTK_NOR_PRGDATA4_REG 0x30
++#define MTK_NOR_PRGDATA5_REG 0x34
++#define MTK_NOR_SHREG0_REG 0x38
++#define MTK_NOR_SHREG1_REG 0x3c
++#define MTK_NOR_SHREG2_REG 0x40
++#define MTK_NOR_SHREG3_REG 0x44
++#define MTK_NOR_SHREG4_REG 0x48
++#define MTK_NOR_SHREG5_REG 0x4c
++#define MTK_NOR_SHREG6_REG 0x50
++#define MTK_NOR_SHREG7_REG 0x54
++#define MTK_NOR_SHREG8_REG 0x58
++#define MTK_NOR_SHREG9_REG 0x5c
++#define MTK_NOR_CFG1_REG 0x60
++#define MTK_NOR_CFG2_REG 0x64
++#define MTK_NOR_CFG3_REG 0x68
++#define MTK_NOR_STATUS0_REG 0x70
++#define MTK_NOR_STATUS1_REG 0x74
++#define MTK_NOR_STATUS2_REG 0x78
++#define MTK_NOR_STATUS3_REG 0x7c
++#define MTK_NOR_FLHCFG_REG 0x84
++#define MTK_NOR_TIME_REG 0x94
++#define MTK_NOR_PP_DATA_REG 0x98
++#define MTK_NOR_PREBUF_STUS_REG 0x9c
++#define MTK_NOR_DELSEL0_REG 0xa0
++#define MTK_NOR_DELSEL1_REG 0xa4
++#define MTK_NOR_INTRSTUS_REG 0xa8
++#define MTK_NOR_INTREN_REG 0xac
++#define MTK_NOR_CHKSUM_CTL_REG 0xb8
++#define MTK_NOR_CHKSUM_REG 0xbc
++#define MTK_NOR_CMD2_REG 0xc0
++#define MTK_NOR_WRPROT_REG 0xc4
++#define MTK_NOR_RADR3_REG 0xc8
++#define MTK_NOR_DUAL_REG 0xcc
++#define MTK_NOR_DELSEL2_REG 0xd0
++#define MTK_NOR_DELSEL3_REG 0xd4
++#define MTK_NOR_DELSEL4_REG 0xd8
++
++/* commands for mtk nor controller */
++#define MTK_NOR_READ_CMD 0x0
++#define MTK_NOR_RDSR_CMD 0x2
++#define MTK_NOR_PRG_CMD 0x4
++#define MTK_NOR_WR_CMD 0x10
++#define MTK_NOR_PIO_WR_CMD 0x90
++#define MTK_NOR_WRSR_CMD 0x20
++#define MTK_NOR_PIO_READ_CMD 0x81
++#define MTK_NOR_WR_BUF_ENABLE 0x1
++#define MTK_NOR_WR_BUF_DISABLE 0x0
++#define MTK_NOR_ENABLE_SF_CMD 0x30
++#define MTK_NOR_DUAD_ADDR_EN 0x8
++#define MTK_NOR_QUAD_READ_EN 0x4
++#define MTK_NOR_DUAL_ADDR_EN 0x2
++#define MTK_NOR_DUAL_READ_EN 0x1
++#define MTK_NOR_DUAL_DISABLE 0x0
++#define MTK_NOR_FAST_READ 0x1
++
++#define SFLASH_WRBUF_SIZE 128
++
++/* Can shift up to 48 bits (6 bytes) of TX/RX */
++#define MTK_NOR_MAX_RX_TX_SHIFT 6
++/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */
++#define MTK_NOR_MAX_SHIFT 7
++
++/* Helpers for accessing the program data / shift data registers */
++#define MTK_NOR_PRG_REG(n) (MTK_NOR_PRGDATA0_REG + 4 * (n))
++#define MTK_NOR_SHREG(n) (MTK_NOR_SHREG0_REG + 4 * (n))
++
++struct mt8173_nor {
++ struct spi_nor nor;
++ struct device *dev;
++ void __iomem *base; /* nor flash base address */
++ struct clk *spi_clk;
++ struct clk *nor_clk;
++};
++
++static void mt8173_nor_set_read_mode(struct mt8173_nor *mt8173_nor)
++{
++ struct spi_nor *nor = &mt8173_nor->nor;
++
++ switch (nor->flash_read) {
++ case SPI_NOR_FAST:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA3_REG);
++ writeb(MTK_NOR_FAST_READ, mt8173_nor->base +
++ MTK_NOR_CFG1_REG);
++ break;
++ case SPI_NOR_DUAL:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA3_REG);
++ writeb(MTK_NOR_DUAL_READ_EN, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ case SPI_NOR_QUAD:
++ writeb(nor->read_opcode, mt8173_nor->base +
++ MTK_NOR_PRGDATA4_REG);
++ writeb(MTK_NOR_QUAD_READ_EN, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ default:
++ writeb(MTK_NOR_DUAL_DISABLE, mt8173_nor->base +
++ MTK_NOR_DUAL_REG);
++ break;
++ }
++}
++
++static int mt8173_nor_execute_cmd(struct mt8173_nor *mt8173_nor, u8 cmdval)
++{
++ int reg;
++ u8 val = cmdval & 0x1f;
++
++ writeb(cmdval, mt8173_nor->base + MTK_NOR_CMD_REG);
++ return readl_poll_timeout(mt8173_nor->base + MTK_NOR_CMD_REG, reg,
++ !(reg & val), 100, 10000);
++}
++
++static int mt8173_nor_do_tx_rx(struct mt8173_nor *mt8173_nor, u8 op,
++ u8 *tx, int txlen, u8 *rx, int rxlen)
++{
++ int len = 1 + txlen + rxlen;
++ int i, ret, idx;
++
++ if (len > MTK_NOR_MAX_SHIFT)
++ return -EINVAL;
++
++ writeb(len * 8, mt8173_nor->base + MTK_NOR_CNT_REG);
++
++ /* start at PRGDATA5, go down to PRGDATA0 */
++ idx = MTK_NOR_MAX_RX_TX_SHIFT - 1;
++
++ /* opcode */
++ writeb(op, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++ idx--;
++
++ /* program TX data */
++ for (i = 0; i < txlen; i++, idx--)
++ writeb(tx[i], mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++
++ /* clear out rest of TX registers */
++ while (idx >= 0) {
++ writeb(0, mt8173_nor->base + MTK_NOR_PRG_REG(idx));
++ idx--;
++ }
++
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PRG_CMD);
++ if (ret)
++ return ret;
++
++ /* restart at first RX byte */
++ idx = rxlen - 1;
++
++ /* read out RX data */
++ for (i = 0; i < rxlen; i++, idx--)
++ rx[i] = readb(mt8173_nor->base + MTK_NOR_SHREG(idx));
++
++ return 0;
++}
++
++/* Do a WRSR (Write Status Register) command */
++static int mt8173_nor_wr_sr(struct mt8173_nor *mt8173_nor, u8 sr)
++{
++ writeb(sr, mt8173_nor->base + MTK_NOR_PRGDATA5_REG);
++ writeb(8, mt8173_nor->base + MTK_NOR_CNT_REG);
++ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WRSR_CMD);
++}
++
++static int mt8173_nor_write_buffer_enable(struct mt8173_nor *mt8173_nor)
++{
++ u8 reg;
++
++ /* the bit0 of MTK_NOR_CFG2_REG is pre-fetch buffer
++ * 0: pre-fetch buffer use for read
++ * 1: pre-fetch buffer use for page program
++ */
++ writel(MTK_NOR_WR_BUF_ENABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
++ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
++ 0x01 == (reg & 0x01), 100, 10000);
++}
++
++static int mt8173_nor_write_buffer_disable(struct mt8173_nor *mt8173_nor)
++{
++ u8 reg;
++
++ writel(MTK_NOR_WR_BUF_DISABLE, mt8173_nor->base + MTK_NOR_CFG2_REG);
++ return readb_poll_timeout(mt8173_nor->base + MTK_NOR_CFG2_REG, reg,
++ MTK_NOR_WR_BUF_DISABLE == (reg & 0x1), 100,
++ 10000);
++}
++
++static void mt8173_nor_set_addr(struct mt8173_nor *mt8173_nor, u32 addr)
++{
++ int i;
++
++ for (i = 0; i < 3; i++) {
++ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR0_REG + i * 4);
++ addr >>= 8;
++ }
++ /* Last register is non-contiguous */
++ writeb(addr & 0xff, mt8173_nor->base + MTK_NOR_RADR3_REG);
++}
++
++static int mt8173_nor_read(struct spi_nor *nor, loff_t from, size_t length,
++ size_t *retlen, u_char *buffer)
++{
++ int i, ret;
++ int addr = (int)from;
++ u8 *buf = (u8 *)buffer;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ /* set mode for fast read mode ,dual mode or quad mode */
++ mt8173_nor_set_read_mode(mt8173_nor);
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ for (i = 0; i < length; i++, (*retlen)++) {
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_READ_CMD);
++ if (ret < 0)
++ return ret;
++ buf[i] = readb(mt8173_nor->base + MTK_NOR_RDATA_REG);
++ }
++ return 0;
++}
++
++static int mt8173_nor_write_single_byte(struct mt8173_nor *mt8173_nor,
++ int addr, int length, u8 *data)
++{
++ int i, ret;
++
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ for (i = 0; i < length; i++) {
++ writeb(*data++, mt8173_nor->base + MTK_NOR_WDATA_REG);
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_PIO_WR_CMD);
++ if (ret < 0)
++ return ret;
++ }
++ return 0;
++}
++
++static int mt8173_nor_write_buffer(struct mt8173_nor *mt8173_nor, int addr,
++ const u8 *buf)
++{
++ int i, bufidx, data;
++
++ mt8173_nor_set_addr(mt8173_nor, addr);
++
++ bufidx = 0;
++ for (i = 0; i < SFLASH_WRBUF_SIZE; i += 4) {
++ data = buf[bufidx + 3]<<24 | buf[bufidx + 2]<<16 |
++ buf[bufidx + 1]<<8 | buf[bufidx];
++ bufidx += 4;
++ writel(data, mt8173_nor->base + MTK_NOR_PP_DATA_REG);
++ }
++ return mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_WR_CMD);
++}
++
++static void mt8173_nor_write(struct spi_nor *nor, loff_t to, size_t len,
++ size_t *retlen, const u_char *buf)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ ret = mt8173_nor_write_buffer_enable(mt8173_nor);
++ if (ret < 0)
++ dev_warn(mt8173_nor->dev, "write buffer enable failed!\n");
++
++ while (len >= SFLASH_WRBUF_SIZE) {
++ ret = mt8173_nor_write_buffer(mt8173_nor, to, buf);
++ if (ret < 0)
++ dev_err(mt8173_nor->dev, "write buffer failed!\n");
++ len -= SFLASH_WRBUF_SIZE;
++ to += SFLASH_WRBUF_SIZE;
++ buf += SFLASH_WRBUF_SIZE;
++ (*retlen) += SFLASH_WRBUF_SIZE;
++ }
++ ret = mt8173_nor_write_buffer_disable(mt8173_nor);
++ if (ret < 0)
++ dev_warn(mt8173_nor->dev, "write buffer disable failed!\n");
++
++ if (len) {
++ ret = mt8173_nor_write_single_byte(mt8173_nor, to, (int)len,
++ (u8 *)buf);
++ if (ret < 0)
++ dev_err(mt8173_nor->dev, "write single byte failed!\n");
++ (*retlen) += len;
++ }
++}
++
++static int mt8173_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ switch (opcode) {
++ case SPINOR_OP_RDSR:
++ ret = mt8173_nor_execute_cmd(mt8173_nor, MTK_NOR_RDSR_CMD);
++ if (ret < 0)
++ return ret;
++ if (len == 1)
++ *buf = readb(mt8173_nor->base + MTK_NOR_RDSR_REG);
++ else
++ dev_err(mt8173_nor->dev, "len should be 1 for read status!\n");
++ break;
++ default:
++ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, NULL, 0, buf, len);
++ break;
++ }
++ return ret;
++}
++
++static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
++ int len)
++{
++ int ret;
++ struct mt8173_nor *mt8173_nor = nor->priv;
++
++ switch (opcode) {
++ case SPINOR_OP_WRSR:
++ /* We only handle 1 byte */
++ ret = mt8173_nor_wr_sr(mt8173_nor, *buf);
++ break;
++ default:
++ ret = mt8173_nor_do_tx_rx(mt8173_nor, opcode, buf, len, NULL, 0);
++ if (ret)
++ dev_warn(mt8173_nor->dev, "write reg failure!\n");
++ break;
++ }
++ return ret;
++}
++
++static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
++ struct device_node *flash_node)
++{
++ int ret;
++ struct spi_nor *nor;
++
++ /* initialize controller to accept commands */
++ writel(MTK_NOR_ENABLE_SF_CMD, mt8173_nor->base + MTK_NOR_WRPROT_REG);
++
++ nor = &mt8173_nor->nor;
++ nor->dev = mt8173_nor->dev;
++ nor->priv = mt8173_nor;
++ spi_nor_set_flash_node(nor, flash_node);
++
++ /* fill the hooks to spi nor */
++ nor->read = mt8173_nor_read;
++ nor->read_reg = mt8173_nor_read_reg;
++ nor->write = mt8173_nor_write;
++ nor->write_reg = mt8173_nor_write_reg;
++ nor->mtd.name = "mtk_nor";
++ /* initialized with NULL */
++ ret = spi_nor_scan(nor, NULL, SPI_NOR_DUAL);
++ if (ret)
++ return ret;
++
++ return mtd_device_register(&nor->mtd, NULL, 0);
++}
++
++static int mtk_nor_drv_probe(struct platform_device *pdev)
++{
++ struct device_node *flash_np;
++ struct resource *res;
++ int ret;
++ struct mt8173_nor *mt8173_nor;
++
++ if (!pdev->dev.of_node) {
++ dev_err(&pdev->dev, "No DT found\n");
++ return -EINVAL;
++ }
++
++ mt8173_nor = devm_kzalloc(&pdev->dev, sizeof(*mt8173_nor), GFP_KERNEL);
++ if (!mt8173_nor)
++ return -ENOMEM;
++ platform_set_drvdata(pdev, mt8173_nor);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ mt8173_nor->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(mt8173_nor->base))
++ return PTR_ERR(mt8173_nor->base);
++
++ mt8173_nor->spi_clk = devm_clk_get(&pdev->dev, "spi");
++ if (IS_ERR(mt8173_nor->spi_clk))
++ return PTR_ERR(mt8173_nor->spi_clk);
++
++ mt8173_nor->nor_clk = devm_clk_get(&pdev->dev, "sf");
++ if (IS_ERR(mt8173_nor->nor_clk))
++ return PTR_ERR(mt8173_nor->nor_clk);
++
++ mt8173_nor->dev = &pdev->dev;
++ ret = clk_prepare_enable(mt8173_nor->spi_clk);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(mt8173_nor->nor_clk);
++ if (ret) {
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ return ret;
++ }
++ /* only support one attached flash */
++ flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
++ if (!flash_np) {
++ dev_err(&pdev->dev, "no SPI flash device to configure\n");
++ ret = -ENODEV;
++ goto nor_free;
++ }
++ ret = mtk_nor_init(mt8173_nor, flash_np);
++
++nor_free:
++ if (ret) {
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ clk_disable_unprepare(mt8173_nor->nor_clk);
++ }
++ return ret;
++}
++
++static int mtk_nor_drv_remove(struct platform_device *pdev)
++{
++ struct mt8173_nor *mt8173_nor = platform_get_drvdata(pdev);
++
++ clk_disable_unprepare(mt8173_nor->spi_clk);
++ clk_disable_unprepare(mt8173_nor->nor_clk);
++ return 0;
++}
++
++static const struct of_device_id mtk_nor_of_ids[] = {
++ { .compatible = "mediatek,mt8173-nor"},
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mtk_nor_of_ids);
++
++static struct platform_driver mtk_nor_driver = {
++ .probe = mtk_nor_drv_probe,
++ .remove = mtk_nor_drv_remove,
++ .driver = {
++ .name = "mtk-nor",
++ .of_match_table = mtk_nor_of_ids,
++ },
++};
++
++module_platform_driver(mtk_nor_driver);
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("MediaTek SPI NOR Flash Driver");
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -38,6 +38,7 @@
+ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
+
+ #define SPI_NOR_MAX_ID_LEN 6
++#define SPI_NOR_MAX_ADDR_WIDTH 4
+
+ struct flash_info {
+ char *name;
+@@ -60,14 +61,20 @@ struct flash_info {
+ u16 addr_width;
+
+ u16 flags;
+-#define SECT_4K 0x01 /* SPINOR_OP_BE_4K works uniformly */
+-#define SPI_NOR_NO_ERASE 0x02 /* No erase command needed */
+-#define SST_WRITE 0x04 /* use SST byte programming */
+-#define SPI_NOR_NO_FR 0x08 /* Can't do fastread */
+-#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */
+-#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */
+-#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */
+-#define USE_FSR 0x80 /* use flag status register */
++#define SECT_4K BIT(0) /* SPINOR_OP_BE_4K works uniformly */
++#define SPI_NOR_NO_ERASE BIT(1) /* No erase command needed */
++#define SST_WRITE BIT(2) /* use SST byte programming */
++#define SPI_NOR_NO_FR BIT(3) /* Can't do fastread */
++#define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */
++#define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */
++#define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */
++#define USE_FSR BIT(7) /* use flag status register */
++#define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */
++#define SPI_NOR_HAS_TB BIT(9) /*
++ * Flash SR has Top/Bottom (TB) protect
++ * bit. Must be used with
++ * SPI_NOR_HAS_LOCK.
++ */
+ };
+
+ #define JEDEC_MFR(info) ((info)->id[0])
+@@ -313,6 +320,29 @@ static void spi_nor_unlock_and_unprep(st
+ }
+
+ /*
++ * Initiate the erasure of a single sector
++ */
++static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
++{
++ u8 buf[SPI_NOR_MAX_ADDR_WIDTH];
++ int i;
++
++ if (nor->erase)
++ return nor->erase(nor, addr);
++
++ /*
++ * Default implementation, if driver doesn't have a specialized HW
++ * control
++ */
++ for (i = nor->addr_width - 1; i >= 0; i--) {
++ buf[i] = addr & 0xff;
++ addr >>= 8;
++ }
++
++ return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
++}
++
++/*
+ * Erase an address range on the nor chip. The address range may extend
+ * one or more erase sectors. Return an error is there is a problem erasing.
+ */
+@@ -371,10 +401,9 @@ static int spi_nor_erase(struct mtd_info
+ while (len) {
+ write_enable(nor);
+
+- if (nor->erase(nor, addr)) {
+- ret = -EIO;
++ ret = spi_nor_erase_sector(nor, addr);
++ if (ret)
+ goto erase_err;
+- }
+
+ addr += mtd->erasesize;
+ len -= mtd->erasesize;
+@@ -387,17 +416,13 @@ static int spi_nor_erase(struct mtd_info
+
+ write_disable(nor);
+
++erase_err:
+ spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+
+- instr->state = MTD_ERASE_DONE;
++ instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return ret;
+-
+-erase_err:
+- spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
+- instr->state = MTD_ERASE_FAILED;
+- return ret;
+ }
+
+ static void stm_get_locked_range(struct spi_nor *nor, u8 sr, loff_t *ofs,
+@@ -415,32 +440,58 @@ static void stm_get_locked_range(struct
+ } else {
+ pow = ((sr & mask) ^ mask) >> shift;
+ *len = mtd->size >> pow;
+- *ofs = mtd->size - *len;
++ if (nor->flags & SNOR_F_HAS_SR_TB && sr & SR_TB)
++ *ofs = 0;
++ else
++ *ofs = mtd->size - *len;
+ }
+ }
+
+ /*
+- * Return 1 if the entire region is locked, 0 otherwise
++ * Return 1 if the entire region is locked (if @locked is true) or unlocked (if
++ * @locked is false); 0 otherwise
+ */
+-static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
+- u8 sr)
++static int stm_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr, bool locked)
+ {
+ loff_t lock_offs;
+ uint64_t lock_len;
+
++ if (!len)
++ return 1;
++
+ stm_get_locked_range(nor, sr, &lock_offs, &lock_len);
+
+- return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++ if (locked)
++ /* Requested range is a sub-range of locked range */
++ return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++ else
++ /* Requested range does not overlap with locked range */
++ return (ofs >= lock_offs + lock_len) || (ofs + len <= lock_offs);
++}
++
++static int stm_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr)
++{
++ return stm_check_lock_status_sr(nor, ofs, len, sr, true);
++}
++
++static int stm_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
++ u8 sr)
++{
++ return stm_check_lock_status_sr(nor, ofs, len, sr, false);
+ }
+
+ /*
+ * Lock a region of the flash. Compatible with ST Micro and similar flash.
+- * Supports only the block protection bits BP{0,1,2} in the status register
++ * Supports the block protection bits BP{0,1,2} in the status register
+ * (SR). Does not support these features found in newer SR bitfields:
+- * - TB: top/bottom protect - only handle TB=0 (top protect)
+ * - SEC: sector/block protect - only handle SEC=0 (block protect)
+ * - CMP: complement protect - only support CMP=0 (range is not complemented)
+ *
++ * Support for the following is provided conditionally for some flash:
++ * - TB: top/bottom protect
++ *
+ * Sample table portion for 8MB flash (Winbond w25q64fw):
+ *
+ * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion
+@@ -453,26 +504,55 @@ static int stm_is_locked_sr(struct spi_n
+ * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4
+ * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2
+ * X | X | 1 | 1 | 1 | 8 MB | ALL
++ * ------|-------|-------|-------|-------|---------------|-------------------
++ * 0 | 1 | 0 | 0 | 1 | 128 KB | Lower 1/64
++ * 0 | 1 | 0 | 1 | 0 | 256 KB | Lower 1/32
++ * 0 | 1 | 0 | 1 | 1 | 512 KB | Lower 1/16
++ * 0 | 1 | 1 | 0 | 0 | 1 MB | Lower 1/8
++ * 0 | 1 | 1 | 0 | 1 | 2 MB | Lower 1/4
++ * 0 | 1 | 1 | 1 | 0 | 4 MB | Lower 1/2
+ *
+ * Returns negative on errors, 0 on success.
+ */
+ static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- u8 status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
++ loff_t lock_len;
++ bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++ bool use_top;
++ int ret;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
+
+- /* SPI NOR always locks to the end */
+- if (ofs + len != mtd->size) {
+- /* Does combined region extend to end? */
+- if (!stm_is_locked_sr(nor, ofs + len, mtd->size - ofs - len,
+- status_old))
+- return -EINVAL;
+- len = mtd->size - ofs;
+- }
++ /* If nothing in our range is unlocked, we don't need to do anything */
++ if (stm_is_locked_sr(nor, ofs, len, status_old))
++ return 0;
++
++ /* If anything below us is unlocked, we can't use 'bottom' protection */
++ if (!stm_is_locked_sr(nor, 0, ofs, status_old))
++ can_be_bottom = false;
++
++ /* If anything above us is unlocked, we can't use 'top' protection */
++ if (!stm_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
++ status_old))
++ can_be_top = false;
++
++ if (!can_be_bottom && !can_be_top)
++ return -EINVAL;
++
++ /* Prefer top, if both are valid */
++ use_top = can_be_top;
++
++ /* lock_len: length of region that should end up locked */
++ if (use_top)
++ lock_len = mtd->size - ofs;
++ else
++ lock_len = ofs + len;
+
+ /*
+ * Need smallest pow such that:
+@@ -483,7 +563,7 @@ static int stm_lock(struct spi_nor *nor,
+ *
+ * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
+ */
+- pow = ilog2(mtd->size) - ilog2(len);
++ pow = ilog2(mtd->size) - ilog2(lock_len);
+ val = mask - (pow << shift);
+ if (val & ~mask)
+ return -EINVAL;
+@@ -491,14 +571,27 @@ static int stm_lock(struct spi_nor *nor,
+ if (!(val & mask))
+ return -EINVAL;
+
+- status_new = (status_old & ~mask) | val;
++ status_new = (status_old & ~mask & ~SR_TB) | val;
++
++ /* Disallow further writes if WP pin is asserted */
++ status_new |= SR_SRWD;
++
++ if (!use_top)
++ status_new |= SR_TB;
++
++ /* Don't bother if they're the same */
++ if (status_new == status_old)
++ return 0;
+
+ /* Only modify protection if it will not unlock other areas */
+- if ((status_new & mask) <= (status_old & mask))
++ if ((status_new & mask) < (status_old & mask))
+ return -EINVAL;
+
+ write_enable(nor);
+- return write_sr(nor, status_new);
++ ret = write_sr(nor, status_new);
++ if (ret)
++ return ret;
++ return spi_nor_wait_till_ready(nor);
+ }
+
+ /*
+@@ -509,17 +602,43 @@ static int stm_lock(struct spi_nor *nor,
+ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
+ {
+ struct mtd_info *mtd = &nor->mtd;
+- uint8_t status_old, status_new;
++ int status_old, status_new;
+ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
+ u8 shift = ffs(mask) - 1, pow, val;
++ loff_t lock_len;
++ bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
++ bool use_top;
++ int ret;
+
+ status_old = read_sr(nor);
++ if (status_old < 0)
++ return status_old;
++
++ /* If nothing in our range is locked, we don't need to do anything */
++ if (stm_is_unlocked_sr(nor, ofs, len, status_old))
++ return 0;
++
++ /* If anything below us is locked, we can't use 'top' protection */
++ if (!stm_is_unlocked_sr(nor, 0, ofs, status_old))
++ can_be_top = false;
++
++ /* If anything above us is locked, we can't use 'bottom' protection */
++ if (!stm_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
++ status_old))
++ can_be_bottom = false;
+
+- /* Cannot unlock; would unlock larger region than requested */
+- if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+- status_old))
++ if (!can_be_bottom && !can_be_top)
+ return -EINVAL;
+
++ /* Prefer top, if both are valid */
++ use_top = can_be_top;
++
++ /* lock_len: length of region that should remain locked */
++ if (use_top)
++ lock_len = mtd->size - (ofs + len);
++ else
++ lock_len = ofs;
++
+ /*
+ * Need largest pow such that:
+ *
+@@ -529,8 +648,8 @@ static int stm_unlock(struct spi_nor *no
+ *
+ * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
+ */
+- pow = ilog2(mtd->size) - order_base_2(mtd->size - (ofs + len));
+- if (ofs + len == mtd->size) {
++ pow = ilog2(mtd->size) - order_base_2(lock_len);
++ if (lock_len == 0) {
+ val = 0; /* fully unlocked */
+ } else {
+ val = mask - (pow << shift);
+@@ -539,14 +658,28 @@ static int stm_unlock(struct spi_nor *no
+ return -EINVAL;
+ }
+
+- status_new = (status_old & ~mask) | val;
++ status_new = (status_old & ~mask & ~SR_TB) | val;
++
++ /* Don't protect status register if we're fully unlocked */
++ if (lock_len == mtd->size)
++ status_new &= ~SR_SRWD;
++
++ if (!use_top)
++ status_new |= SR_TB;
++
++ /* Don't bother if they're the same */
++ if (status_new == status_old)
++ return 0;
+
+ /* Only modify protection if it will not lock other areas */
+- if ((status_new & mask) >= (status_old & mask))
++ if ((status_new & mask) > (status_old & mask))
+ return -EINVAL;
+
+ write_enable(nor);
+- return write_sr(nor, status_new);
++ ret = write_sr(nor, status_new);
++ if (ret)
++ return ret;
++ return spi_nor_wait_till_ready(nor);
+ }
+
+ /*
+@@ -715,9 +848,9 @@ static const struct flash_info spi_nor_i
+ { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
+ { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
+ { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
+- { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
++ { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
+ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
+- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+ { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+@@ -732,8 +865,8 @@ static const struct flash_info spi_nor_i
+ { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
+ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
+- { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
+- { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
++ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
++ { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+ { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+@@ -767,6 +900,7 @@ static const struct flash_info spi_nor_i
+ { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
++ { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) },
+ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
+ { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) },
+@@ -830,11 +964,23 @@ static const struct flash_info spi_nor_i
+ { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) },
+ { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) },
+ { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
+- { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++ {
++ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
+ { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
+ { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+- { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+- { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++ {
++ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
++ {
++ "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256,
++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
++ },
+ { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
+ { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
+@@ -857,7 +1003,7 @@ static const struct flash_info *spi_nor_
+
+ tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN);
+ if (tmp < 0) {
+- dev_dbg(nor->dev, " error %d reading JEDEC ID\n", tmp);
++ dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
+ return ERR_PTR(tmp);
+ }
+
+@@ -868,7 +1014,7 @@ static const struct flash_info *spi_nor_
+ return &spi_nor_ids[tmp];
+ }
+ }
+- dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %2x, %2x\n",
++ dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
+ id[0], id[1], id[2]);
+ return ERR_PTR(-ENODEV);
+ }
+@@ -1014,6 +1160,8 @@ static int macronix_quad_enable(struct s
+ int ret, val;
+
+ val = read_sr(nor);
++ if (val < 0)
++ return val;
+ write_enable(nor);
+
+ write_sr(nor, val | SR_QUAD_EN_MX);
+@@ -1095,7 +1243,7 @@ static int set_quad_mode(struct spi_nor
+ static int spi_nor_check(struct spi_nor *nor)
+ {
+ if (!nor->dev || !nor->read || !nor->write ||
+- !nor->read_reg || !nor->write_reg || !nor->erase) {
++ !nor->read_reg || !nor->write_reg) {
+ pr_err("spi-nor: please fill all the necessary fields!\n");
+ return -EINVAL;
+ }
+@@ -1108,7 +1256,7 @@ int spi_nor_scan(struct spi_nor *nor, co
+ const struct flash_info *info = NULL;
+ struct device *dev = nor->dev;
+ struct mtd_info *mtd = &nor->mtd;
+- struct device_node *np = nor->flash_node;
++ struct device_node *np = spi_nor_get_flash_node(nor);
+ int ret;
+ int i;
+
+@@ -1158,9 +1306,11 @@ int spi_nor_scan(struct spi_nor *nor, co
+ if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
+ JEDEC_MFR(info) == SNOR_MFR_INTEL ||
+ JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
+- JEDEC_MFR(info) == SNOR_MFR_SST) {
++ JEDEC_MFR(info) == SNOR_MFR_SST ||
++ info->flags & SPI_NOR_HAS_LOCK) {
+ write_enable(nor);
+ write_sr(nor, 0);
++ spi_nor_wait_till_ready(nor);
+ }
+
+ if (!mtd->name)
+@@ -1174,7 +1324,8 @@ int spi_nor_scan(struct spi_nor *nor, co
+ mtd->_read = spi_nor_read;
+
+ /* NOR protection support for STmicro/Micron chips and similar */
+- if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
++ if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
++ info->flags & SPI_NOR_HAS_LOCK) {
+ nor->flash_lock = stm_lock;
+ nor->flash_unlock = stm_unlock;
+ nor->flash_is_locked = stm_is_locked;
+@@ -1194,6 +1345,8 @@ int spi_nor_scan(struct spi_nor *nor, co
+
+ if (info->flags & USE_FSR)
+ nor->flags |= SNOR_F_USE_FSR;
++ if (info->flags & SPI_NOR_HAS_TB)
++ nor->flags |= SNOR_F_HAS_SR_TB;
+
+ #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
+ /* prefer "small sector" erase if possible */
+@@ -1296,6 +1449,12 @@ int spi_nor_scan(struct spi_nor *nor, co
+ nor->addr_width = 3;
+ }
+
++ if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) {
++ dev_err(dev, "address width is too large: %u\n",
++ nor->addr_width);
++ return -EINVAL;
++ }
++
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor);
+
+ dev_info(dev, "%s (%lld Kbytes)\n", info->name,
+--- a/drivers/mtd/tests/mtd_nandecctest.c
++++ b/drivers/mtd/tests/mtd_nandecctest.c
+@@ -187,7 +187,7 @@ static int double_bit_error_detect(void
+ __nand_calculate_ecc(error_data, size, calc_ecc);
+ ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size);
+
+- return (ret == -1) ? 0 : -EINVAL;
++ return (ret == -EBADMSG) ? 0 : -EINVAL;
+ }
+
+ static const struct nand_ecc_test nand_ecc_test[] = {
+--- a/drivers/mtd/tests/oobtest.c
++++ b/drivers/mtd/tests/oobtest.c
+@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum)
+ pr_info("ignoring error as within bitflip_limit\n");
+ }
+
+- if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
++ if (use_offset != 0 || use_len < mtd->oobavail) {
+ int k;
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+ ops.oobbuf = readbuf;
+ err = mtd_read_oob(mtd, addr, &ops);
+- if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
++ if (err || ops.oobretlen != mtd->oobavail) {
+ pr_err("error: readoob failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum)
+ /* verify post-(use_offset + use_len) area for 0xff */
+ k = use_offset + use_len;
+ bitflips += memffshow(addr, k, readbuf + k,
+- mtd->ecclayout->oobavail - k);
++ mtd->oobavail - k);
+
+ if (bitflips > bitflip_limit) {
+ pr_err("error: verify failed at %#llx\n",
+@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(i
+ struct mtd_oob_ops ops;
+ int err = 0;
+ loff_t addr = (loff_t)ebnum * mtd->erasesize;
+- size_t len = mtd->ecclayout->oobavail * pgcnt;
+- size_t oobavail = mtd->ecclayout->oobavail;
++ size_t len = mtd->oobavail * pgcnt;
++ size_t oobavail = mtd->oobavail;
+ size_t bitflips;
+ int i;
+
+@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void)
+ goto out;
+
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 0;
+
+ /* First test: write all OOB, read it back and verify */
+@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void)
+
+ /* Write all eraseblocks */
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 1;
+ prandom_seed_state(&rnd_state, 5);
+
+@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void)
+
+ /* Check all eraseblocks */
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 1;
+ prandom_seed_state(&rnd_state, 5);
+ err = verify_all_eraseblocks();
+@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void)
+ goto out;
+
+ use_offset = 0;
+- use_len = mtd->ecclayout->oobavail;
+- use_len_max = mtd->ecclayout->oobavail;
++ use_len = mtd->oobavail;
++ use_len_max = mtd->oobavail;
+ vary_offset = 0;
+
+ /* Fourth test: try to write off end of device */
+@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void)
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+- ops.ooboffs = mtd->ecclayout->oobavail;
++ ops.ooboffs = mtd->oobavail;
+ ops.datbuf = NULL;
+ ops.oobbuf = writebuf;
+ pr_info("attempting to start write past end of OOB\n");
+@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void)
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+- ops.ooboffs = mtd->ecclayout->oobavail;
++ ops.ooboffs = mtd->oobavail;
+ ops.datbuf = NULL;
+ ops.oobbuf = readbuf;
+ pr_info("attempting to start read past end of OOB\n");
+@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail + 1;
++ ops.ooblen = mtd->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail + 1;
++ ops.ooblen = mtd->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = NULL;
+@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void)
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail;
++ ops.ooblen = mtd->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = NULL;
+@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void)
+ for (i = 0; i < ebcnt - 1; ++i) {
+ int cnt = 2;
+ int pg;
+- size_t sz = mtd->ecclayout->oobavail;
++ size_t sz = mtd->oobavail;
+ if (bbt[i] || bbt[i + 1])
+ continue;
+ addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
+@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void)
+ for (i = 0; i < ebcnt - 1; ++i) {
+ if (bbt[i] || bbt[i + 1])
+ continue;
+- prandom_bytes_state(&rnd_state, writebuf,
+- mtd->ecclayout->oobavail * 2);
++ prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
+ addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.len = 0;
+ ops.retlen = 0;
+- ops.ooblen = mtd->ecclayout->oobavail * 2;
++ ops.ooblen = mtd->oobavail * 2;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = NULL;
+@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void)
+ if (err)
+ goto out;
+ if (memcmpshow(addr, readbuf, writebuf,
+- mtd->ecclayout->oobavail * 2)) {
++ mtd->oobavail * 2)) {
+ pr_err("error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+--- a/drivers/mtd/tests/pagetest.c
++++ b/drivers/mtd/tests/pagetest.c
+@@ -127,13 +127,12 @@ static int crosstest(void)
+ unsigned char *pp1, *pp2, *pp3, *pp4;
+
+ pr_info("crosstest\n");
+- pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
++ pp1 = kzalloc(pgsize * 4, GFP_KERNEL);
+ if (!pp1)
+ return -ENOMEM;
+ pp2 = pp1 + pgsize;
+ pp3 = pp2 + pgsize;
+ pp4 = pp3 + pgsize;
+- memset(pp1, 0, pgsize * 4);
+
+ addr0 = 0;
+ for (i = 0; i < ebcnt && bbt[i]; ++i)
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -174,9 +174,9 @@ static int vol_cdev_fsync(struct file *f
+ struct ubi_device *ubi = desc->vol->ubi;
+ struct inode *inode = file_inode(file);
+ int err;
+- mutex_lock(&inode->i_mutex);
++ inode_lock(inode);
+ err = ubi_sync(ubi->ubi_num);
+- mutex_unlock(&inode->i_mutex);
++ inode_unlock(inode);
+ return err;
+ }
+
+--- a/drivers/mtd/ubi/misc.c
++++ b/drivers/mtd/ubi/misc.c
+@@ -153,3 +153,52 @@ int ubi_check_pattern(const void *buf, u
+ return 0;
+ return 1;
+ }
++
++/* Normal UBI messages */
++void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_notice(UBI_NAME_STR "%d: %pV\n", ubi->ubi_num, &vaf);
++
++ va_end(args);
++}
++
++/* UBI warning messages */
++void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_warn(UBI_NAME_STR "%d warning: %ps: %pV\n",
++ ubi->ubi_num, __builtin_return_address(0), &vaf);
++
++ va_end(args);
++}
++
++/* UBI error messages */
++void ubi_err(const struct ubi_device *ubi, const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ pr_err(UBI_NAME_STR "%d error: %ps: %pV\n",
++ ubi->ubi_num, __builtin_return_address(0), &vaf);
++ va_end(args);
++}
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -49,15 +49,19 @@
+ /* UBI name used for character devices, sysfs, etc */
+ #define UBI_NAME_STR "ubi"
+
++struct ubi_device;
++
+ /* Normal UBI messages */
+-#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
+- ubi->ubi_num, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_msg(const struct ubi_device *ubi, const char *fmt, ...);
++
+ /* UBI warning messages */
+-#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
+- ubi->ubi_num, __func__, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_warn(const struct ubi_device *ubi, const char *fmt, ...);
++
+ /* UBI error messages */
+-#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
+- ubi->ubi_num, __func__, ##__VA_ARGS__)
++__printf(2, 3)
++void ubi_err(const struct ubi_device *ubi, const char *fmt, ...);
+
+ /* Background thread name pattern */
+ #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
+--- a/drivers/mtd/ubi/wl.c
++++ b/drivers/mtd/ubi/wl.c
+@@ -628,6 +628,7 @@ static int do_sync_erase(struct ubi_devi
+ return __erase_worker(ubi, &wl_wrk);
+ }
+
++static int ensure_wear_leveling(struct ubi_device *ubi, int nested);
+ /**
+ * wear_leveling_worker - wear-leveling worker function.
+ * @ubi: UBI device description object
+@@ -649,6 +650,7 @@ static int wear_leveling_worker(struct u
+ #endif
+ struct ubi_wl_entry *e1, *e2;
+ struct ubi_vid_hdr *vid_hdr;
++ int dst_leb_clean = 0;
+
+ kfree(wrk);
+ if (shutdown)
+@@ -753,6 +755,7 @@ static int wear_leveling_worker(struct u
+
+ err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0);
+ if (err && err != UBI_IO_BITFLIPS) {
++ dst_leb_clean = 1;
+ if (err == UBI_IO_FF) {
+ /*
+ * We are trying to move PEB without a VID header. UBI
+@@ -798,10 +801,12 @@ static int wear_leveling_worker(struct u
+ * protection queue.
+ */
+ protect = 1;
++ dst_leb_clean = 1;
+ goto out_not_moved;
+ }
+ if (err == MOVE_RETRY) {
+ scrubbing = 1;
++ dst_leb_clean = 1;
+ goto out_not_moved;
+ }
+ if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
+@@ -827,6 +832,7 @@ static int wear_leveling_worker(struct u
+ ubi->erroneous_peb_count);
+ goto out_error;
+ }
++ dst_leb_clean = 1;
+ erroneous = 1;
+ goto out_not_moved;
+ }
+@@ -897,15 +903,24 @@ out_not_moved:
+ wl_tree_add(e1, &ubi->scrub);
+ else
+ wl_tree_add(e1, &ubi->used);
++ if (dst_leb_clean) {
++ wl_tree_add(e2, &ubi->free);
++ ubi->free_count++;
++ }
++
+ ubi_assert(!ubi->move_to_put);
+ ubi->move_from = ubi->move_to = NULL;
+ ubi->wl_scheduled = 0;
+ spin_unlock(&ubi->wl_lock);
+
+ ubi_free_vid_hdr(ubi, vid_hdr);
+- err = do_sync_erase(ubi, e2, vol_id, lnum, torture);
+- if (err)
+- goto out_ro;
++ if (dst_leb_clean) {
++ ensure_wear_leveling(ubi, 1);
++ } else {
++ err = do_sync_erase(ubi, e2, vol_id, lnum, torture);
++ if (err)
++ goto out_ro;
++ }
+
+ mutex_unlock(&ubi->move_mutex);
+ return 0;
+--- a/include/linux/mtd/bbm.h
++++ b/include/linux/mtd/bbm.h
+@@ -166,7 +166,6 @@ struct bbm_info {
+ };
+
+ /* OneNAND BBT interface */
+-extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
+ extern int onenand_default_bbt(struct mtd_info *mtd);
+
+ #endif /* __LINUX_MTD_BBM_H */
+--- a/include/linux/mtd/fsmc.h
++++ b/include/linux/mtd/fsmc.h
+@@ -103,24 +103,6 @@
+
+ #define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ)
+
+-/*
+- * There are 13 bytes of ecc for every 512 byte block in FSMC version 8
+- * and it has to be read consecutively and immediately after the 512
+- * byte data block for hardware to generate the error bit offsets
+- * Managing the ecc bytes in the following way is easier. This way is
+- * similar to oobfree structure maintained already in u-boot nand driver
+- */
+-#define MAX_ECCPLACE_ENTRIES 32
+-
+-struct fsmc_nand_eccplace {
+- uint8_t offset;
+- uint8_t length;
+-};
+-
+-struct fsmc_eccplace {
+- struct fsmc_nand_eccplace eccplace[MAX_ECCPLACE_ENTRIES];
+-};
+-
+ struct fsmc_nand_timings {
+ uint8_t tclr;
+ uint8_t tar;
+--- a/include/linux/mtd/inftl.h
++++ b/include/linux/mtd/inftl.h
+@@ -44,7 +44,6 @@ struct INFTLrecord {
+ unsigned int nb_blocks; /* number of physical blocks */
+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
+ struct erase_info instr;
+- struct nand_ecclayout oobinfo;
+ };
+
+ int INFTL_mount(struct INFTLrecord *s);
+--- a/include/linux/mtd/map.h
++++ b/include/linux/mtd/map.h
+@@ -142,7 +142,9 @@
+ #endif
+
+ #ifndef map_bankwidth
++#ifdef CONFIG_MTD
+ #warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work"
++#endif
+ static inline int map_bankwidth(void *map)
+ {
+ BUG();
+@@ -238,8 +240,11 @@ struct map_info {
+ If there is no cache to care about this can be set to NULL. */
+ void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
+
+- /* set_vpp() must handle being reentered -- enable, enable, disable
+- must leave it enabled. */
++ /* This will be called with 1 as parameter when the first map user
++ * needs VPP, and called with 0 when the last user exits. The map
++ * core maintains a reference counter, and assumes that VPP is a
++ * global resource applying to all mapped flash chips on the system.
++ */
+ void (*set_vpp)(struct map_info *, int);
+
+ unsigned long pfow_base;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -100,17 +100,35 @@ struct mtd_oob_ops {
+
+ #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32
+ #define MTD_MAX_ECCPOS_ENTRIES_LARGE 640
++/**
++ * struct mtd_oob_region - oob region definition
++ * @offset: region offset
++ * @length: region length
++ *
++ * This structure describes a region of the OOB area, and is used
++ * to retrieve ECC or free bytes sections.
++ * Each section is defined by an offset within the OOB area and a
++ * length.
++ */
++struct mtd_oob_region {
++ u32 offset;
++ u32 length;
++};
++
+ /*
+- * Internal ECC layout control structure. For historical reasons, there is a
+- * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
+- * for export to user-space via the ECCGETLAYOUT ioctl.
+- * nand_ecclayout should be expandable in the future simply by the above macros.
++ * struct mtd_ooblayout_ops - NAND OOB layout operations
++ * @ecc: function returning an ECC region in the OOB area.
++ * Should return -ERANGE if %section exceeds the total number of
++ * ECC sections.
++ * @free: function returning a free region in the OOB area.
++ * Should return -ERANGE if %section exceeds the total number of
++ * free sections.
+ */
+-struct nand_ecclayout {
+- __u32 eccbytes;
+- __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE];
+- __u32 oobavail;
+- struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE];
++struct mtd_ooblayout_ops {
++ int (*ecc)(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc);
++ int (*free)(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree);
+ };
+
+ struct module; /* only needed for owner field in mtd_info */
+@@ -171,8 +189,8 @@ struct mtd_info {
+ const char *name;
+ int index;
+
+- /* ECC layout structure pointer - read only! */
+- struct nand_ecclayout *ecclayout;
++ /* OOB layout description */
++ const struct mtd_ooblayout_ops *ooblayout;
+
+ /* the ecc step size. */
+ unsigned int ecc_step_size;
+@@ -258,6 +276,46 @@ struct mtd_info {
+ int usecount;
+ };
+
++int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobecc);
++int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
++ int *section,
++ struct mtd_oob_region *oobregion);
++int mtd_ooblayout_get_eccbytes(struct mtd_info *mtd, u8 *eccbuf,
++ const u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_set_eccbytes(struct mtd_info *mtd, const u8 *eccbuf,
++ u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oobfree);
++int mtd_ooblayout_get_databytes(struct mtd_info *mtd, u8 *databuf,
++ const u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
++ u8 *oobbuf, int start, int nbytes);
++int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
++int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
++
++static inline void mtd_set_ooblayout(struct mtd_info *mtd,
++ const struct mtd_ooblayout_ops *ooblayout)
++{
++ mtd->ooblayout = ooblayout;
++}
++
++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;
++}
++
++static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
++{
++ return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
++}
++
+ 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);
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -119,6 +119,12 @@ typedef enum {
+ NAND_ECC_SOFT_BCH,
+ } nand_ecc_modes_t;
+
++enum nand_ecc_algo {
++ NAND_ECC_UNKNOWN,
++ NAND_ECC_HAMMING,
++ NAND_ECC_BCH,
++};
++
+ /*
+ * Constants for Hardware ECC
+ */
+@@ -129,6 +135,14 @@ typedef enum {
+ /* Enable Hardware ECC before syndrome is read back from flash */
+ #define NAND_ECC_READSYN 2
+
++/*
++ * Enable generic NAND 'page erased' check. This check is only done when
++ * ecc.correct() returns -EBADMSG.
++ * Set this flag if your implementation does not fix bitflips in erased
++ * pages and you want to rely on the default implementation.
++ */
++#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
++
+ /* Bit mask for flags passed to do_nand_read_ecc */
+ #define NAND_GET_DEVICE 0x80
+
+@@ -160,6 +174,12 @@ typedef enum {
+ /* Device supports subpage reads */
+ #define NAND_SUBPAGE_READ 0x00001000
+
++/*
++ * Some MLC NANDs need data scrambling to limit bitflips caused by repeated
++ * patterns.
++ */
++#define NAND_NEED_SCRAMBLING 0x00002000
++
+ /* Options valid for Samsung large page devices */
+ #define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
+
+@@ -276,15 +296,15 @@ struct nand_onfi_params {
+ __le16 t_r;
+ __le16 t_ccs;
+ __le16 src_sync_timing_mode;
+- __le16 src_ssync_features;
++ u8 src_ssync_features;
+ __le16 clk_pin_capacitance_typ;
+ __le16 io_pin_capacitance_typ;
+ __le16 input_pin_capacitance_typ;
+ u8 input_pin_capacitance_max;
+ u8 driver_strength_support;
+ __le16 t_int_r;
+- __le16 t_ald;
+- u8 reserved4[7];
++ __le16 t_adl;
++ u8 reserved4[8];
+
+ /* vendor */
+ __le16 vendor_revision;
+@@ -407,7 +427,7 @@ struct nand_jedec_params {
+ __le16 input_pin_capacitance_typ;
+ __le16 clk_pin_capacitance_typ;
+ u8 driver_strength_support;
+- __le16 t_ald;
++ __le16 t_adl;
+ u8 reserved4[36];
+
+ /* ECC and endurance block */
+@@ -444,6 +464,7 @@ struct nand_hw_control {
+ /**
+ * struct nand_ecc_ctrl - Control structure for ECC
+ * @mode: ECC mode
++ * @algo: ECC algorithm
+ * @steps: number of ECC steps per page
+ * @size: data bytes per ECC step
+ * @bytes: ECC bytes per step
+@@ -451,12 +472,18 @@ struct nand_hw_control {
+ * @total: total number of ECC bytes per page
+ * @prepad: padding information for syndrome based ECC generators
+ * @postpad: padding information for syndrome based ECC generators
+- * @layout: ECC layout control struct pointer
++ * @options: ECC specific options (see NAND_ECC_XXX flags defined above)
+ * @priv: pointer to private ECC control data
+ * @hwctl: function to control hardware ECC generator. Must only
+ * be provided if an hardware ECC is available
+ * @calculate: function for ECC calculation or readback from ECC hardware
+- * @correct: function for ECC correction, matching to ECC generator (sw/hw)
++ * @correct: function for ECC correction, matching to ECC generator (sw/hw).
++ * Should return a positive number representing the number of
++ * corrected bitflips, -EBADMSG if the number of bitflips exceed
++ * ECC strength, or any other error code if the error is not
++ * directly related to correction.
++ * If -EBADMSG is returned the input buffers should be left
++ * untouched.
+ * @read_page_raw: function to read a raw page without ECC. This function
+ * should hide the specific layout used by the ECC
+ * controller and always return contiguous in-band and
+@@ -487,6 +514,7 @@ struct nand_hw_control {
+ */
+ struct nand_ecc_ctrl {
+ nand_ecc_modes_t mode;
++ enum nand_ecc_algo algo;
+ int steps;
+ int size;
+ int bytes;
+@@ -494,7 +522,7 @@ struct nand_ecc_ctrl {
+ int strength;
+ int prepad;
+ int postpad;
+- struct nand_ecclayout *layout;
++ unsigned int options;
+ void *priv;
+ void (*hwctl)(struct mtd_info *mtd, int mode);
+ int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
+@@ -540,11 +568,11 @@ 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
+ * flash device.
+- * @flash_node: [BOARDSPECIFIC] device node describing this instance
+ * @read_byte: [REPLACEABLE] read one byte from the chip
+ * @read_word: [REPLACEABLE] read one word from the chip
+ * @write_byte: [REPLACEABLE] write a single byte to the chip on the
+@@ -640,18 +668,17 @@ struct nand_buffers {
+ */
+
+ struct nand_chip {
++ struct mtd_info mtd;
+ void __iomem *IO_ADDR_R;
+ void __iomem *IO_ADDR_W;
+
+- struct device_node *flash_node;
+-
+ uint8_t (*read_byte)(struct mtd_info *mtd);
+ u16 (*read_word)(struct mtd_info *mtd);
+ void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
+ void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+ void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
+ void (*select_chip)(struct mtd_info *mtd, int chip);
+- int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
++ int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
+ int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
+ int (*dev_ready)(struct mtd_info *mtd);
+@@ -719,6 +746,40 @@ struct nand_chip {
+ void *priv;
+ };
+
++extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops;
++extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops;
++
++static inline void nand_set_flash_node(struct nand_chip *chip,
++ struct device_node *np)
++{
++ mtd_set_of_node(&chip->mtd, np);
++}
++
++static inline struct device_node *nand_get_flash_node(struct nand_chip *chip)
++{
++ return mtd_get_of_node(&chip->mtd);
++}
++
++static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd)
++{
++ return container_of(mtd, struct nand_chip, mtd);
++}
++
++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
+ */
+@@ -850,7 +911,6 @@ extern int nand_do_read(struct mtd_info
+ * @chip_delay: R/B delay value in us
+ * @options: Option flags, e.g. 16bit buswidth
+ * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
+- * @ecclayout: ECC layout info structure
+ * @part_probe_types: NULL-terminated array of probe types
+ */
+ struct platform_nand_chip {
+@@ -858,7 +918,6 @@ struct platform_nand_chip {
+ int chip_offset;
+ int nr_partitions;
+ struct mtd_partition *partitions;
+- struct nand_ecclayout *ecclayout;
+ int chip_delay;
+ unsigned int options;
+ unsigned int bbt_options;
+@@ -908,15 +967,6 @@ struct platform_nand_data {
+ struct platform_nand_ctrl ctrl;
+ };
+
+-/* Some helpers to access the data structures */
+-static inline
+-struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
+-{
+- struct nand_chip *chip = mtd->priv;
+-
+- return chip->priv;
+-}
+-
+ /* return the supported features. */
+ static inline int onfi_feature(struct nand_chip *chip)
+ {
+--- a/include/linux/mtd/nand_bch.h
++++ b/include/linux/mtd/nand_bch.h
+@@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_inf
+ /*
+ * Initialize BCH encoder/decoder
+ */
+-struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+- unsigned int eccbytes, struct nand_ecclayout **ecclayout);
++struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
+ /*
+ * Release BCH encoder/decoder resources
+ */
+@@ -55,12 +53,10 @@ static inline int
+ nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
+ unsigned char *read_ecc, unsigned char *calc_ecc)
+ {
+- return -1;
++ return -ENOTSUPP;
+ }
+
+-static inline struct nand_bch_control *
+-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
+- unsigned int eccbytes, struct nand_ecclayout **ecclayout)
++static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
+ {
+ return NULL;
+ }
+--- a/include/linux/mtd/nftl.h
++++ b/include/linux/mtd/nftl.h
+@@ -50,7 +50,6 @@ struct NFTLrecord {
+ unsigned int nb_blocks; /* number of physical blocks */
+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */
+ struct erase_info instr;
+- struct nand_ecclayout oobinfo;
+ };
+
+ int NFTL_mount(struct NFTLrecord *s);
+--- a/include/linux/mtd/onenand.h
++++ b/include/linux/mtd/onenand.h
+@@ -80,7 +80,6 @@ struct onenand_bufferram {
+ * @page_buf: [INTERN] page main data buffer
+ * @oob_buf: [INTERN] page oob data buffer
+ * @subpagesize: [INTERN] holds the subpagesize
+- * @ecclayout: [REPLACEABLE] the default ecc placement scheme
+ * @bbm: [REPLACEABLE] pointer to Bad Block Management
+ * @priv: [OPTIONAL] pointer to private chip date
+ */
+@@ -134,7 +133,6 @@ struct onenand_chip {
+ #endif
+
+ int subpagesize;
+- struct nand_ecclayout *ecclayout;
+
+ void *bbm;
+
+--- a/include/linux/mtd/partitions.h
++++ b/include/linux/mtd/partitions.h
+@@ -42,7 +42,6 @@ struct mtd_partition {
+ uint64_t size; /* partition size */
+ uint64_t offset; /* offset within the master MTD space */
+ uint32_t mask_flags; /* master MTD flags to mask out for this partition */
+- struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */
+ };
+
+ #define MTDPART_OFS_RETAIN (-3)
+@@ -56,11 +55,9 @@ struct device_node;
+ /**
+ * struct mtd_part_parser_data - used to pass data to MTD partition parsers.
+ * @origin: for RedBoot, start address of MTD device
+- * @of_node: for OF parsers, device node containing partitioning information
+ */
+ struct mtd_part_parser_data {
+ unsigned long origin;
+- struct device_node *of_node;
+ };
+
+
+@@ -78,14 +75,34 @@ struct mtd_part_parser {
+ struct list_head list;
+ struct module *owner;
+ const char *name;
+- int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
++ int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
+ struct mtd_part_parser_data *);
++ void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
+ enum mtd_parser_type type;
+ };
+
+-extern void register_mtd_parser(struct mtd_part_parser *parser);
++/* Container for passing around a set of parsed partitions */
++struct mtd_partitions {
++ const struct mtd_partition *parts;
++ int nr_parts;
++ const struct mtd_part_parser *parser;
++};
++
++extern int __register_mtd_parser(struct mtd_part_parser *parser,
++ struct module *owner);
++#define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE)
++
+ extern void deregister_mtd_parser(struct mtd_part_parser *parser);
+
++/*
++ * module_mtd_part_parser() - Helper macro for MTD partition parsers that don't
++ * do anything special in module init/exit. Each driver may only use this macro
++ * once, and calling it replaces module_init() and module_exit().
++ */
++#define module_mtd_part_parser(__mtd_part_parser) \
++ module_driver(__mtd_part_parser, register_mtd_parser, \
++ deregister_mtd_parser)
++
+ int mtd_is_partition(const struct mtd_info *mtd);
+ int mtd_add_partition(struct mtd_info *master, const char *name,
+ long long offset, long long length);
+--- a/include/linux/mtd/sh_flctl.h
++++ b/include/linux/mtd/sh_flctl.h
+@@ -143,11 +143,11 @@ enum flctl_ecc_res_t {
+ struct dma_chan;
+
+ struct sh_flctl {
+- struct mtd_info mtd;
+ struct nand_chip chip;
+ struct platform_device *pdev;
+ struct dev_pm_qos_request pm_qos;
+ void __iomem *reg;
++ resource_size_t fifo;
+
+ uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */
+ int read_bytes;
+@@ -186,7 +186,7 @@ struct sh_flctl_platform_data {
+
+ static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
+ {
+- return container_of(mtdinfo, struct sh_flctl, mtd);
++ return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip);
+ }
+
+ #endif /* __SH_FLCTL_H__ */
+--- a/include/linux/mtd/sharpsl.h
++++ b/include/linux/mtd/sharpsl.h
+@@ -14,7 +14,7 @@
+
+ struct sharpsl_nand_platform_data {
+ struct nand_bbt_descr *badblock_pattern;
+- struct nand_ecclayout *ecc_layout;
++ const struct mtd_ooblayout_ops *ecc_layout;
+ struct mtd_partition *partitions;
+ unsigned int nr_partitions;
+ };
+--- a/include/uapi/mtd/mtd-abi.h
++++ b/include/uapi/mtd/mtd-abi.h
+@@ -228,7 +228,7 @@ struct nand_oobfree {
+ * complete set of ECC information. The ioctl truncates the larger internal
+ * structure to retain binary compatibility with the static declaration of the
+ * ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
+- * the user struct, not the MAX size of the internal struct nand_ecclayout.
++ * the user struct, not the MAX size of the internal OOB layout representation.
+ */
+ struct nand_ecclayout_user {
+ __u32 eccbytes;
+--- a/fs/jffs2/wbuf.c
++++ b/fs/jffs2/wbuf.c
+@@ -1153,7 +1153,7 @@ static struct jffs2_sb_info *work_to_sb(
+ {
+ struct delayed_work *dwork;
+
+- dwork = container_of(work, struct delayed_work, work);
++ dwork = to_delayed_work(work);
+ return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
+ }
+
+@@ -1183,22 +1183,20 @@ void jffs2_dirty_trigger(struct jffs2_sb
+
+ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+ {
+- struct nand_ecclayout *oinfo = c->mtd->ecclayout;
+-
+ if (!c->mtd->oobsize)
+ return 0;
+
+ /* Cleanmarker is out-of-band, so inline size zero */
+ c->cleanmarker_size = 0;
+
+- if (!oinfo || oinfo->oobavail == 0) {
++ if (c->mtd->oobavail == 0) {
+ pr_err("inconsistent device description\n");
+ return -EINVAL;
+ }
+
+ jffs2_dbg(1, "using OOB on NAND\n");
+
+- c->oobavail = oinfo->oobavail;
++ c->oobavail = c->mtd->oobavail;
+
+ /* Initialise write buffer */
+ init_rwsem(&c->wbuf_sem);
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -85,6 +85,7 @@
+ #define SR_BP0 BIT(2) /* Block protect 0 */
+ #define SR_BP1 BIT(3) /* Block protect 1 */
+ #define SR_BP2 BIT(4) /* Block protect 2 */
++#define SR_TB BIT(5) /* Top/Bottom protect */
+ #define SR_SRWD BIT(7) /* SR write protect */
+
+ #define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */
+@@ -116,6 +117,7 @@ enum spi_nor_ops {
+
+ enum spi_nor_option_flags {
+ SNOR_F_USE_FSR = BIT(0),
++ SNOR_F_HAS_SR_TB = BIT(1),
+ };
+
+ /**
+@@ -123,7 +125,6 @@ enum spi_nor_option_flags {
+ * @mtd: point to a mtd_info structure
+ * @lock: the lock for the read/write/erase/lock/unlock operations
+ * @dev: point to a spi device, or a spi nor controller device.
+- * @flash_node: point to a device node describing this flash instance.
+ * @page_size: the page size of the SPI NOR
+ * @addr_width: number of address bytes
+ * @erase_opcode: the opcode for erasing a sector
+@@ -143,7 +144,8 @@ enum spi_nor_option_flags {
+ * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
+ * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
+ * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
+- * at the offset @offs
++ * at the offset @offs; if not provided by the driver,
++ * spi-nor will send the erase opcode via write_reg()
+ * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
+ * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
+ * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is
+@@ -154,7 +156,6 @@ struct spi_nor {
+ struct mtd_info mtd;
+ struct mutex lock;
+ struct device *dev;
+- struct device_node *flash_node;
+ u32 page_size;
+ u8 addr_width;
+ u8 erase_opcode;
+@@ -184,6 +185,17 @@ struct spi_nor {
+ void *priv;
+ };
+
++static inline void spi_nor_set_flash_node(struct spi_nor *nor,
++ struct device_node *np)
++{
++ mtd_set_of_node(&nor->mtd, np);
++}
++
++static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
++{
++ return mtd_get_of_node(&nor->mtd);
++}
++
+ /**
+ * spi_nor_scan() - scan the SPI NOR
+ * @nor: the spi_nor structure
diff --git a/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch b/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch
new file mode 100644
index 0000000000..44ab079cc0
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0073-of-mtd-prepare-helper-reading-NAND-ECC-algo-from-DT.patch
@@ -0,0 +1,91 @@
+From 410a91f6efa1c4c3c4369d1dd2c31286749dff33 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 23 Mar 2016 11:19:01 +0100
+Subject: [PATCH 073/102] of: mtd: prepare helper reading NAND ECC algo from
+ DT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+NAND subsystem is being slightly reworked to store ECC details in
+separated fields. In future we'll want to add support for more DT
+properties as specifying every possible setup with a single
+"nand-ecc-mode" is a pretty bad idea.
+To allow this let's add a helper that will support something like
+"nand-ecc-algo" in future. Right now we use it for keeping backward
+compatibility.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+---
+ drivers/of/of_mtd.c | 36 ++++++++++++++++++++++++++++++++++++
+ include/linux/of_mtd.h | 6 ++++++
+ 2 files changed, 42 insertions(+)
+
+--- a/drivers/of/of_mtd.c
++++ b/drivers/of/of_mtd.c
+@@ -50,6 +50,42 @@ int of_get_nand_ecc_mode(struct device_n
+ EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
+
+ /**
++ * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
++ * @np: Pointer to the given device_node
++ *
++ * The function gets ecc algorithm and returns its enum value, or errno in error
++ * case.
++ */
++int of_get_nand_ecc_algo(struct device_node *np)
++{
++ const char *pm;
++ int err;
++
++ /*
++ * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
++ * It's not implemented yet as currently NAND subsystem ignores
++ * algorithm explicitly set this way. Once it's handled we should
++ * document & support new property.
++ */
++
++ /*
++ * For backward compatibility we also read "nand-ecc-mode" checking
++ * for some obsoleted values that were specifying ECC algorithm.
++ */
++ err = of_property_read_string(np, "nand-ecc-mode", &pm);
++ if (err < 0)
++ return err;
++
++ if (!strcasecmp(pm, "soft"))
++ return NAND_ECC_HAMMING;
++ else if (!strcasecmp(pm, "soft_bch"))
++ return NAND_ECC_BCH;
++
++ return -ENODEV;
++}
++EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
++
++/**
+ * of_get_nand_ecc_step_size - Get ECC step size associated to
+ * the required ECC strength (see below).
+ * @np: Pointer to the given device_node
+--- a/include/linux/of_mtd.h
++++ b/include/linux/of_mtd.h
+@@ -13,6 +13,7 @@
+
+ #include <linux/of.h>
+ int of_get_nand_ecc_mode(struct device_node *np);
++int of_get_nand_ecc_algo(struct device_node *np);
+ int of_get_nand_ecc_step_size(struct device_node *np);
+ int of_get_nand_ecc_strength(struct device_node *np);
+ int of_get_nand_bus_width(struct device_node *np);
+@@ -24,6 +25,11 @@ static inline int of_get_nand_ecc_mode(s
+ {
+ return -ENOSYS;
+ }
++
++static inline int of_get_nand_ecc_algo(struct device_node *np)
++{
++ return -ENOSYS;
++}
+
+ static inline int of_get_nand_ecc_step_size(struct device_node *np)
+ {
diff --git a/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch b/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
new file mode 100644
index 0000000000..5f260e3e34
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0074-mtd-mediatek-device-tree-docs-for-MTK-Smart-Device-G.patch
@@ -0,0 +1,179 @@
+From 5e1c00983efeca4522ac2e8574e3e3997d26a203 Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Date: Fri, 29 Apr 2016 12:17:21 -0400
+Subject: [PATCH 074/102] mtd: mediatek: device tree docs for MTK Smart Device
+ Gen1 NAND
+
+This patch adds documentation support for Smart Device Gen1 type of
+NAND controllers.
+
+Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+---
+ Documentation/devicetree/bindings/mtd/mtk-nand.txt | 161 ++++++++++++++++++++
+ 1 file changed, 161 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/mtk-nand.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/mtk-nand.txt
+@@ -0,0 +1,161 @@
++MTK SoCs NAND FLASH controller (NFC) DT binding
++
++This file documents the device tree bindings for MTK SoCs NAND controllers.
++The functional split of the controller requires two drivers to operate:
++the nand controller interface driver and the ECC engine driver.
++
++The hardware description for both devices must be captured as device
++tree nodes.
++
++1) NFC NAND Controller Interface (NFI):
++=======================================
++
++The first part of NFC is NAND Controller Interface (NFI) HW.
++Required NFI properties:
++- compatible: Should be "mediatek,mtxxxx-nfc".
++- reg: Base physical address and size of NFI.
++- interrupts: Interrupts of NFI.
++- clocks: NFI required clocks.
++- clock-names: NFI clocks internal name.
++- status: Disabled default. Then set "okay" by platform.
++- ecc-engine: Required ECC Engine node.
++- #address-cells: NAND chip index, should be 1.
++- #size-cells: Should be 0.
++
++Example:
++
++ nandc: nfi@1100d000 {
++ compatible = "mediatek,mt2701-nfc";
++ reg = <0 0x1100d000 0 0x1000>;
++ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFI>,
++ <&pericfg CLK_PERI_NFI_PAD>;
++ clock-names = "nfi_clk", "pad_clk";
++ status = "disabled";
++ ecc-engine = <&bch>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++Platform related properties, should be set in {platform_name}.dts:
++- children nodes: NAND chips.
++
++Children nodes properties:
++- reg: Chip Select Signal, default 0.
++ Set as reg = <0>, <1> when need 2 CS.
++Optional:
++- nand-on-flash-bbt: Store BBT on NAND Flash.
++- nand-ecc-mode: the NAND ecc mode (check driver for supported modes)
++- nand-ecc-step-size: Number of data bytes covered by a single ECC step.
++ The controller only supports 512 and 1024.
++ For large page NANDs ther recommended value is 1024.
++- nand-ecc-strength: Number of bits to correct per ECC step.
++ The valid values that the controller supports are: 4, 6,
++ 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44,
++ 48, 52, 56, 60.
++ The strength should be calculated as follows:
++ E = (S - F) * 8 / 14
++ S = O / (P / Q)
++ E :nand-ecc-strength;
++ S :spare size per sector;
++ F : FDM size, should be in the range [1,8].
++ It is used to store free oob data.
++ O : oob size;
++ P : page size;
++ Q :nand-ecc-step-size
++ If the result does not match any one of the listed
++ choices above, please select the smaller valid value from
++ the list.
++ (otherwise the driver will do the clamping at runtime).
++- vmch-supply: NAND power supply.
++- pinctrl-names: Default NAND pin GPIO setting name.
++- pinctrl-0: GPIO setting node.
++
++Example:
++ &pio {
++ nand_pins_default: nanddefault {
++ pins_dat {
++ pinmux = <MT2701_PIN_111_MSDC0_DAT7__FUNC_NLD7>,
++ <MT2701_PIN_112_MSDC0_DAT6__FUNC_NLD6>,
++ <MT2701_PIN_114_MSDC0_DAT4__FUNC_NLD4>,
++ <MT2701_PIN_118_MSDC0_DAT3__FUNC_NLD3>,
++ <MT2701_PIN_121_MSDC0_DAT0__FUNC_NLD0>,
++ <MT2701_PIN_120_MSDC0_DAT1__FUNC_NLD1>,
++ <MT2701_PIN_113_MSDC0_DAT5__FUNC_NLD5>,
++ <MT2701_PIN_115_MSDC0_RSTB__FUNC_NLD8>,
++ <MT2701_PIN_119_MSDC0_DAT2__FUNC_NLD2>;
++ input-enable;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up;
++ };
++
++ pins_we {
++ pinmux = <MT2701_PIN_117_MSDC0_CLK__FUNC_NWEB>;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
++ };
++
++ pins_ale {
++ pinmux = <MT2701_PIN_116_MSDC0_CMD__FUNC_NALE>;
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
++ };
++ };
++ };
++
++ &nandc {
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&nand_pins_default>;
++ nand@0 {
++ reg = <0>;
++ nand-on-flash-bbt;
++ nand-ecc-mode = "hw";
++ nand-ecc-strength = <24>;
++ nand-ecc-step-size = <1024>;
++ };
++ };
++
++NAND chip optional subnodes:
++- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
++
++Example:
++ nand@0 {
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ preloader@0 {
++ label = "pl";
++ read-only;
++ reg = <0x00000000 0x00400000>;
++ };
++ android@0x00400000 {
++ label = "android";
++ reg = <0x00400000 0x12c00000>;
++ };
++ };
++ };
++
++2) ECC Engine:
++==============
++
++Required BCH properties:
++- compatible: Should be "mediatek,mtxxxx-ecc".
++- reg: Base physical address and size of ECC.
++- interrupts: Interrupts of ECC.
++- clocks: ECC required clocks.
++- clock-names: ECC clocks internal name.
++- status: Disabled default. Then set "okay" by platform.
++
++Example:
++
++ bch: ecc@1100e000 {
++ compatible = "mediatek,mt2701-ecc";
++ reg = <0 0x1100e000 0 0x1000>;
++ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_LOW>;
++ clocks = <&pericfg CLK_PERI_NFI_ECC>;
++ clock-names = "nfiecc_clk";
++ status = "disabled";
++ };
diff --git a/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch b/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
new file mode 100644
index 0000000000..e5312eb08c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0075-mtd-mediatek-driver-for-MTK-Smart-Device-Gen1-NAND.patch
@@ -0,0 +1,2064 @@
+From de18239fc971cfc17c53320c66ae64dd5ade032d Mon Sep 17 00:00:00 2001
+From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+Date: Fri, 29 Apr 2016 12:17:22 -0400
+Subject: [PATCH 075/102] mtd: mediatek: driver for MTK Smart Device Gen1 NAND
+
+This patch adds support for mediatek's SDG1 NFC nand controller
+embedded in SoC 2701
+
+Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+---
+ drivers/mtd/nand/Kconfig | 7 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/mtk_ecc.c | 527 ++++++++++++++++
+ drivers/mtd/nand/mtk_ecc.h | 53 ++
+ drivers/mtd/nand/mtk_nand.c | 1432 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 2020 insertions(+)
+ create mode 100644 drivers/mtd/nand/mtk_ecc.c
+ create mode 100644 drivers/mtd/nand/mtk_ecc.h
+ create mode 100644 drivers/mtd/nand/mtk_nand.c
+
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -563,4 +563,11 @@ config MTD_NAND_QCOM
+ Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+ controller. This controller is found on IPQ806x SoC.
+
++config MTD_NAND_MTK
++ tristate "Support for NAND controller on MTK SoCs"
++ depends on HAS_DMA
++ help
++ Enables support for NAND controller on MTK SoCs.
++ This controller is found on mt27xx, mt81xx, mt65xx SoCs.
++
+ endif # MTD_NAND
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -57,5 +57,6 @@ obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_n
+ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
+ obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
++obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_ecc.c
+@@ -0,0 +1,527 @@
++/*
++ * MTK ECC controller driver.
++ * Copyright (C) 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/clk.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/semaphore.h>
++
++#include "mtk_ecc.h"
++
++#define ECC_ENCCON (0x00)
++#define ENC_EN (1)
++#define ENC_DE (0)
++#define ECC_ENCCNFG (0x04)
++#define ECC_CNFG_4BIT (0)
++#define ECC_CNFG_6BIT (1)
++#define ECC_CNFG_8BIT (2)
++#define ECC_CNFG_10BIT (3)
++#define ECC_CNFG_12BIT (4)
++#define ECC_CNFG_14BIT (5)
++#define ECC_CNFG_16BIT (6)
++#define ECC_CNFG_18BIT (7)
++#define ECC_CNFG_20BIT (8)
++#define ECC_CNFG_22BIT (9)
++#define ECC_CNFG_24BIT (0xa)
++#define ECC_CNFG_28BIT (0xb)
++#define ECC_CNFG_32BIT (0xc)
++#define ECC_CNFG_36BIT (0xd)
++#define ECC_CNFG_40BIT (0xe)
++#define ECC_CNFG_44BIT (0xf)
++#define ECC_CNFG_48BIT (0x10)
++#define ECC_CNFG_52BIT (0x11)
++#define ECC_CNFG_56BIT (0x12)
++#define ECC_CNFG_60BIT (0x13)
++#define ECC_MODE_SHIFT (5)
++#define ECC_MS_SHIFT (16)
++#define ECC_ENCDIADDR (0x08)
++#define ECC_ENCIDLE (0x0C)
++#define ENC_IDLE BIT(0)
++#define ECC_ENCPAR(x) (0x10 + (x) * sizeof(u32))
++#define ECC_ENCIRQ_EN (0x80)
++#define ENC_IRQEN BIT(0)
++#define ECC_ENCIRQ_STA (0x84)
++#define ECC_DECCON (0x100)
++#define DEC_EN (1)
++#define DEC_DE (0)
++#define ECC_DECCNFG (0x104)
++#define DEC_EMPTY_EN BIT(31)
++#define DEC_CNFG_CORRECT (0x3 << 12)
++#define ECC_DECIDLE (0x10C)
++#define DEC_IDLE BIT(0)
++#define ECC_DECENUM0 (0x114)
++#define ERR_MASK (0x3f)
++#define ECC_DECDONE (0x124)
++#define ECC_DECIRQ_EN (0x200)
++#define DEC_IRQEN BIT(0)
++#define ECC_DECIRQ_STA (0x204)
++
++#define ECC_TIMEOUT (500000)
++
++#define ECC_IDLE_REG(x) ((x) == ECC_ENC ? ECC_ENCIDLE : ECC_DECIDLE)
++#define ECC_IDLE_MASK(x) ((x) == ECC_ENC ? ENC_IDLE : DEC_IDLE)
++#define ECC_IRQ_REG(x) ((x) == ECC_ENC ? ECC_ENCIRQ_EN : ECC_DECIRQ_EN)
++#define ECC_IRQ_EN(x) ((x) == ECC_ENC ? ENC_IRQEN : DEC_IRQEN)
++#define ECC_CTL_REG(x) ((x) == ECC_ENC ? ECC_ENCCON : ECC_DECCON)
++#define ECC_CODEC_ENABLE(x) ((x) == ECC_ENC ? ENC_EN : DEC_EN)
++#define ECC_CODEC_DISABLE(x) ((x) == ECC_ENC ? ENC_DE : DEC_DE)
++
++struct mtk_ecc {
++ struct device *dev;
++ void __iomem *regs;
++ struct clk *clk;
++
++ struct completion done;
++ struct semaphore sem;
++ u32 sec_mask;
++};
++
++static inline void mtk_ecc_codec_wait_idle(struct mtk_ecc *ecc,
++ enum mtk_ecc_codec codec)
++{
++ struct device *dev = ecc->dev;
++ u32 val;
++ int ret;
++
++ ret = readl_poll_timeout_atomic(ecc->regs + ECC_IDLE_REG(codec), val,
++ val & ECC_IDLE_MASK(codec),
++ 10, ECC_TIMEOUT);
++ if (ret)
++ dev_warn(dev, "%s NOT idle\n",
++ codec == ECC_ENC ? "encoder" : "decoder");
++}
++
++static irqreturn_t mtk_ecc_irq(int irq, void *id)
++{
++ struct mtk_ecc *ecc = id;
++ enum mtk_ecc_codec codec;
++ u32 dec, enc;
++
++ dec = readw(ecc->regs + ECC_DECIRQ_STA) & DEC_IRQEN;
++ if (dec) {
++ codec = ECC_DEC;
++ dec = readw(ecc->regs + ECC_DECDONE);
++ if (dec & ecc->sec_mask) {
++ ecc->sec_mask = 0;
++ complete(&ecc->done);
++ } else
++ return IRQ_HANDLED;
++ } else {
++ enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ENC_IRQEN;
++ if (enc) {
++ codec = ECC_ENC;
++ complete(&ecc->done);
++ } else
++ return IRQ_NONE;
++ }
++
++ writel(0, ecc->regs + ECC_IRQ_REG(codec));
++
++ return IRQ_HANDLED;
++}
++
++static void mtk_ecc_config(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ u32 ecc_bit = ECC_CNFG_4BIT, dec_sz, enc_sz;
++ u32 reg;
++
++ switch (config->strength) {
++ case 4:
++ ecc_bit = ECC_CNFG_4BIT;
++ break;
++ case 6:
++ ecc_bit = ECC_CNFG_6BIT;
++ break;
++ case 8:
++ ecc_bit = ECC_CNFG_8BIT;
++ break;
++ case 10:
++ ecc_bit = ECC_CNFG_10BIT;
++ break;
++ case 12:
++ ecc_bit = ECC_CNFG_12BIT;
++ break;
++ case 14:
++ ecc_bit = ECC_CNFG_14BIT;
++ break;
++ case 16:
++ ecc_bit = ECC_CNFG_16BIT;
++ break;
++ case 18:
++ ecc_bit = ECC_CNFG_18BIT;
++ break;
++ case 20:
++ ecc_bit = ECC_CNFG_20BIT;
++ break;
++ case 22:
++ ecc_bit = ECC_CNFG_22BIT;
++ break;
++ case 24:
++ ecc_bit = ECC_CNFG_24BIT;
++ break;
++ case 28:
++ ecc_bit = ECC_CNFG_28BIT;
++ break;
++ case 32:
++ ecc_bit = ECC_CNFG_32BIT;
++ break;
++ case 36:
++ ecc_bit = ECC_CNFG_36BIT;
++ break;
++ case 40:
++ ecc_bit = ECC_CNFG_40BIT;
++ break;
++ case 44:
++ ecc_bit = ECC_CNFG_44BIT;
++ break;
++ case 48:
++ ecc_bit = ECC_CNFG_48BIT;
++ break;
++ case 52:
++ ecc_bit = ECC_CNFG_52BIT;
++ break;
++ case 56:
++ ecc_bit = ECC_CNFG_56BIT;
++ break;
++ case 60:
++ ecc_bit = ECC_CNFG_60BIT;
++ break;
++ default:
++ dev_err(ecc->dev, "invalid strength %d\n", config->strength);
++ }
++
++ if (config->codec == ECC_ENC) {
++ /* configure ECC encoder (in bits) */
++ enc_sz = config->enc_len << 3;
++
++ reg = ecc_bit | (config->ecc_mode << ECC_MODE_SHIFT);
++ reg |= (enc_sz << ECC_MS_SHIFT);
++ writel(reg, ecc->regs + ECC_ENCCNFG);
++
++ if (config->ecc_mode != ECC_NFI_MODE)
++ writel(lower_32_bits(config->addr),
++ ecc->regs + ECC_ENCDIADDR);
++
++ } else {
++ /* configure ECC decoder (in bits) */
++ dec_sz = config->dec_len;
++
++ reg = ecc_bit | (config->ecc_mode << ECC_MODE_SHIFT);
++ reg |= (dec_sz << ECC_MS_SHIFT) | DEC_CNFG_CORRECT;
++ reg |= DEC_EMPTY_EN;
++ writel(reg, ecc->regs + ECC_DECCNFG);
++
++ if (config->sec_mask)
++ ecc->sec_mask = 1 << (config->sec_mask - 1);
++ }
++}
++
++void mtk_ecc_get_stats(struct mtk_ecc *ecc, struct mtk_ecc_stats *stats,
++ int sectors)
++{
++ u32 offset, i, err;
++ u32 bitflips = 0;
++
++ stats->corrected = 0;
++ stats->failed = 0;
++
++ for (i = 0; i < sectors; i++) {
++ offset = (i >> 2) << 2;
++ err = readl(ecc->regs + ECC_DECENUM0 + offset);
++ err = err >> ((i % 4) * 8);
++ err &= ERR_MASK;
++ if (err == ERR_MASK) {
++ /* uncorrectable errors */
++ stats->failed++;
++ continue;
++ }
++
++ stats->corrected += err;
++ bitflips = max_t(u32, bitflips, err);
++ }
++
++ stats->bitflips = bitflips;
++}
++EXPORT_SYMBOL(mtk_ecc_get_stats);
++
++void mtk_ecc_release(struct mtk_ecc *ecc)
++{
++ clk_disable_unprepare(ecc->clk);
++ put_device(ecc->dev);
++}
++EXPORT_SYMBOL(mtk_ecc_release);
++
++static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
++{
++ struct platform_device *pdev;
++ struct mtk_ecc *ecc;
++
++ pdev = of_find_device_by_node(np);
++ if (!pdev || !platform_get_drvdata(pdev))
++ return ERR_PTR(-EPROBE_DEFER);
++
++ get_device(&pdev->dev);
++ ecc = platform_get_drvdata(pdev);
++ clk_prepare_enable(ecc->clk);
++ mtk_ecc_hw_init(ecc);
++
++ return ecc;
++}
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *of_node)
++{
++ struct mtk_ecc *ecc = NULL;
++ struct device_node *np;
++
++ np = of_parse_phandle(of_node, "ecc-engine", 0);
++ if (np) {
++ ecc = mtk_ecc_get(np);
++ of_node_put(np);
++ }
++
++ return ecc;
++}
++EXPORT_SYMBOL(of_mtk_ecc_get);
++
++int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ enum mtk_ecc_codec codec = config->codec;
++ int ret;
++
++ ret = down_interruptible(&ecc->sem);
++ if (ret) {
++ dev_err(ecc->dev, "interrupted when attempting to lock\n");
++ return ret;
++ }
++
++ mtk_ecc_codec_wait_idle(ecc, codec);
++ mtk_ecc_config(ecc, config);
++ writew(ECC_CODEC_ENABLE(codec), ecc->regs + ECC_CTL_REG(codec));
++
++ init_completion(&ecc->done);
++ writew(ECC_IRQ_EN(codec), ecc->regs + ECC_IRQ_REG(codec));
++
++ return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_enable);
++
++void mtk_ecc_disable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
++{
++ enum mtk_ecc_codec codec = config->codec;
++
++ mtk_ecc_codec_wait_idle(ecc, codec);
++ writew(0, ecc->regs + ECC_IRQ_REG(codec));
++ writew(ECC_CODEC_DISABLE(codec), ecc->regs + ECC_CTL_REG(codec));
++ up(&ecc->sem);
++}
++EXPORT_SYMBOL(mtk_ecc_disable);
++
++int mtk_ecc_wait_irq_done(struct mtk_ecc *ecc, enum mtk_ecc_codec codec)
++{
++ int ret;
++
++ ret = wait_for_completion_timeout(&ecc->done, msecs_to_jiffies(500));
++ if (!ret) {
++ dev_err(ecc->dev, "%s timeout - interrupt did not arrive)\n",
++ (codec == ECC_ENC) ? "encoder" : "decoder");
++ return -ETIMEDOUT;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(mtk_ecc_wait_irq_done);
++
++int mtk_ecc_encode_non_nfi_mode(struct mtk_ecc *ecc,
++ struct mtk_ecc_config *config, u8 *data, u32 bytes)
++{
++ dma_addr_t addr;
++ u32 *p, len, i;
++ int ret = 0;
++
++ addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE);
++ ret = dma_mapping_error(ecc->dev, addr);
++ if (ret) {
++ dev_err(ecc->dev, "dma mapping error\n");
++ return -EINVAL;
++ }
++
++ config->codec = ECC_ENC;
++ config->addr = addr;
++ ret = mtk_ecc_enable(ecc, config);
++ if (ret) {
++ dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
++ return ret;
++ }
++
++ ret = mtk_ecc_wait_irq_done(ecc, ECC_ENC);
++ if (ret)
++ goto timeout;
++
++ mtk_ecc_codec_wait_idle(ecc, ECC_ENC);
++
++ /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
++ len = (config->strength * ECC_PARITY_BITS + 7) >> 3;
++ p = (u32 *) (data + bytes);
++
++ /* write the parity bytes generated by the ECC back to the OOB region */
++ for (i = 0; i < len; i++)
++ p[i] = readl(ecc->regs + ECC_ENCPAR(i));
++timeout:
++
++ dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE);
++ mtk_ecc_disable(ecc, config);
++
++ return ret;
++}
++EXPORT_SYMBOL(mtk_ecc_encode_non_nfi_mode);
++
++void mtk_ecc_hw_init(struct mtk_ecc *ecc)
++{
++ mtk_ecc_codec_wait_idle(ecc, ECC_ENC);
++ writew(ENC_DE, ecc->regs + ECC_ENCCON);
++
++ mtk_ecc_codec_wait_idle(ecc, ECC_DEC);
++ writel(DEC_DE, ecc->regs + ECC_DECCON);
++}
++
++void mtk_ecc_update_strength(u32 *p)
++{
++ u32 ecc[] = {4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36,
++ 40, 44, 48, 52, 56, 60};
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ecc); i++) {
++ if (*p <= ecc[i]) {
++ if (!i)
++ *p = ecc[i];
++ else if (*p != ecc[i])
++ *p = ecc[i - 1];
++ return;
++ }
++ }
++
++ *p = ecc[ARRAY_SIZE(ecc) - 1];
++}
++EXPORT_SYMBOL(mtk_ecc_update_strength);
++
++static int mtk_ecc_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct mtk_ecc *ecc;
++ struct resource *res;
++ int irq, ret;
++
++ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
++ if (!ecc)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ecc->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ecc->regs)) {
++ dev_err(dev, "failed to map regs: %ld\n", PTR_ERR(ecc->regs));
++ return PTR_ERR(ecc->regs);
++ }
++
++ ecc->clk = devm_clk_get(dev, NULL);
++ if (IS_ERR(ecc->clk)) {
++ dev_err(dev, "failed to get clock: %ld\n", PTR_ERR(ecc->clk));
++ return PTR_ERR(ecc->clk);
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(dev, "failed to get irq\n");
++ return -EINVAL;
++ }
++
++ ret = dma_set_mask(dev, DMA_BIT_MASK(32));
++ if (ret) {
++ dev_err(dev, "failed to set DMA mask\n");
++ return ret;
++ }
++
++ ret = devm_request_irq(dev, irq, mtk_ecc_irq, 0x0, "mtk-ecc", ecc);
++ if (ret) {
++ dev_err(dev, "failed to request irq\n");
++ return -EINVAL;
++ }
++
++ ecc->dev = dev;
++ sema_init(&ecc->sem, 1);
++ platform_set_drvdata(pdev, ecc);
++ dev_info(dev, "probed\n");
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_ecc_suspend(struct device *dev)
++{
++ struct mtk_ecc *ecc = dev_get_drvdata(dev);
++
++ clk_disable_unprepare(ecc->clk);
++
++ return 0;
++}
++
++static int mtk_ecc_resume(struct device *dev)
++{
++ struct mtk_ecc *ecc = dev_get_drvdata(dev);
++ int ret;
++
++ ret = clk_prepare_enable(ecc->clk);
++ if (ret) {
++ dev_err(dev, "failed to enable clk\n");
++ return ret;
++ }
++
++ mtk_ecc_hw_init(ecc);
++
++ return 0;
++}
++
++static SIMPLE_DEV_PM_OPS(mtk_ecc_pm_ops, mtk_ecc_suspend, mtk_ecc_resume);
++#endif
++
++static const struct of_device_id mtk_ecc_dt_match[] = {
++ { .compatible = "mediatek,mt2701-ecc" },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, mtk_ecc_dt_match);
++
++static struct platform_driver mtk_ecc_driver = {
++ .probe = mtk_ecc_probe,
++ .driver = {
++ .name = "mtk-ecc",
++ .of_match_table = of_match_ptr(mtk_ecc_dt_match),
++#ifdef CONFIG_PM_SLEEP
++ .pm = &mtk_ecc_pm_ops,
++#endif
++ },
++};
++
++module_platform_driver(mtk_ecc_driver);
++
++MODULE_AUTHOR("Xiaolei Li <xiaolei.li@mediatek.com>");
++MODULE_AUTHOR("Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>");
++MODULE_DESCRIPTION("MTK Nand ECC Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_ecc.h
+@@ -0,0 +1,53 @@
++/*
++ * MTK SDG1 ECC controller
++ *
++ * Copyright (c) 2016 Mediatek
++ * 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.
++ */
++
++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__
++#define __DRIVERS_MTD_NAND_MTK_ECC_H__
++
++#include <linux/types.h>
++
++#define ECC_PARITY_BITS (14)
++
++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1};
++enum mtk_ecc_codec {ECC_ENC, ECC_DEC};
++
++struct device_node;
++struct mtk_ecc;
++
++struct mtk_ecc_stats {
++ u32 corrected;
++ u32 bitflips;
++ u32 failed;
++};
++
++struct mtk_ecc_config {
++ enum mtk_ecc_mode ecc_mode;
++ enum mtk_ecc_codec codec;
++ dma_addr_t addr;
++ u32 sec_mask;
++ u32 strength;
++ u32 enc_len;
++ u32 dec_len;
++};
++
++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *);
++void mtk_ecc_disable(struct mtk_ecc *, struct mtk_ecc_config *);
++int mtk_ecc_encode_non_nfi_mode(struct mtk_ecc *, struct mtk_ecc_config *,
++ u8 *, u32);
++void mtk_ecc_get_stats(struct mtk_ecc *, struct mtk_ecc_stats *, int);
++int mtk_ecc_wait_irq_done(struct mtk_ecc *, enum mtk_ecc_codec);
++void mtk_ecc_hw_init(struct mtk_ecc *);
++void mtk_ecc_update_strength(u32 *);
++
++struct mtk_ecc *of_mtk_ecc_get(struct device_node *);
++void mtk_ecc_release(struct mtk_ecc *);
++
++#endif
+--- /dev/null
++++ b/drivers/mtd/nand/mtk_nand.c
+@@ -0,0 +1,1432 @@
++/*
++ * MTK NAND Flash controller driver.
++ * Copyright (C) 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/delay.h>
++#include <linux/clk.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/module.h>
++#include <linux/iopoll.h>
++#include <linux/of.h>
++#include "mtk_ecc.h"
++
++/* NAND controller register definition */
++#define 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_CUST (6 << 12)
++#define NFI_PAGEFMT (0x04)
++#define PAGEFMT_FDM_ECC_SHIFT (12)
++#define PAGEFMT_FDM_SHIFT (8)
++#define PAGEFMT_SPARE_16 (0)
++#define PAGEFMT_SPARE_26 (1)
++#define PAGEFMT_SPARE_27 (2)
++#define PAGEFMT_SPARE_28 (3)
++#define PAGEFMT_SPARE_32 (4)
++#define PAGEFMT_SPARE_36 (5)
++#define PAGEFMT_SPARE_40 (6)
++#define PAGEFMT_SPARE_44 (7)
++#define PAGEFMT_SPARE_48 (8)
++#define PAGEFMT_SPARE_49 (9)
++#define PAGEFMT_SPARE_50 (0xa)
++#define PAGEFMT_SPARE_51 (0xb)
++#define PAGEFMT_SPARE_52 (0xc)
++#define PAGEFMT_SPARE_62 (0xd)
++#define PAGEFMT_SPARE_63 (0xe)
++#define PAGEFMT_SPARE_64 (0xf)
++#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)
++#define PAGEFMT_8K_16K (3)
++/* NFI control */
++#define NFI_CON (0x08)
++#define CON_FIFO_FLUSH BIT(0)
++#define CON_NFI_RST BIT(1)
++#define CON_BRD BIT(8) /* burst read */
++#define CON_BWR BIT(9) /* burst write */
++#define CON_SEC_SHIFT (12)
++/* Timming control register */
++#define NFI_ACCCON (0x0C)
++#define NFI_INTR_EN (0x10)
++#define INTR_AHB_DONE_EN BIT(6)
++#define NFI_INTR_STA (0x14)
++#define NFI_CMD (0x20)
++#define NFI_ADDRNOB (0x30)
++#define NFI_COLADDR (0x34)
++#define NFI_ROWADDR (0x38)
++#define NFI_STRDATA (0x40)
++#define STAR_EN (1)
++#define STAR_DE (0)
++#define NFI_CNRNB (0x44)
++#define NFI_DATAW (0x50)
++#define NFI_DATAR (0x54)
++#define NFI_PIO_DIRDY (0x58)
++#define PIO_DI_RDY (0x01)
++#define NFI_STA (0x60)
++#define STA_CMD BIT(0)
++#define STA_ADDR BIT(1)
++#define STA_BUSY BIT(8)
++#define STA_EMP_PAGE BIT(12)
++#define NFI_FSM_CUSTDATA (0xe << 16)
++#define NFI_FSM_MASK (0xf << 16)
++#define NFI_ADDRCNTR (0x70)
++#define CNTR_MASK GENMASK(16, 12)
++#define NFI_STRADDR (0x80)
++#define NFI_BYTELEN (0x84)
++#define NFI_CSEL (0x90)
++#define NFI_FDML(x) (0xA0 + (x) * sizeof(u32) * 2)
++#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
++#define NFI_FDM_MAX_SIZE (8)
++#define NFI_MASTER_STA (0x224)
++#define MASTER_STA_MASK (0x0FFF)
++#define NFI_EMPTY_THRESH (0x23C)
++
++#define MTK_NAME "mtk-nand"
++#define KB(x) ((x) * 1024UL)
++#define MB(x) (KB(x) * 1024UL)
++
++#define MTK_TIMEOUT (500000)
++#define MTK_RESET_TIMEOUT (1000000)
++#define MTK_MAX_SECTOR (16)
++#define MTK_NAND_MAX_NSELS (2)
++
++typedef void (*bad_mark_swap)(struct mtd_info *, uint8_t *buf, int raw);
++struct mtk_nfc_bad_mark_ctl {
++ bad_mark_swap bm_swap;
++ u32 sec;
++ u32 pos;
++};
++
++/*
++ * FDM: region used to store free OOB data
++ */
++struct mtk_nfc_fdm {
++ u32 reg_size;
++ u32 ecc_size;
++};
++
++struct mtk_nfc_nand_chip {
++ struct list_head node;
++ struct nand_chip nand;
++
++ struct mtk_nfc_bad_mark_ctl bad_mark;
++ struct mtk_nfc_fdm fdm;
++ u32 spare_per_sector;
++
++ int nsels;
++ u8 sels[0];
++ /* nothing after this field */
++};
++
++struct mtk_nfc_clk {
++ struct clk *nfi_clk;
++ struct clk *pad_clk;
++};
++
++struct mtk_nfc {
++ struct nand_hw_control controller;
++ struct mtk_ecc_config ecc_cfg;
++ struct mtk_nfc_clk clk;
++ struct mtk_ecc *ecc;
++
++ struct device *dev;
++ void __iomem *regs;
++
++ struct completion done;
++ struct list_head chips;
++
++ u8 *buffer;
++};
++
++static inline struct mtk_nfc_nand_chip *to_mtk_nand(struct nand_chip *nand)
++{
++ return container_of(nand, struct mtk_nfc_nand_chip, nand);
++}
++
++static inline uint8_t *data_ptr(struct nand_chip *chip, const uint8_t *p, int i)
++{
++ return (uint8_t *) p + i * chip->ecc.size;
++}
++
++static inline uint8_t *oob_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ uint8_t *poi;
++
++ if (i < mtk_nand->bad_mark.sec)
++ poi = chip->oob_poi + (i + 1) * mtk_nand->fdm.reg_size;
++ else if (i == mtk_nand->bad_mark.sec)
++ poi = chip->oob_poi;
++ else
++ poi = chip->oob_poi + i * mtk_nand->fdm.reg_size;
++
++ return poi;
++}
++
++static inline int mtk_data_len(struct nand_chip *chip)
++{
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++
++ return chip->ecc.size + mtk_nand->spare_per_sector;
++}
++
++static inline uint8_t *mtk_data_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++ return nfc->buffer + i * mtk_data_len(chip);
++}
++
++static inline uint8_t *mtk_oob_ptr(struct nand_chip *chip, int i)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++
++ return nfc->buffer + i * mtk_data_len(chip) + chip->ecc.size;
++}
++
++static inline void nfi_writel(struct mtk_nfc *nfc, u32 val, u32 reg)
++{
++ writel(val, nfc->regs + reg);
++}
++
++static inline void nfi_writew(struct mtk_nfc *nfc, u16 val, u32 reg)
++{
++ writew(val, nfc->regs + reg);
++}
++
++static inline void nfi_writeb(struct mtk_nfc *nfc, u8 val, u32 reg)
++{
++ writeb(val, nfc->regs + reg);
++}
++
++static inline u32 nfi_readl(struct mtk_nfc *nfc, u32 reg)
++{
++ return readl_relaxed(nfc->regs + reg);
++}
++
++static inline u16 nfi_readw(struct mtk_nfc *nfc, u32 reg)
++{
++ return readw_relaxed(nfc->regs + reg);
++}
++
++static inline u8 nfi_readb(struct mtk_nfc *nfc, u32 reg)
++{
++ return readb_relaxed(nfc->regs + reg);
++}
++
++static void mtk_nfc_hw_reset(struct mtk_nfc *nfc)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ /* reset all registers and force the NFI master to terminate */
++ nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++
++ /* wait for the master to finish the last transaction */
++ ret = readl_poll_timeout(nfc->regs + NFI_MASTER_STA, val,
++ !(val & MASTER_STA_MASK), 50, MTK_RESET_TIMEOUT);
++ if (ret)
++ dev_warn(dev, "master active in reset [0x%x] = 0x%x\n",
++ NFI_MASTER_STA, val);
++
++ /* ensure any status register affected by the NFI master is reset */
++ nfi_writel(nfc, CON_FIFO_FLUSH | CON_NFI_RST, NFI_CON);
++ nfi_writew(nfc, STAR_DE, NFI_STRDATA);
++}
++
++static int mtk_nfc_send_command(struct mtk_nfc *nfc, u8 command)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ nfi_writel(nfc, command, NFI_CMD);
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++ !(val & STA_CMD), 10, MTK_TIMEOUT);
++ if (ret) {
++ dev_warn(dev, "nfi core timed out entering command mode\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_send_address(struct mtk_nfc *nfc, int addr)
++{
++ struct device *dev = nfc->dev;
++ u32 val;
++ int ret;
++
++ nfi_writel(nfc, addr, NFI_COLADDR);
++ nfi_writel(nfc, 0, NFI_ROWADDR);
++ nfi_writew(nfc, 1, NFI_ADDRNOB);
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_STA, val,
++ !(val & STA_ADDR), 10, MTK_TIMEOUT);
++ if (ret) {
++ dev_warn(dev, "nfi core timed out entering address mode\n");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_hw_runtime_config(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 fmt, spare;
++
++ if (!mtd->writesize)
++ return 0;
++
++ spare = mtk_nand->spare_per_sector;
++
++ switch (mtd->writesize) {
++ case 512:
++ fmt = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
++ break;
++ case KB(2):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_512_2K;
++ break;
++ case KB(4):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_2K_4K;
++ break;
++ case KB(8):
++ if (chip->ecc.size == 512)
++ fmt = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
++ else
++ fmt = PAGEFMT_4K_8K;
++ break;
++ case KB(16):
++ fmt = PAGEFMT_8K_16K;
++ break;
++ default:
++ dev_err(nfc->dev, "invalid page len: %d\n", mtd->writesize);
++ return -EINVAL;
++ }
++
++ /* the hardware doubles the value for this eccsize so let's halve it */
++ if (chip->ecc.size == 1024)
++ spare >>= 1;
++
++ switch (spare) {
++ case 16:
++ fmt |= (PAGEFMT_SPARE_16 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 26:
++ fmt |= (PAGEFMT_SPARE_26 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 27:
++ fmt |= (PAGEFMT_SPARE_27 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 28:
++ fmt |= (PAGEFMT_SPARE_28 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 32:
++ fmt |= (PAGEFMT_SPARE_32 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 36:
++ fmt |= (PAGEFMT_SPARE_36 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 40:
++ fmt |= (PAGEFMT_SPARE_40 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 44:
++ fmt |= (PAGEFMT_SPARE_44 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 48:
++ fmt |= (PAGEFMT_SPARE_48 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 49:
++ fmt |= (PAGEFMT_SPARE_49 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 50:
++ fmt |= (PAGEFMT_SPARE_50 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 51:
++ fmt |= (PAGEFMT_SPARE_51 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 52:
++ fmt |= (PAGEFMT_SPARE_52 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 62:
++ fmt |= (PAGEFMT_SPARE_62 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 63:
++ fmt |= (PAGEFMT_SPARE_63 << PAGEFMT_SPARE_SHIFT);
++ break;
++ case 64:
++ fmt |= (PAGEFMT_SPARE_64 << PAGEFMT_SPARE_SHIFT);
++ break;
++ default:
++ dev_err(nfc->dev, "invalid spare per sector %d\n", spare);
++ return -EINVAL;
++ }
++
++ fmt |= mtk_nand->fdm.reg_size << PAGEFMT_FDM_SHIFT;
++ fmt |= mtk_nand->fdm.ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++ nfi_writew(nfc, fmt, NFI_PAGEFMT);
++
++ nfc->ecc_cfg.strength = chip->ecc.strength;
++ nfc->ecc_cfg.enc_len = chip->ecc.size + mtk_nand->fdm.ecc_size;
++ nfc->ecc_cfg.dec_len = (nfc->ecc_cfg.enc_len << 3)
++ + chip->ecc.strength * ECC_PARITY_BITS;
++
++ return 0;
++}
++
++static void mtk_nfc_select_chip(struct mtd_info *mtd, int chip)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(nand);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(nand);
++
++ if (chip < 0)
++ return;
++
++ mtk_nfc_hw_runtime_config(mtd);
++
++ nfi_writel(nfc, mtk_nand->sels[chip], NFI_CSEL);
++}
++
++static int mtk_nfc_dev_ready(struct mtd_info *mtd)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++ if (nfi_readl(nfc, NFI_STA) & STA_BUSY)
++ return 0;
++
++ return 1;
++}
++
++static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++
++ if (ctrl & NAND_ALE)
++ mtk_nfc_send_address(nfc, dat);
++ else if (ctrl & NAND_CLE) {
++ mtk_nfc_hw_reset(nfc);
++
++ nfi_writew(nfc, CNFG_OP_CUST, NFI_CNFG);
++ mtk_nfc_send_command(nfc, dat);
++ }
++}
++
++static inline void mtk_nfc_wait_ioready(struct mtk_nfc *nfc)
++{
++ int rc;
++ u8 val;
++
++ rc = readb_poll_timeout_atomic(nfc->regs + NFI_PIO_DIRDY, val,
++ val & PIO_DI_RDY, 10, MTK_TIMEOUT);
++ if (rc < 0)
++ dev_err(nfc->dev, "data not ready\n");
++}
++
++static inline uint8_t mtk_nfc_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 reg;
++
++ reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++ if (reg != NFI_FSM_CUSTDATA) {
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg |= CNFG_BYTE_RW | CNFG_READ_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ reg = (MTK_MAX_SECTOR << CON_SEC_SHIFT) | CON_BRD;
++ nfi_writel(nfc, reg, NFI_CON);
++
++ /* trigger to fetch data */
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++ }
++
++ mtk_nfc_wait_ioready(nfc);
++
++ return nfi_readb(nfc, NFI_DATAR);
++}
++
++static void mtk_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ int i;
++
++ for (i = 0; i < len; i++)
++ buf[i] = mtk_nfc_read_byte(mtd);
++}
++
++static void mtk_nfc_write_byte(struct mtd_info *mtd, uint8_t byte)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
++ u32 reg;
++
++ reg = nfi_readl(nfc, NFI_STA) & NFI_FSM_MASK;
++
++ if (reg != NFI_FSM_CUSTDATA) {
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_BYTE_RW;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ reg = MTK_MAX_SECTOR << CON_SEC_SHIFT | CON_BWR;
++ nfi_writel(nfc, reg, NFI_CON);
++
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++ }
++
++ mtk_nfc_wait_ioready(nfc);
++ nfi_writeb(nfc, byte, NFI_DATAW);
++}
++
++static void mtk_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
++{
++ int i;
++
++ for (i = 0; i < len; i++)
++ mtk_nfc_write_byte(mtd, buf[i]);
++}
++
++static int mtk_nfc_sector_encode(struct nand_chip *chip, u8 *data)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ int size = chip->ecc.size + mtk_nand->fdm.reg_size;
++
++ nfc->ecc_cfg.ecc_mode = ECC_DMA_MODE;
++ nfc->ecc_cfg.codec = ECC_ENC;
++ return mtk_ecc_encode_non_nfi_mode(nfc->ecc, &nfc->ecc_cfg, data, size);
++}
++
++static void mtk_nfc_no_bad_mark_swap(struct mtd_info *a, uint8_t *b, int c)
++{
++ /* nope */
++}
++
++static void mtk_nfc_bad_mark_swap(struct mtd_info *mtd, uint8_t *buf, int raw)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
++ u32 bad_pos = nand->bad_mark.pos;
++
++ if (raw)
++ bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
++ else
++ bad_pos += nand->bad_mark.sec * chip->ecc.size;
++
++ swap(chip->oob_poi[0], buf[bad_pos]);
++}
++
++static int mtk_nfc_format_subpage(struct mtd_info *mtd, uint32_t offset,
++ uint32_t len, const uint8_t *buf)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 start, end;
++ int i, ret;
++
++ start = offset / chip->ecc.size;
++ end = DIV_ROUND_UP(offset + len, chip->ecc.size);
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ for (i = 0; i < chip->ecc.steps; i++) {
++
++ memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++ chip->ecc.size);
++
++ if (start > i || i >= end)
++ continue;
++
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++
++ /* program the CRC back to the OOB */
++ ret = mtk_nfc_sector_encode(chip, mtk_data_ptr(chip, i));
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++static void mtk_nfc_format_page(struct mtd_info *mtd, const uint8_t *buf)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 i;
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ for (i = 0; i < chip->ecc.steps; i++) {
++ if (buf)
++ memcpy(mtk_data_ptr(chip, i), data_ptr(chip, buf, i),
++ chip->ecc.size);
++
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ memcpy(mtk_oob_ptr(chip, i), oob_ptr(chip, i), fdm->reg_size);
++ }
++}
++
++static inline void mtk_nfc_read_fdm(struct nand_chip *chip, u32 start,
++ u32 sectors)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 *p;
++ int i;
++
++ for (i = 0; i < sectors; i++) {
++ p = (u32 *) oob_ptr(chip, start + i);
++ p[0] = nfi_readl(nfc, NFI_FDML(i));
++ p[1] = nfi_readl(nfc, NFI_FDMM(i));
++ }
++}
++
++static inline void mtk_nfc_write_fdm(struct nand_chip *chip)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ u32 *p;
++ int i;
++
++ for (i = 0; i < chip->ecc.steps ; i++) {
++ p = (u32 *) oob_ptr(chip, i);
++ nfi_writel(nfc, p[0], NFI_FDML(i));
++ nfi_writel(nfc, p[1], NFI_FDMM(i));
++ }
++}
++
++static int mtk_nfc_do_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int len)
++{
++
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct device *dev = nfc->dev;
++ dma_addr_t addr;
++ u32 reg;
++ int ret;
++
++ addr = dma_map_single(dev, (void *) buf, len, DMA_TO_DEVICE);
++ ret = dma_mapping_error(nfc->dev, addr);
++ if (ret) {
++ dev_err(nfc->dev, "dma mapping error\n");
++ return -EINVAL;
++ }
++
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AHB | CNFG_DMA_BURST_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfi_writel(nfc, chip->ecc.steps << CON_SEC_SHIFT, NFI_CON);
++ nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++ nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++
++ init_completion(&nfc->done);
++
++ reg = nfi_readl(nfc, NFI_CON) | CON_BWR;
++ nfi_writel(nfc, reg, NFI_CON);
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++ ret = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++ if (!ret) {
++ dev_err(dev, "program ahb done timeout\n");
++ nfi_writew(nfc, 0, NFI_INTR_EN);
++ ret = -ETIMEDOUT;
++ goto timeout;
++ }
++
++ ret = readl_poll_timeout_atomic(nfc->regs + NFI_ADDRCNTR, reg,
++ (reg & CNTR_MASK) >= chip->ecc.steps, 10, MTK_TIMEOUT);
++ if (ret)
++ dev_err(dev, "hwecc write timeout\n");
++
++timeout:
++
++ dma_unmap_single(nfc->dev, addr, len, DMA_TO_DEVICE);
++ nfi_writel(nfc, 0, NFI_CON);
++
++ return ret;
++}
++
++static int mtk_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int page, int raw)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ size_t len;
++ const u8 *bufpoi;
++ u32 reg;
++ int ret;
++
++ if (!raw) {
++ /* OOB => FDM: from register, ECC: from HW */
++ reg = nfi_readw(nfc, NFI_CNFG) | CNFG_AUTO_FMT_EN;
++ nfi_writew(nfc, reg | CNFG_HW_ECC_EN, NFI_CNFG);
++
++ nfc->ecc_cfg.codec = ECC_ENC;
++ nfc->ecc_cfg.ecc_mode = ECC_NFI_MODE;
++ ret = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++ if (ret) {
++ /* clear NFI config */
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg &= ~(CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ return ret;
++ }
++
++ memcpy(nfc->buffer, buf, mtd->writesize);
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, raw);
++ bufpoi = nfc->buffer;
++
++ /* write OOB into the FDM registers (OOB area in MTK NAND) */
++ mtk_nfc_write_fdm(chip);
++ } else
++ bufpoi = buf;
++
++ len = mtd->writesize + (raw ? mtd->oobsize : 0);
++ ret = mtk_nfc_do_write_page(mtd, chip, bufpoi, page, len);
++
++ if (!raw)
++ mtk_ecc_disable(nfc->ecc, &nfc->ecc_cfg);
++
++ 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, page, 0);
++}
++
++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 *nfc = nand_get_controller_data(chip);
++
++ mtk_nfc_format_page(mtd, buf);
++ return mtk_nfc_write_page(mtd, chip, nfc->buffer, pg, 1);
++}
++
++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 page)
++{
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ int ret;
++
++ ret = mtk_nfc_format_subpage(mtd, offset, data_len, buf);
++ if (ret < 0)
++ return ret;
++
++ /* use the data in the private buffer (now with FDM and CRC) */
++ return mtk_nfc_write_page(mtd, chip, nfc->buffer, page, 1);
++}
++
++static int mtk_nfc_write_oob_std(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, 1, 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_update_ecc_stats(struct mtd_info *mtd, u8 *buf, u32 sectors)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_ecc_stats stats;
++ int rc, i;
++
++ rc = nfi_readl(nfc, NFI_STA) & STA_EMP_PAGE;
++ if (rc) {
++ memset(buf, 0xff, sectors * chip->ecc.size);
++ for (i = 0; i < sectors; i++)
++ memset(oob_ptr(chip, i), 0xff, mtk_nand->fdm.reg_size);
++ return 0;
++ }
++
++ mtk_ecc_get_stats(nfc->ecc, &stats, sectors);
++ mtd->ecc_stats.corrected += stats.corrected;
++ mtd->ecc_stats.failed += stats.failed;
++
++ return stats.bitflips;
++}
++
++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 *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ u32 spare = mtk_nand->spare_per_sector;
++ u32 column, sectors, start, end, reg;
++ dma_addr_t addr;
++ int bitflips;
++ size_t len;
++ u8 *buf;
++ int rc;
++
++ start = data_offs / chip->ecc.size;
++ end = DIV_ROUND_UP(data_offs + readlen, chip->ecc.size);
++
++ sectors = end - start;
++ column = start * (chip->ecc.size + spare);
++
++ len = sectors * chip->ecc.size + (raw ? sectors * spare : 0);
++ buf = bufpoi + start * chip->ecc.size;
++
++ if (column != 0)
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
++
++ addr = dma_map_single(nfc->dev, buf, len, DMA_FROM_DEVICE);
++ rc = dma_mapping_error(nfc->dev, addr);
++ if (rc) {
++ dev_err(nfc->dev, "dma mapping error\n");
++
++ return -EINVAL;
++ }
++
++ reg = nfi_readw(nfc, NFI_CNFG);
++ reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_AHB;
++ if (!raw) {
++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN;
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfc->ecc_cfg.ecc_mode = ECC_NFI_MODE;
++ nfc->ecc_cfg.sec_mask = sectors;
++ nfc->ecc_cfg.codec = ECC_DEC;
++ rc = mtk_ecc_enable(nfc->ecc, &nfc->ecc_cfg);
++ if (rc) {
++ dev_err(nfc->dev, "ecc enable\n");
++ /* clear NFI_CNFG */
++ reg &= ~(CNFG_DMA_BURST_EN | CNFG_AHB | CNFG_READ_EN |
++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++ nfi_writew(nfc, reg, NFI_CNFG);
++ dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++ return rc;
++ }
++ } else
++ nfi_writew(nfc, reg, NFI_CNFG);
++
++ nfi_writel(nfc, sectors << CON_SEC_SHIFT, NFI_CON);
++ nfi_writew(nfc, INTR_AHB_DONE_EN, NFI_INTR_EN);
++ nfi_writel(nfc, lower_32_bits(addr), NFI_STRADDR);
++
++ init_completion(&nfc->done);
++ reg = nfi_readl(nfc, NFI_CON) | CON_BRD;
++ nfi_writel(nfc, reg, NFI_CON);
++ nfi_writew(nfc, STAR_EN, NFI_STRDATA);
++
++ rc = wait_for_completion_timeout(&nfc->done, msecs_to_jiffies(500));
++ if (!rc)
++ dev_warn(nfc->dev, "read ahb/dma done timeout\n");
++
++ rc = readl_poll_timeout_atomic(nfc->regs + NFI_BYTELEN, reg,
++ (reg & CNTR_MASK) >= sectors, 10, MTK_TIMEOUT);
++ if (rc < 0) {
++ dev_err(nfc->dev, "subpage done timeout\n");
++ bitflips = -EIO;
++ } else {
++ bitflips = 0;
++ if (!raw) {
++ rc = mtk_ecc_wait_irq_done(nfc->ecc, ECC_DEC);
++ bitflips = rc < 0 ? -ETIMEDOUT :
++ mtk_nfc_update_ecc_stats(mtd, buf, sectors);
++ mtk_nfc_read_fdm(chip, start, sectors);
++ }
++ }
++
++ dma_unmap_single(nfc->dev, addr, len, DMA_FROM_DEVICE);
++
++ if (raw)
++ goto done;
++
++ mtk_ecc_disable(nfc->ecc, &nfc->ecc_cfg);
++
++ if (clamp(mtk_nand->bad_mark.sec, start, end) == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, bufpoi, raw);
++done:
++ nfi_writel(nfc, 0, NFI_CON);
++
++ return bitflips;
++}
++
++static int mtk_nfc_read_subpage_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, uint32_t off, uint32_t len, uint8_t *p, int pg)
++{
++ return mtk_nfc_read_subpage(mtd, chip, off, len, p, pg, 0);
++}
++
++static int mtk_nfc_read_page_hwecc(struct mtd_info *mtd,
++ struct nand_chip *chip, uint8_t *p, int oob_on, int pg)
++{
++ return mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, p, pg, 0);
++}
++
++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_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc *nfc = nand_get_controller_data(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ int i, ret;
++
++ memset(nfc->buffer, 0xff, mtd->writesize + mtd->oobsize);
++ ret = mtk_nfc_read_subpage(mtd, chip, 0, mtd->writesize, nfc->buffer,
++ page, 1);
++ if (ret < 0)
++ return ret;
++
++ for (i = 0; i < chip->ecc.steps; i++) {
++ memcpy(oob_ptr(chip, i), mtk_oob_ptr(chip, i), fdm->reg_size);
++ if (i == mtk_nand->bad_mark.sec)
++ mtk_nand->bad_mark.bm_swap(mtd, nfc->buffer, 1);
++
++ if (buf)
++ memcpy(data_ptr(chip, buf, i), mtk_data_ptr(chip, i),
++ chip->ecc.size);
++ }
++
++ return ret;
++}
++
++static int mtk_nfc_read_oob_std(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, 1, page);
++}
++
++static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
++{
++ nfi_writel(nfc, 0x10804211, NFI_ACCCON);
++ nfi_writew(nfc, 0xf1, NFI_CNRNB);
++ nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
++
++ mtk_nfc_hw_reset(nfc);
++
++ nfi_readl(nfc, NFI_INTR_STA);
++ nfi_writel(nfc, 0, NFI_INTR_EN);
++}
++
++static irqreturn_t mtk_nfc_irq(int irq, void *id)
++{
++ struct mtk_nfc *nfc = id;
++ u16 sta, ien;
++
++ sta = nfi_readw(nfc, NFI_INTR_STA);
++ ien = nfi_readw(nfc, NFI_INTR_EN);
++
++ if (!(sta & ien))
++ return IRQ_NONE;
++
++ nfi_writew(nfc, ~sta & ien, NFI_INTR_EN);
++ complete(&nfc->done);
++
++ return IRQ_HANDLED;
++}
++
++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->pad_clk);
++ if (ret) {
++ dev_err(dev, "failed to enable pad clk\n");
++ clk_disable_unprepare(clk->nfi_clk);
++ return ret;
++ }
++
++ return 0;
++}
++
++static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
++{
++ clk_disable_unprepare(clk->nfi_clk);
++ clk_disable_unprepare(clk->pad_clk);
++}
++
++static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oob_region)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ struct mtk_nfc_fdm *fdm = &mtk_nand->fdm;
++ u32 eccsteps;
++
++ eccsteps = mtd->writesize / chip->ecc.size;
++
++ if (section >= eccsteps)
++ return -ERANGE;
++
++ oob_region->length = fdm->reg_size - fdm->ecc_size;
++ oob_region->offset = section * fdm->reg_size + fdm->ecc_size;
++
++ return 0;
++}
++
++static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++ struct mtd_oob_region *oob_region)
++{
++ struct nand_chip *chip = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *mtk_nand = to_mtk_nand(chip);
++ u32 eccsteps;
++
++ if (section)
++ return -ERANGE;
++
++ eccsteps = mtd->writesize / chip->ecc.size;
++ oob_region->offset = mtk_nand->fdm.reg_size * eccsteps;
++ oob_region->length = mtd->oobsize - oob_region->offset;
++
++ return 0;
++}
++
++static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
++ .free = mtk_nfc_ooblayout_free,
++ .ecc = mtk_nfc_ooblayout_ecc,
++};
++
++static void mtk_nfc_set_fdm(struct mtk_nfc_fdm *fdm, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ struct mtk_nfc_nand_chip *chip = to_mtk_nand(nand);
++ u32 ecc_bytes;
++
++ ecc_bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++ fdm->reg_size = chip->spare_per_sector - ecc_bytes;
++ if (fdm->reg_size > NFI_FDM_MAX_SIZE)
++ fdm->reg_size = NFI_FDM_MAX_SIZE;
++
++ /* bad block mark storage */
++ fdm->ecc_size = 1;
++}
++
++static void mtk_nfc_set_bad_mark_ctl(struct mtk_nfc_bad_mark_ctl *bm_ctl,
++ struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++
++ if (mtd->writesize == 512)
++ bm_ctl->bm_swap = mtk_nfc_no_bad_mark_swap;
++ else {
++ bm_ctl->bm_swap = mtk_nfc_bad_mark_swap;
++ bm_ctl->sec = mtd->writesize / mtk_data_len(nand);
++ bm_ctl->pos = mtd->writesize % mtk_data_len(nand);
++ }
++}
++
++static void mtk_nfc_set_spare_per_sector(u32 *sps, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ u32 spare[] = {16, 26, 27, 28, 32, 36, 40, 44,
++ 48, 49, 50, 51, 52, 62, 63, 64};
++ u32 eccsteps, i;
++
++ eccsteps = mtd->writesize / nand->ecc.size;
++ *sps = mtd->oobsize / eccsteps;
++
++ if (nand->ecc.size == 1024)
++ *sps >>= 1;
++
++ for (i = 0; i < ARRAY_SIZE(spare); i++) {
++ if (*sps <= spare[i]) {
++ if (!i)
++ *sps = spare[i];
++ else if (*sps != spare[i])
++ *sps = spare[i - 1];
++ break;
++ }
++ }
++
++ if (i >= ARRAY_SIZE(spare))
++ *sps = spare[ARRAY_SIZE(spare) - 1];
++
++ if (nand->ecc.size == 1024)
++ *sps <<= 1;
++}
++
++static int mtk_nfc_ecc_init(struct device *dev, struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd_to_nand(mtd);
++ u32 spare;
++
++ /* support only ecc hw mode */
++ if (nand->ecc.mode != NAND_ECC_HW) {
++ dev_err(dev, "ecc.mode not supported\n");
++ return -EINVAL;
++ }
++
++ /* if optional DT settings are not present */
++ if (!nand->ecc.size || !nand->ecc.strength) {
++
++ /* controller only supports sizes 512 and 1024 */
++ nand->ecc.size = (mtd->writesize > 512) ? 1024 : 512;
++
++ /* get controller valid values */
++ mtk_nfc_set_spare_per_sector(&spare, mtd);
++ spare = spare - NFI_FDM_MAX_SIZE;
++ nand->ecc.strength = (spare << 3) / ECC_PARITY_BITS;
++ }
++
++ mtk_ecc_update_strength(&nand->ecc.strength);
++
++ dev_info(dev, "eccsize %d eccstrength %d\n",
++ nand->ecc.size, nand->ecc.strength);
++
++ return 0;
++}
++
++static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc,
++ struct device_node *np)
++{
++ struct mtk_nfc_nand_chip *chip;
++ struct nand_chip *nand;
++ struct mtd_info *mtd;
++ int nsels, len;
++ u32 tmp;
++ int ret;
++ int i;
++
++ if (!of_get_property(np, "reg", &nsels))
++ return -ENODEV;
++
++ nsels /= sizeof(u32);
++ if (!nsels || nsels > MTK_NAND_MAX_NSELS) {
++ dev_err(dev, "invalid reg property size %d\n", nsels);
++ return -EINVAL;
++ }
++
++ chip = devm_kzalloc(dev,
++ sizeof(*chip) + nsels * sizeof(u8), GFP_KERNEL);
++ if (!chip)
++ return -ENOMEM;
++
++ chip->nsels = nsels;
++ for (i = 0; i < nsels; i++) {
++ ret = of_property_read_u32_index(np, "reg", i, &tmp);
++ if (ret) {
++ dev_err(dev, "reg property failure : %d\n", ret);
++ return ret;
++ }
++ chip->sels[i] = tmp;
++ }
++
++ nand = &chip->nand;
++ nand->controller = &nfc->controller;
++
++ nand_set_flash_node(nand, np);
++ nand_set_controller_data(nand, nfc);
++
++ nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ;
++ nand->dev_ready = mtk_nfc_dev_ready;
++ nand->select_chip = mtk_nfc_select_chip;
++ nand->write_byte = mtk_nfc_write_byte;
++ nand->write_buf = mtk_nfc_write_buf;
++ nand->read_byte = mtk_nfc_read_byte;
++ nand->read_buf = mtk_nfc_read_buf;
++ nand->cmd_ctrl = mtk_nfc_cmd_ctrl;
++
++ /* set default mode in case dt entry is missing */
++ nand->ecc.mode = NAND_ECC_HW;
++
++ nand->ecc.write_subpage = mtk_nfc_write_subpage_hwecc;
++ nand->ecc.write_page_raw = mtk_nfc_write_page_raw;
++ nand->ecc.write_page = mtk_nfc_write_page_hwecc;
++ nand->ecc.write_oob_raw = mtk_nfc_write_oob_std;
++ nand->ecc.write_oob = mtk_nfc_write_oob_std;
++
++ nand->ecc.read_subpage = mtk_nfc_read_subpage_hwecc;
++ nand->ecc.read_page_raw = mtk_nfc_read_page_raw;
++ nand->ecc.read_page = mtk_nfc_read_page_hwecc;
++ nand->ecc.read_oob_raw = mtk_nfc_read_oob_std;
++ nand->ecc.read_oob = mtk_nfc_read_oob_std;
++
++ mtd = nand_to_mtd(nand);
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = dev;
++ mtd->name = MTK_NAME;
++ mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
++
++ mtk_nfc_hw_init(nfc);
++
++ ret = nand_scan_ident(mtd, nsels, NULL);
++ if (ret)
++ return -ENODEV;
++
++ /* store bbt magic in page, cause OOB is not protected */
++ if (nand->bbt_options & NAND_BBT_USE_FLASH)
++ nand->bbt_options |= NAND_BBT_NO_OOB;
++
++ ret = mtk_nfc_ecc_init(dev, mtd);
++ if (ret)
++ return -EINVAL;
++
++ mtk_nfc_set_spare_per_sector(&chip->spare_per_sector, mtd);
++ mtk_nfc_set_fdm(&chip->fdm, mtd);
++ mtk_nfc_set_bad_mark_ctl(&chip->bad_mark, mtd);
++
++ len = mtd->writesize + mtd->oobsize;
++ nfc->buffer = devm_kzalloc(dev, len, GFP_KERNEL);
++ if (!nfc->buffer)
++ return -ENOMEM;
++
++ ret = nand_scan_tail(mtd);
++ if (ret)
++ return -ENODEV;
++
++ ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
++ if (ret) {
++ dev_err(dev, "mtd parse partition error\n");
++ nand_release(mtd);
++ return ret;
++ }
++
++ list_add_tail(&chip->node, &nfc->chips);
++
++ return 0;
++}
++
++static int mtk_nfc_nand_chips_init(struct device *dev, struct mtk_nfc *nfc)
++{
++ struct device_node *np = dev->of_node;
++ struct device_node *nand_np;
++ int ret;
++
++ for_each_child_of_node(np, nand_np) {
++ ret = mtk_nfc_nand_chip_init(dev, nfc, nand_np);
++ if (ret) {
++ of_node_put(nand_np);
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int mtk_nfc_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct mtk_nfc *nfc;
++ struct resource *res;
++ int ret, irq;
++
++ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++ if (!nfc)
++ return -ENOMEM;
++
++ spin_lock_init(&nfc->controller.lock);
++ init_waitqueue_head(&nfc->controller.wq);
++ INIT_LIST_HEAD(&nfc->chips);
++
++ /* probe defer if not ready */
++ nfc->ecc = of_mtk_ecc_get(np);
++ if (IS_ERR(nfc->ecc))
++ return PTR_ERR(nfc->ecc);
++ else if (!nfc->ecc)
++ return -ENODEV;
++
++ nfc->dev = dev;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ nfc->regs = devm_ioremap_resource(dev, res);
++ if (IS_ERR(nfc->regs)) {
++ ret = PTR_ERR(nfc->regs);
++ dev_err(dev, "no nfi base\n");
++ goto release_ecc;
++ }
++
++ nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
++ if (IS_ERR(nfc->clk.nfi_clk)) {
++ dev_err(dev, "no clk\n");
++ ret = PTR_ERR(nfc->clk.nfi_clk);
++ goto release_ecc;
++ }
++
++ nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
++ if (IS_ERR(nfc->clk.pad_clk)) {
++ dev_err(dev, "no pad clk\n");
++ ret = PTR_ERR(nfc->clk.pad_clk);
++ goto release_ecc;
++ }
++
++ ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++ if (ret)
++ goto release_ecc;
++
++ 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_nfc_irq, 0x0, "mtk-nand", nfc);
++ if (ret) {
++ dev_err(dev, "failed to request nfi 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, nfc);
++
++ ret = mtk_nfc_nand_chips_init(dev, nfc);
++ if (ret) {
++ dev_err(dev, "failed to init nand chips\n");
++ goto clk_disable;
++ }
++
++ return 0;
++
++clk_disable:
++ mtk_nfc_disable_clk(&nfc->clk);
++
++release_ecc:
++ mtk_ecc_release(nfc->ecc);
++
++ return ret;
++}
++
++static int mtk_nfc_remove(struct platform_device *pdev)
++{
++ struct mtk_nfc *nfc = platform_get_drvdata(pdev);
++ struct mtk_nfc_nand_chip *chip;
++
++ while (!list_empty(&nfc->chips)) {
++ chip = list_first_entry(&nfc->chips, struct mtk_nfc_nand_chip,
++ node);
++ nand_release(nand_to_mtd(&chip->nand));
++ list_del(&chip->node);
++ }
++
++ mtk_ecc_release(nfc->ecc);
++ mtk_nfc_disable_clk(&nfc->clk);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int mtk_nfc_suspend(struct device *dev)
++{
++ struct mtk_nfc *nfc = dev_get_drvdata(dev);
++
++ mtk_nfc_disable_clk(&nfc->clk);
++
++ return 0;
++}
++
++static int mtk_nfc_resume(struct device *dev)
++{
++ struct mtk_nfc *nfc = dev_get_drvdata(dev);
++ struct mtk_nfc_nand_chip *chip;
++ struct nand_chip *nand;
++ struct mtd_info *mtd;
++ int ret;
++ u32 i;
++
++ udelay(200);
++
++ ret = mtk_nfc_enable_clk(dev, &nfc->clk);
++ if (ret)
++ return ret;
++
++ mtk_nfc_hw_init(nfc);
++
++ list_for_each_entry(chip, &nfc->chips, node) {
++ nand = &chip->nand;
++ mtd = nand_to_mtd(nand);
++ for (i = 0; i < chip->nsels; i++) {
++ nand->select_chip(mtd, i);
++ nand->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ }
++ }
++
++ 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_AUTHOR("Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>");
++MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
diff --git a/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch b/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch
new file mode 100644
index 0000000000..7702246a4c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0076-mtd-nand-add-power-domains-to-the-mediatek-driver.patch
@@ -0,0 +1,67 @@
+From 5dc0d474396e04e6c140d71f0e113eb1c03501c5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 17 May 2016 05:44:10 +0200
+Subject: [PATCH 076/102] mtd: nand: add power domains to the mediatek driver
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/mtd/nand/mtk_nand.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/mtk_nand.c
++++ b/drivers/mtd/nand/mtk_nand.c
+@@ -16,6 +16,7 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/pm_runtime.h>
+ #include <linux/interrupt.h>
+ #include <linux/delay.h>
+ #include <linux/clk.h>
+@@ -102,6 +103,7 @@
+ #define NFI_MASTER_STA (0x224)
+ #define MASTER_STA_MASK (0x0FFF)
+ #define NFI_EMPTY_THRESH (0x23C)
++#define NFI_ACCCON1 (0x244)
+
+ #define MTK_NAME "mtk-nand"
+ #define KB(x) ((x) * 1024UL)
+@@ -539,6 +541,8 @@ static void mtk_nfc_bad_mark_swap(struct
+ struct mtk_nfc_nand_chip *nand = to_mtk_nand(chip);
+ u32 bad_pos = nand->bad_mark.pos;
+
++ return;
++
+ if (raw)
+ bad_pos += nand->bad_mark.sec * mtk_data_len(chip);
+ else
+@@ -946,7 +950,8 @@ static int mtk_nfc_read_oob_std(struct m
+
+ static inline void mtk_nfc_hw_init(struct mtk_nfc *nfc)
+ {
+- nfi_writel(nfc, 0x10804211, NFI_ACCCON);
++ nfi_writel(nfc, 0x30c77fff, NFI_ACCCON);
++ nfi_writel(nfc, 0xC03222, NFI_ACCCON1);
+ nfi_writew(nfc, 0xf1, NFI_CNRNB);
+ nfi_writew(nfc, PAGEFMT_8K_16K, NFI_PAGEFMT);
+
+@@ -1328,6 +1333,9 @@ static int mtk_nfc_probe(struct platform
+ goto clk_disable;
+ }
+
++ pm_runtime_enable(dev);
++ pm_runtime_get_sync(dev);
++
+ platform_set_drvdata(pdev, nfc);
+
+ ret = mtk_nfc_nand_chips_init(dev, nfc);
+@@ -1362,6 +1370,9 @@ static int mtk_nfc_remove(struct platfor
+ mtk_ecc_release(nfc->ecc);
+ mtk_nfc_disable_clk(&nfc->clk);
+
++ pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++
+ return 0;
+ }
+
diff --git a/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch b/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch
new file mode 100644
index 0000000000..c2fe21825c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0077-net-next-mediatek-use-mdiobus_free-in-favour-of-kfre.patch
@@ -0,0 +1,36 @@
+From b1c85818c3fb00022dc125bb62d657d3fd3cf49c Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 7 May 2016 06:31:08 +0200
+Subject: [PATCH 077/102] net-next: mediatek: use mdiobus_free() in favour of
+ kfree()
+
+The driver currently uses kfree() to clear the mii_bus. This is not the
+correct way to clear the memory and mdiobus_free() should be used instead.
+This patch fixes the two instances where this happens in the driver.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -280,7 +280,7 @@ static int mtk_mdio_init(struct mtk_eth
+ return 0;
+
+ err_free_bus:
+- kfree(eth->mii_bus);
++ mdiobus_free(eth->mii_bus);
+
+ err_put_node:
+ of_node_put(mii_np);
+@@ -295,7 +295,7 @@ static void mtk_mdio_cleanup(struct mtk_
+
+ mdiobus_unregister(eth->mii_bus);
+ of_node_put(eth->mii_bus->dev.of_node);
+- kfree(eth->mii_bus);
++ mdiobus_free(eth->mii_bus);
+ }
+
+ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
diff --git a/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch b/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
new file mode 100644
index 0000000000..42adb9e786
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0078-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
@@ -0,0 +1,71 @@
+From 09313f26999e2685e0b9434374e7308e1f447e55 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:05:23 +0200
+Subject: [PATCH 078/102] net-next: mediatek: fix gigabit and flow control
+ advertisement
+
+The current code will not setup the PHYs advertisement features correctly.
+Fix this and properly advertise Gigabit features and properly handle
+asymmetric pause frames.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++++++++++++++++++----
+ 1 file changed, 26 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -133,6 +133,8 @@ static int mtk_mdio_read(struct mii_bus
+ static void mtk_phy_link_adjust(struct net_device *dev)
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
++ u16 lcl_adv = 0, rmt_adv = 0;
++ u8 flowctrl;
+ 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 |
+@@ -150,11 +152,30 @@ static void mtk_phy_link_adjust(struct n
+ if (mac->phy_dev->link)
+ mcr |= MAC_MCR_FORCE_LINK;
+
+- if (mac->phy_dev->duplex)
++ 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;
++ if (mac->phy_dev->pause)
++ rmt_adv = LPA_PAUSE_CAP;
++ if (mac->phy_dev->asym_pause)
++ rmt_adv |= LPA_PAUSE_ASYM;
++
++ if (mac->phy_dev->advertising & ADVERTISED_Pause)
++ lcl_adv |= ADVERTISE_PAUSE_CAP;
++ if (mac->phy_dev->advertising & ADVERTISED_Asym_Pause)
++ lcl_adv |= ADVERTISE_PAUSE_ASYM;
++
++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
++
++ if (flowctrl & FLOW_CTRL_TX)
++ mcr |= MAC_MCR_FORCE_TX_FC;
++ if (flowctrl & FLOW_CTRL_RX)
++ mcr |= MAC_MCR_FORCE_RX_FC;
++
++ netif_dbg(mac->hw, link, dev, "rx pause %s, tx pause %s\n",
++ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
++ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
++ }
+
+ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+
+@@ -236,7 +257,8 @@ static int mtk_phy_connect(struct mtk_ma
+ mac->phy_dev->autoneg = AUTONEG_ENABLE;
+ mac->phy_dev->speed = 0;
+ mac->phy_dev->duplex = 0;
+- mac->phy_dev->supported &= PHY_BASIC_FEATURES;
++ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
++ SUPPORTED_Asym_Pause;
+ mac->phy_dev->advertising = mac->phy_dev->supported |
+ ADVERTISED_Autoneg;
+ phy_start_aneg(mac->phy_dev);
diff --git a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch b/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch
new file mode 100644
index 0000000000..669febbdf1
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-add-fixed-phy-support.patch
@@ -0,0 +1,38 @@
+From 09f0b50ae838bd6e2bbf0aa22de9f352122297de Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:06:03 +0200
+Subject: [PATCH 079/102] net-next: mediatek: add fixed-phy support
+
+The MT7623 SoC has a builtin gigabit switch. If we want to use it, GMAC1
+needs to be configured using a fixed link speed and flow control settings.
+The easiest way to do this is to used the fixed-phy driver, allowing us to
+reuse the existing mdio polling code to setup the MAC.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -229,6 +229,9 @@ static int mtk_phy_connect(struct mtk_ma
+ u32 val, ge_mode;
+
+ np = of_parse_phandle(mac->of_node, "phy-handle", 0);
++ if (!np && of_phy_is_fixed_link(mac->of_node))
++ if (!of_phy_register_fixed_link(mac->of_node))
++ np = of_node_get(mac->of_node);
+ if (!np)
+ return -ENODEV;
+
+@@ -257,6 +260,9 @@ static int mtk_phy_connect(struct mtk_ma
+ mac->phy_dev->autoneg = AUTONEG_ENABLE;
+ mac->phy_dev->speed = 0;
+ mac->phy_dev->duplex = 0;
++ if (of_phy_is_fixed_link(mac->of_node))
++ mac->phy_dev->supported |= SUPPORTED_Pause |
++ SUPPORTED_Asym_Pause;
+ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause;
+ mac->phy_dev->advertising = mac->phy_dev->supported |
diff --git a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
deleted file mode 100644
index facbbf2937..0000000000
--- a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-fix-gigabit-and-flow-control-adver.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 6918f290a9019425043dbedf7b39bc82a69e23a6 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:05:23 +0200
-Subject: [PATCH 80/91] net-next: mediatek: fix gigabit and flow control
- advertisement
-
-The current code will not setup the PHYs advertisement features correctly.
-Fix this and properly advertise Gigabit features and properly handle
-asymmetric pause frames.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 9928a79..204d927 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -133,6 +133,8 @@ static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
- static void mtk_phy_link_adjust(struct net_device *dev)
- {
- struct mtk_mac *mac = netdev_priv(dev);
-+ u16 lcl_adv, rmt_adv = 0;
-+ u8 flowctrl;
- 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 |
-@@ -154,7 +156,16 @@ static void mtk_phy_link_adjust(struct net_device *dev)
- mcr |= MAC_MCR_FORCE_DPX;
-
- if (mac->phy_dev->pause)
-- mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC;
-+ rmt_adv = LPA_PAUSE_CAP;
-+ if (mac->phy_dev->asym_pause)
-+ rmt_adv |= LPA_PAUSE_ASYM;
-+
-+ lcl_adv = mii_advertise_flowctrl(FLOW_CTRL_RX | FLOW_CTRL_TX);
-+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
-+ if (flowctrl & FLOW_CTRL_TX)
-+ mcr |= MAC_MCR_FORCE_TX_FC;
-+ if (flowctrl & FLOW_CTRL_RX)
-+ mcr |= MAC_MCR_FORCE_RX_FC;
-
- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
-
-@@ -236,7 +247,8 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- mac->phy_dev->autoneg = AUTONEG_ENABLE;
- mac->phy_dev->speed = 0;
- mac->phy_dev->duplex = 0;
-- mac->phy_dev->supported &= PHY_BASIC_FEATURES;
-+ mac->phy_dev->supported &= PHY_GBIT_FEATURES | SUPPORTED_Pause |
-+ ~SUPPORTED_Asym_Pause;
- mac->phy_dev->advertising = mac->phy_dev->supported |
- ADVERTISED_Autoneg;
- phy_start_aneg(mac->phy_dev);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch
new file mode 100644
index 0000000000..1d176f2ece
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0080-net-next-mediatek-properly-handle-RGMII-modes.patch
@@ -0,0 +1,31 @@
+From 25eaa5d6483a5899e6bf48b47f762f05c186b4b6 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Fri, 22 Apr 2016 11:08:43 +0200
+Subject: [PATCH 080/102] net-next: mediatek: properly handle RGMII modes
+
+If an external Gigabit PHY is connected to either of the MACs we need to
+be able to tell the PHY to use a delay. Not doing so will result in heavy
+packet loss and/or data corruption when using PHYs such as the IC+ IP1001.
+We tell the PHY which MII delay mode to use via the devictree.
+
+The ethernet driver needs to be adapted to handle all 3 rgmii-*id modes
+in the same way as normal rgmii when setting up the MAC.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -236,6 +236,9 @@ static int mtk_phy_connect(struct mtk_ma
+ return -ENODEV;
+
+ switch (of_get_phy_mode(np)) {
++ case PHY_INTERFACE_MODE_RGMII_TXID:
++ case PHY_INTERFACE_MODE_RGMII_RXID:
++ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII:
+ ge_mode = 0;
+ break;
diff --git a/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch
deleted file mode 100644
index bc6349568a..0000000000
--- a/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-add-fixed-phy-support.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From b5ecc24a027dea24f3ff798f87f65dd42015b342 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:06:03 +0200
-Subject: [PATCH 81/91] net-next: mediatek: add fixed-phy support
-
-The MT7623 SoC has a builtin gigabit switch. If we want to use it, GMAC1
-needs to be configured using a fixed link speed and flow control settings.
-The easiest way to do this is to used the fixed-phy driver, allowing us to
-reuse the existing mdio polling code to setup the MAC.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 204d927..f4d8519 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -219,6 +219,9 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- u32 val, ge_mode;
-
- np = of_parse_phandle(mac->of_node, "phy-handle", 0);
-+ if (!np && of_phy_is_fixed_link(mac->of_node))
-+ if (!of_phy_register_fixed_link(mac->of_node))
-+ np = of_node_get(mac->of_node);
- if (!np)
- return -ENODEV;
-
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch
index a4d42d324a..f1c7290aac 100644
--- a/target/linux/mediatek/patches-4.4/0079-net-next-mediatek-fix-BQL-support.patch
+++ b/target/linux/mediatek/patches-4.4/0081-net-next-mediatek-fix-DQL-support.patch
@@ -1,18 +1,24 @@
-From f26f228f312fafc090d21036b682bd1062bb731f Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
+From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
Date: Sat, 23 Apr 2016 11:57:21 +0200
-Subject: [PATCH 79/91] net-next: mediatek: fix BQL support
+Subject: [PATCH 081/102] net-next: mediatek: fix DQL support
-Signed-off-by: John Crispin <blogic@openwrt.org>
+The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The
+current code will assign the TX traffic of each MAC to its own DQL. This
+results in the amount of data, that DQL says is in the queue incorrect. As
+the data from multiple devices is infact enqueued. This makes any decision
+based on these value non deterministic. Fix this by tracking all TX
+traffic, regardless of the MAC it belongs to in the DQL of all devices
+using the DMA.
+
+Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++++-----------
1 file changed, 20 insertions(+), 13 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bab5d45..9928a79 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -625,7 +625,16 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+@@ -656,7 +656,16 @@ static int mtk_tx_map(struct sk_buff *sk
WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
(!nr_frags * TX_DMA_LS0)));
@@ -30,7 +36,7 @@ index bab5d45..9928a79 100644
skb_tx_timestamp(skb);
ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
-@@ -853,21 +862,18 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+@@ -884,21 +893,18 @@ static int mtk_poll_tx(struct mtk_eth *e
struct mtk_tx_dma *desc;
struct sk_buff *skb;
struct mtk_tx_buf *tx_buf;
@@ -55,7 +61,7 @@ index bab5d45..9928a79 100644
u32 next_cpu = desc->txd2;
int mac;
-@@ -887,9 +893,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+@@ -918,9 +924,8 @@ static int mtk_poll_tx(struct mtk_eth *e
}
if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
@@ -67,7 +73,7 @@ index bab5d45..9928a79 100644
}
mtk_tx_unmap(eth->dev, tx_buf);
-@@ -902,11 +907,13 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+@@ -933,11 +938,13 @@ static int mtk_poll_tx(struct mtk_eth *e
mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
@@ -84,6 +90,3 @@ index bab5d45..9928a79 100644
}
/* read hw index again make sure no new tx packet */
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch
deleted file mode 100644
index ad49fd9352..0000000000
--- a/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-RX-delay-support.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From bbd92ed51c48a4586f149767841a5495cbc5a979 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 22 Apr 2016 11:08:43 +0200
-Subject: [PATCH 82/91] net-next: mediatek: add RX delay support
-
-If an external Gigabit PHY is connected to either of the MACs we need to
-tell the to use a RX delay. Not doing so will result in heavy packet loss
-and/or data corruption of RX traffic.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index f4d8519..aa25788 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -226,6 +226,7 @@ static int mtk_phy_connect(struct mtk_mac *mac)
- return -ENODEV;
-
- switch (of_get_phy_mode(np)) {
-+ case PHY_INTERFACE_MODE_RGMII_RXID:
- case PHY_INTERFACE_MODE_RGMII:
- ge_mode = 0;
- break;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch
index 652001ecf9..19cdbf0d3e 100644
--- a/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-add-missing-return-code-check.patch
+++ b/target/linux/mediatek/patches-4.4/0082-net-next-mediatek-add-missing-return-code-check.patch
@@ -1,21 +1,20 @@
-From d20b45f50d6b3352aa7be76eb7a28cffcfe379da Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
+From 51ca1e9f141499fd7c95bff5401215b706656754 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
Date: Sat, 23 Apr 2016 09:06:05 +0200
-Subject: [PATCH 83/91] net-next: mediatek: add missing return code check
+Subject: [PATCH 082/102] net-next: mediatek: add missing return code check
The code fails to check if the scratch memory was properly allocated. Add
this check and return with an error if the allocation failed.
-Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++
1 file changed, 3 insertions(+)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index aa25788..e58a634 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -483,6 +483,9 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
+@@ -498,6 +498,9 @@ static int mtk_init_fq_dma(struct mtk_et
eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE,
GFP_KERNEL);
@@ -25,6 +24,3 @@ index aa25788..e58a634 100644
dma_addr = dma_map_single(eth->dev,
eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
DMA_FROM_DEVICE);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch b/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
index 632b9a8140..793875faf4 100644
--- a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
+++ b/target/linux/mediatek/patches-4.4/0083-net-next-mediatek-fix-missing-free-of-scratch-memory.patch
@@ -1,22 +1,23 @@
-From 2d22628561299e1c7d71e16262131127de3c4216 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
+From b48745c534ced06005d2ba57198b54a6a160b39d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
Date: Sat, 23 Apr 2016 09:18:28 +0200
-Subject: [PATCH 84/91] net-next: mediatek: fix missing free of scratch memory
+Subject: [PATCH 083/102] net-next: mediatek: fix missing free of scratch
+ memory
Scratch memory gets allocated in mtk_init_fq_dma() but the corresponding
code to free it is missing inside mtk_dma_free() causing a memory leak.
+With this patch applied, we can run ifconfig/up/down several thousand
+times without any problems.
-Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++++++++++++-----
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++
2 files changed, 15 insertions(+), 5 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index e58a634..06b9094 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -469,14 +469,14 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd,
+@@ -484,14 +484,14 @@ static inline void mtk_rx_get_desc(struc
/* the qdma core needs scratch memory to be setup */
static int mtk_init_fq_dma(struct mtk_eth *eth)
{
@@ -33,7 +34,7 @@ index e58a634..06b9094 100644
GFP_ATOMIC | __GFP_ZERO);
if (unlikely(!eth->scratch_ring))
return -ENOMEM;
-@@ -493,19 +493,19 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
+@@ -508,19 +508,19 @@ static int mtk_init_fq_dma(struct mtk_et
return -ENOMEM;
memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
@@ -56,7 +57,7 @@ index e58a634..06b9094 100644
mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
-@@ -1205,6 +1205,14 @@ static void mtk_dma_free(struct mtk_eth *eth)
+@@ -1220,6 +1220,14 @@ static void mtk_dma_free(struct mtk_eth
for (i = 0; i < MTK_MAC_COUNT; i++)
if (eth->netdev[i])
netdev_reset_queue(eth->netdev[i]);
@@ -71,8 +72,6 @@ index e58a634..06b9094 100644
mtk_tx_clean(eth);
mtk_rx_clean(eth);
kfree(eth->scratch_head);
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index eed626d..57f7e8a 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -357,6 +357,7 @@ struct mtk_rx_ring {
@@ -91,6 +90,3 @@ index eed626d..57f7e8a 100644
void *scratch_head;
struct clk *clk_ethif;
struct clk *clk_esw;
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch b/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
new file mode 100644
index 0000000000..eb44af6f89
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0084-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
@@ -0,0 +1,27 @@
+From 1eea1536dbbbfda418751ec6f5387acb521ddb97 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Sat, 23 Apr 2016 09:25:00 +0200
+Subject: [PATCH 084/102] net-next: mediatek: invalid buffer lookup in
+ mtk_tx_map()
+
+The lookup of the tx_buffer in the error path inside mtk_tx_map() uses the
+wrong descriptor pointer. This looks like a copy & paste error. Change the
+code to use the correct pointer.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -686,7 +686,7 @@ static int mtk_tx_map(struct sk_buff *sk
+
+ err_dma:
+ do {
+- tx_buf = mtk_desc_to_tx_buf(ring, txd);
++ tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+
+ /* unmap dma */
+ mtk_tx_unmap(&dev->dev, tx_buf);
diff --git a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
index 8a38b5a5f5..2b2a011b3d 100644
--- a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
+++ b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-dropped-rx-packets-are-not-being-c.patch
@@ -1,23 +1,22 @@
-From d74187cab7927d3496c01c97051d9c539067ad1b Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
+From 98aac832925a99afee8722cdfd5a848dd6086b8f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
Date: Sat, 23 Apr 2016 09:28:25 +0200
-Subject: [PATCH 86/91] net-next: mediatek: dropped rx packets are not being
+Subject: [PATCH 085/102] net-next: mediatek: dropped rx packets are not being
counted properly
There are 2 places inside mtk_poll_rx where rx_dropped is not being
incremented properly. Fix this by adding the missing code to increment
the counter.
-Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
---
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 63e1da4..24a4179 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -826,6 +826,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -841,6 +841,7 @@ static int mtk_poll_rx(struct napi_struc
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) {
skb_free_frag(new_data);
@@ -25,7 +24,7 @@ index 63e1da4..24a4179 100644
goto release_desc;
}
-@@ -833,6 +834,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -848,6 +849,7 @@ static int mtk_poll_rx(struct napi_struc
skb = build_skb(data, ring->frag_size);
if (unlikely(!skb)) {
put_page(virt_to_head_page(new_data));
@@ -33,6 +32,3 @@ index 63e1da4..24a4179 100644
goto release_desc;
}
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch b/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
deleted file mode 100644
index 37e14b19bc..0000000000
--- a/target/linux/mediatek/patches-4.4/0085-net-next-mediatek-invalid-buffer-lookup-in-mtk_tx_ma.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 7ae20e15e06eed22f343a566b22dce258f7b8704 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sat, 23 Apr 2016 09:25:00 +0200
-Subject: [PATCH 85/91] net-next: mediatek: invalid buffer lookup in
- mtk_tx_map()
-
-The lookup of the tx_buffer in the error path inside mtk_tx_map() uses the
-wrong descriptor pointer. This looks like a copy & paste error.
-
-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 06b9094..63e1da4 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -671,7 +671,7 @@ static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
-
- err_dma:
- do {
-- tx_buf = mtk_desc_to_tx_buf(ring, txd);
-+ tx_buf = mtk_desc_to_tx_buf(ring, itxd);
-
- /* unmap dma */
- mtk_tx_unmap(&dev->dev, tx_buf);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch b/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch
new file mode 100644
index 0000000000..cd4bdf8fa4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0086-net-next-mediatek-add-next-data-pointer-coherency-pr.patch
@@ -0,0 +1,39 @@
+From 5077ac38a86023124ebbe24cd1b7ecbd0f8edaff Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:06:59 +0200
+Subject: [PATCH 086/102] net-next: mediatek: add next data pointer coherency
+ protection
+
+The QDMA engine can fail to update the register pointing to the next TX
+descriptor if this bit does not get set in the QDMA configuration register.
+Not setting this bit can result in invalid values inside the TX rings
+registers which will causes TX stalls.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1292,7 +1292,7 @@ static int mtk_start_dma(struct mtk_eth
+ mtk_w32(eth,
+ MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
+ MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
+- MTK_RX_BT_32DWORDS,
++ MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
+ MTK_QDMA_GLO_CFG);
+
+ return 0;
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -91,6 +91,7 @@
+ #define MTK_QDMA_GLO_CFG 0x1A04
+ #define MTK_RX_2B_OFFSET BIT(31)
+ #define MTK_RX_BT_32DWORDS (3 << 11)
++#define MTK_NDP_CO_PRO BIT(10)
+ #define MTK_TX_WB_DDONE BIT(6)
+ #define MTK_DMA_SIZE_16DWORDS (2 << 4)
+ #define MTK_RX_DMA_BUSY BIT(3)
diff --git a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch b/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch
new file mode 100644
index 0000000000..6e809b9315
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-disable-all-interrupts-during-prob.patch
@@ -0,0 +1,26 @@
+From f9a08e142fd87c72a7803203ce4ecc94806046ca Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:14:07 +0200
+Subject: [PATCH 087/102] net-next: mediatek: disable all interrupts during
+ probe
+
+The current code only disables those IRQs that we will later use. To
+ensure that we have a predefined state, we really want to disable all IRQs.
+Change the code to disable all IRQs to achieve this.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1406,7 +1406,7 @@ static int __init mtk_hw_init(struct mtk
+
+ /* disable delay and normal interrupt */
+ mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
++ mtk_irq_disable(eth, ~0);
+ mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
+ mtk_w32(eth, 0, MTK_RST_GL);
+
diff --git a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch b/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch
new file mode 100644
index 0000000000..466f8731e0
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-fix-threshold-value.patch
@@ -0,0 +1,30 @@
+From 34ea0f209e0759158e363039852a04b1facc3acd Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 02:55:27 +0200
+Subject: [PATCH 088/102] net-next: mediatek: fix threshold value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The logic to calculate the threshold value for stopping the TX queue is
+bad. Currently it will always use 1/2 of the rings size, which is way too
+much. Set the threshold to MAX_SKB_FRAGS. This makes sure that the queue
+is stopped when there is not enough room to accept an additional segment. 
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1043,8 +1043,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+ atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+ ring->next_free = &ring->dma[0];
+ ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
+- ring->thresh = max((unsigned long)MTK_DMA_SIZE >> 2,
+- MAX_SKB_FRAGS);
++ ring->thresh = MAX_SKB_FRAGS;
+
+ /* make sure that all changes to the dma ring are flushed before we
+ * continue
diff --git a/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch b/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch
new file mode 100644
index 0000000000..96928d232a
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0089-net-next-mediatek-increase-watchdog_timeo.patch
@@ -0,0 +1,26 @@
+From 2cbf3f95a49925317ef4138ceaf7f7f30f353f0f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:17:53 +0200
+Subject: [PATCH 089/102] net-next: mediatek: increase watchdog_timeo
+
+During stress testing, after reducing the threshold value, we have seen
+TX timeouts that were caused by the watchdog_timeo value being too low.
+Increase the value to 5 * HZ which is a value commonly used by many other
+drivers.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1720,7 +1720,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+- eth->netdev[id]->watchdog_timeo = HZ;
++ eth->netdev[id]->watchdog_timeo = 5 * HZ;
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
diff --git a/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch b/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch
deleted file mode 100644
index f26eaeaccc..0000000000
--- a/target/linux/mediatek/patches-4.4/0090-net-mediatek-v4.4-backports.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 7d2bdde21bc72eb41878890149f2b9d05fc3af6e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 11 Apr 2016 06:00:23 +0200
-Subject: [PATCH 90/91] net: mediatek: v4.4 backports
-
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 23 ++++++++++++++---------
- 1 file changed, 14 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index bb62b91..5d33053 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -207,7 +207,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;
-@@ -1268,9 +1268,10 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- return IRQ_NONE;
-
- if (status & MTK_RX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->rx_napi)))
-+ if (likely(napi_schedule_prep(&eth->rx_napi))) {
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
- __napi_schedule(&eth->rx_napi);
-- mtk_irq_disable(eth, MTK_RX_DONE_INT);
-+ }
- }
- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
-@@ -1289,9 +1290,10 @@ static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
- return IRQ_NONE;
-
- if (status & MTK_TX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->tx_napi)))
-+ if (likely(napi_schedule_prep(&eth->tx_napi))) {
-+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
- __napi_schedule(&eth->tx_napi);
-- mtk_irq_disable(eth, MTK_TX_DONE_INT);
-+ }
- }
- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
-@@ -1383,6 +1385,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);
-
-@@ -1582,11 +1585,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);
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch b/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch
new file mode 100644
index 0000000000..b6f32fc451
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0090-net-next-mediatek-fix-off-by-one-in-the-TX-ring-allo.patch
@@ -0,0 +1,36 @@
+From 94425de9ede5ef0eafbfced65140c30e7c0b6c0d Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:01:13 +0200
+Subject: [PATCH 090/102] net-next: mediatek: fix off by one in the TX ring
+ allocation
+
+The TX ring setup has an off by one error causing it to not utilise all
+descriptors. This has the side effect that we need to reset the next
+pointer at runtime to make it work. Fix the off by one and remove the
+code fixing the ring at runtime.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -934,7 +934,6 @@ static int mtk_poll_tx(struct mtk_eth *e
+ }
+ mtk_tx_unmap(eth->dev, tx_buf);
+
+- ring->last_free->txd2 = next_cpu;
+ ring->last_free = desc;
+ atomic_inc(&ring->free_count);
+
+@@ -1042,7 +1041,7 @@ static int mtk_tx_alloc(struct mtk_eth *
+
+ atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+ ring->next_free = &ring->dma[0];
+- ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
++ ring->last_free = &ring->dma[MTK_DMA_SIZE - 1];
+ ring->thresh = MAX_SKB_FRAGS;
+
+ /* make sure that all changes to the dma ring are flushed before we
diff --git a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch
deleted file mode 100644
index b852e67470..0000000000
--- a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-WIP.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-From 34e10b96d5ccb99fb78251051bc5652b09359983 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 28 Apr 2016 07:58:22 +0200
-Subject: [PATCH 91/91] net-next: mediatek WIP
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 89 ++++++++++++---------------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +-
- 2 files changed, 44 insertions(+), 50 deletions(-)
-
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 5d33053..2e05920 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -326,7 +326,7 @@ static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
- /* flush write */
-- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+// mtk_r32(eth, MTK_QDMA_INT_MASK);
- spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
-@@ -339,7 +339,7 @@ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
- val = mtk_r32(eth, MTK_QDMA_INT_MASK);
- mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
- /* flush write */
-- mtk_r32(eth, MTK_QDMA_INT_MASK);
-+// mtk_r32(eth, MTK_QDMA_INT_MASK);
- spin_unlock_irqrestore(&eth->irq_lock, flags);
- }
-
-@@ -710,10 +710,26 @@ static inline int mtk_cal_txd_req(struct sk_buff *skb)
- return nfrags;
- }
-
-+static int mtk_queue_stopped(struct mtk_eth *eth)
-+{
-+ int i;
-+
-+ for (i = 0; i < MTK_MAC_COUNT; i++) {
-+ if (!eth->netdev[i])
-+ continue;
-+ if (netif_queue_stopped(eth->netdev[i]))
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
- static void mtk_wake_queue(struct mtk_eth *eth)
- {
- int i;
-
-+ printk("%s:%s[%d]w\n", __FILE__, __func__, __LINE__);
-+
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -725,6 +741,7 @@ static void mtk_stop_queue(struct mtk_eth *eth)
- {
- int i;
-
-+ printk("%s:%s[%d]s\n", __FILE__, __func__, __LINE__);
- for (i = 0; i < MTK_MAC_COUNT; i++) {
- if (!eth->netdev[i])
- continue;
-@@ -775,12 +792,9 @@ static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
- goto drop;
-
-- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
-+ if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
- mtk_stop_queue(eth);
-- if (unlikely(atomic_read(&ring->free_count) >
-- ring->thresh))
-- mtk_wake_queue(eth);
-- }
-+
- spin_unlock_irqrestore(&eth->page_lock, flags);
-
- return NETDEV_TX_OK;
-@@ -927,7 +941,6 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)
- }
- mtk_tx_unmap(eth->dev, tx_buf);
-
-- ring->last_free->txd2 = next_cpu;
- ring->last_free = desc;
- atomic_inc(&ring->free_count);
-
-@@ -945,11 +958,8 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget)
- netdev_completed_queue(eth->netdev[i], done, bytes);
- }
-
-- /* read hw index again make sure no new tx packet */
-- if (cpu == dma && cpu == mtk_r32(eth, MTK_QTX_DRX_PTR))
-- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
--
-- if (atomic_read(&ring->free_count) > ring->thresh)
-+ if (mtk_queue_stopped(eth) &&
-+ (atomic_read(&ring->free_count) > ring->thresh))
- mtk_wake_queue(eth);
-
- return done;
-@@ -973,10 +983,11 @@ static int mtk_napi_tx(struct napi_struct *napi, int budget)
- int tx_done = 0;
-
- mtk_handle_status_irq(eth);
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
- tx_done = mtk_poll_tx(eth, budget);
-+
- if (unlikely(netif_msg_intr(eth))) {
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
- dev_info(eth->dev,
- "done tx %d, intr 0x%08x/0x%x\n",
-@@ -1002,9 +1013,12 @@ static int mtk_napi_rx(struct napi_struct *napi, int budget)
- u32 status, mask;
- int rx_done = 0;
-
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ mtk_handle_status_irq(eth);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
- rx_done = mtk_poll_rx(napi, budget, eth);
-+
- if (unlikely(netif_msg_intr(eth))) {
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
- dev_info(eth->dev,
- "done rx %d, intr 0x%08x/0x%x\n",
-@@ -1052,9 +1066,8 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
-
- atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
- ring->next_free = &ring->dma[0];
-- ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
-- ring->thresh = max((unsigned long)MTK_DMA_SIZE >> 2,
-- MAX_SKB_FRAGS);
-+ ring->last_free = &ring->dma[MTK_DMA_SIZE - 1];
-+ ring->thresh = MAX_SKB_FRAGS;
-
- /* make sure that all changes to the dma ring are flushed before we
- * continue
-@@ -1259,21 +1272,11 @@ static void mtk_tx_timeout(struct net_device *dev)
- static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- {
- struct mtk_eth *eth = _eth;
-- u32 status;
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- status &= ~MTK_TX_DONE_INT;
--
-- if (unlikely(!status))
-- return IRQ_NONE;
-
-- if (status & MTK_RX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->rx_napi))) {
-- mtk_irq_disable(eth, MTK_RX_DONE_INT);
-- __napi_schedule(&eth->rx_napi);
-- }
-+ if (likely(napi_schedule_prep(&eth->rx_napi))) {
-+ __napi_schedule(&eth->rx_napi);
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
- }
-- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
- return IRQ_HANDLED;
- }
-@@ -1281,21 +1284,11 @@ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
- static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
- {
- struct mtk_eth *eth = _eth;
-- u32 status;
--
-- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-- status &= ~MTK_RX_DONE_INT;
--
-- if (unlikely(!status))
-- return IRQ_NONE;
-
-- if (status & MTK_TX_DONE_INT) {
-- if (likely(napi_schedule_prep(&eth->tx_napi))) {
-- mtk_irq_disable(eth, MTK_TX_DONE_INT);
-- __napi_schedule(&eth->tx_napi);
-- }
-+ if (likely(napi_schedule_prep(&eth->tx_napi))) {
-+ __napi_schedule(&eth->tx_napi);
-+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
- }
-- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-
- return IRQ_HANDLED;
- }
-@@ -1326,7 +1319,7 @@ static int mtk_start_dma(struct mtk_eth *eth)
- mtk_w32(eth,
- MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
- MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
-- MTK_RX_BT_32DWORDS,
-+ MTK_RX_BT_32DWORDS | MTK_NDP_CO_PRO,
- MTK_QDMA_GLO_CFG);
-
- return 0;
-@@ -1440,7 +1433,7 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
-
- /* disable delay and normal interrupt */
- mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
-- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
-+ mtk_irq_disable(eth, ~0);
- mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
- mtk_w32(eth, 0, MTK_RST_GL);
-
-@@ -1765,7 +1758,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
-
- SET_NETDEV_DEV(eth->netdev[id], eth->dev);
-- eth->netdev[id]->watchdog_timeo = HZ;
-+ eth->netdev[id]->watchdog_timeo = 4 * HZ;
- eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
- eth->netdev[id]->base_addr = (unsigned long)eth->base;
- eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 5093518..6b22445 100644
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -18,9 +18,9 @@
- #define MTK_QDMA_PAGE_SIZE 2048
- #define MTK_MAX_RX_LENGTH 1536
- #define MTK_TX_DMA_BUF_LEN 0x3fff
--#define MTK_DMA_SIZE 256
--#define MTK_NAPI_WEIGHT 64
- #define MTK_MAC_COUNT 2
-+#define MTK_DMA_SIZE (256 * MTK_MAC_COUNT)
-+#define MTK_NAPI_WEIGHT (64 * MTK_MAC_COUNT)
- #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
- #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
- #define MTK_DMA_DUMMY_DESC 0xffffffff
-@@ -95,6 +95,7 @@
- #define MTK_QDMA_GLO_CFG 0x1A04
- #define MTK_RX_2B_OFFSET BIT(31)
- #define MTK_RX_BT_32DWORDS (3 << 11)
-+#define MTK_NDP_CO_PRO BIT(10)
- #define MTK_TX_WB_DDONE BIT(6)
- #define MTK_DMA_SIZE_16DWORDS (2 << 4)
- #define MTK_RX_DMA_BUSY BIT(3)
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch
new file mode 100644
index 0000000000..257634c4c3
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0091-net-next-mediatek-only-wake-the-queue-if-it-is-stopp.patch
@@ -0,0 +1,48 @@
+From 1473b4cce85760c0202a08e6a48ec51867dc1bf7 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 04:01:38 +0200
+Subject: [PATCH 091/102] net-next: mediatek: only wake the queue if it is
+ stopped
+
+The current code unconditionally wakes up the queue at the end of each
+tx_poll action. Change the code to only wake up the queues if any of
+them have actually been stopped before.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -716,6 +716,20 @@ static inline int mtk_cal_txd_req(struct
+ return nfrags;
+ }
+
++static int mtk_queue_stopped(struct mtk_eth *eth)
++{
++ int i;
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i])
++ continue;
++ if (netif_queue_stopped(eth->netdev[i]))
++ return 1;
++ }
++
++ return 0;
++}
++
+ static void mtk_wake_queue(struct mtk_eth *eth)
+ {
+ int i;
+@@ -960,7 +974,8 @@ static int mtk_poll_tx(struct mtk_eth *e
+ if (!total)
+ return 0;
+
+- if (atomic_read(&ring->free_count) > ring->thresh)
++ if (mtk_queue_stopped(eth) &&
++ (atomic_read(&ring->free_count) > ring->thresh))
+ mtk_wake_queue(eth);
+
+ return total;
diff --git a/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch b/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch
new file mode 100644
index 0000000000..fe08958b5c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0092-net-next-mediatek-remove-superfluous-queue-wake-up-c.patch
@@ -0,0 +1,36 @@
+From 538020913db04d199ce4d7e845444880e8200b5f Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 05:40:38 +0200
+Subject: [PATCH 092/102] net-next: mediatek: remove superfluous queue wake up
+ call
+
+The code checks if the queue should be stopped because we are below the
+threshold of free descriptors only to check if it should be started again.
+If we do end up in a state where we are at the threshold limit, it makes
+more sense to just stop the queue and wait for the next IRQ to trigger the
+TX housekeeping again. There is no rush in enqueuing the next packet, it
+needs to wait for all the others in the queue to be dispatched first
+anyway.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -795,12 +795,9 @@ static int mtk_start_xmit(struct sk_buff
+ if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
+ goto drop;
+
+- if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
++ if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
+ mtk_stop_queue(eth);
+- if (unlikely(atomic_read(&ring->free_count) >
+- ring->thresh))
+- mtk_wake_queue(eth);
+- }
++
+ spin_unlock_irqrestore(&eth->page_lock, flags);
+
+ return NETDEV_TX_OK;
diff --git a/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch b/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch
new file mode 100644
index 0000000000..3ddbbc6fd6
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0093-net-next-mediatek-remove-superfluous-register-reads.patch
@@ -0,0 +1,37 @@
+From 31428406bf4b9da2a322ae947096414ff0489fb5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 03:57:01 +0200
+Subject: [PATCH 093/102] net-next: mediatek: remove superfluous register
+ reads
+
+The driver was originally written for MIPS based SoC. These required the
+IRQ mask register to be read after writing it to ensure that the content
+was actually applied. As this version only works on ARM based SoC, we can
+safely remove the 2 reads as they ware not required.
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -335,8 +335,6 @@ static inline void mtk_irq_disable(struc
+
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+- /* flush write */
+- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ }
+
+ static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+@@ -345,8 +343,6 @@ static inline void mtk_irq_enable(struct
+
+ val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+- /* flush write */
+- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ }
+
+ static int mtk_set_mac_address(struct net_device *dev, void *p)
diff --git a/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch b/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch
new file mode 100644
index 0000000000..983d0c2712
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0094-net-next-mediatek-don-t-use-intermediate-variables-t.patch
@@ -0,0 +1,82 @@
+From 441d87495f33fd444a2b2a16f6df07892dac3f89 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 3 May 2016 04:12:35 +0200
+Subject: [PATCH 094/102] net-next: mediatek: don't use intermediate variables
+ to store IRQ masks
+
+The code currently uses variables to store and never modify the bit masks
+of interrupts. This is legacy code from an early version of the driver
+that supported MIPS based SoCs where the IRQ bits depended on the actual
+SoC. As the bits are the same for all ARM based SoC using this driver we
+can remove the intermediate variables.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -806,7 +806,7 @@ drop:
+ }
+
+ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+- struct mtk_eth *eth, u32 rx_intr)
++ struct mtk_eth *eth)
+ {
+ struct mtk_rx_ring *ring = &eth->rx_ring;
+ int idx = ring->calc_idx;
+@@ -894,7 +894,7 @@ release_desc:
+ }
+
+ if (done < budget)
+- mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+
+ return done;
+ }
+@@ -977,28 +977,26 @@ static int mtk_poll_tx(struct mtk_eth *e
+ static int mtk_poll(struct napi_struct *napi, int budget)
+ {
+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+- u32 status, status2, mask, tx_intr, rx_intr, status_intr;
++ u32 status, status2, mask;
+ int tx_done, rx_done;
+ bool tx_again = false;
+
+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ status2 = mtk_r32(eth, MTK_INT_STATUS2);
+- tx_intr = MTK_TX_DONE_INT;
+- rx_intr = MTK_RX_DONE_INT;
+- status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
+ tx_done = 0;
+ rx_done = 0;
+ tx_again = 0;
+
+- if (status & tx_intr)
++ if (status & MTK_TX_DONE_INT)
+ tx_done = mtk_poll_tx(eth, budget, &tx_again);
+
+- if (status & rx_intr)
+- rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
++ if (status & MTK_RX_DONE_INT)
++ rx_done = mtk_poll_rx(napi, budget, eth);
+
+- if (unlikely(status2 & status_intr)) {
++ if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) {
+ mtk_stats_update(eth);
+- mtk_w32(eth, status_intr, MTK_INT_STATUS2);
++ mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF),
++ MTK_INT_STATUS2);
+ }
+
+ if (unlikely(netif_msg_intr(eth))) {
+@@ -1016,7 +1014,7 @@ static int mtk_poll(struct napi_struct *
+ return budget;
+
+ napi_complete(napi);
+- mtk_irq_enable(eth, tx_intr | rx_intr);
++ mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT);
+
+ return rx_done;
+ }
diff --git a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch b/target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch
index 7278d83285..bf27aac15c 100644
--- a/target/linux/mediatek/patches-4.4/0087-net-next-mediatek-add-IRQ-locking.patch
+++ b/target/linux/mediatek/patches-4.4/0095-net-next-mediatek-add-IRQ-locking.patch
@@ -1,7 +1,7 @@
-From 4ff9304355036d4a00bdf0e47e869fc770ba1cc5 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Wed, 20 Apr 2016 16:18:07 +0200
-Subject: [PATCH 87/91] net-next: mediatek: add IRQ locking
+From dd08d1ac4cfc86fbea5ee207b9615922ede88ec6 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 17 May 2016 06:01:45 +0200
+Subject: [PATCH 095/102] net-next: mediatek: add IRQ locking
The code that enables and disables IRQs is missing proper locking. After
adding the IRQ separation patch and routing the putting the RX and TX IRQs
@@ -10,17 +10,16 @@ locking. We use a dedicated lock to reduce the latency if the IRQ code.
Otherwise it might wait for bottom code to finish before reenabling or
disabling IRQs.
-Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++++
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
2 files changed, 8 insertions(+)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 24a4179..f86d551 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -316,22 +316,28 @@ static void mtk_mdio_cleanup(struct mtk_eth *eth)
+@@ -331,18 +331,24 @@ static void mtk_mdio_cleanup(struct mtk_
static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
{
@@ -30,8 +29,6 @@ index 24a4179..f86d551 100644
+ spin_lock_irqsave(&eth->irq_lock, flags);
val = mtk_r32(eth, MTK_QDMA_INT_MASK);
mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
- /* flush write */
- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ spin_unlock_irqrestore(&eth->irq_lock, flags);
}
@@ -43,13 +40,11 @@ index 24a4179..f86d551 100644
+ spin_lock_irqsave(&eth->irq_lock, flags);
val = mtk_r32(eth, MTK_QDMA_INT_MASK);
mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
- /* flush write */
- mtk_r32(eth, MTK_QDMA_INT_MASK);
+ spin_unlock_irqrestore(&eth->irq_lock, flags);
}
static int mtk_set_mac_address(struct net_device *dev, void *p)
-@@ -1752,6 +1758,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1771,6 +1777,7 @@ static int mtk_probe(struct platform_dev
return -EADDRNOTAVAIL;
spin_lock_init(&eth->page_lock);
@@ -57,11 +52,9 @@ index 24a4179..f86d551 100644
eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"mediatek,ethsys");
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 57f7e8a..8220275 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -372,6 +372,7 @@ struct mtk_eth {
+@@ -373,6 +373,7 @@ struct mtk_eth {
void __iomem *base;
struct reset_control *rstc;
spinlock_t page_lock;
@@ -69,6 +62,3 @@ index 57f7e8a..8220275 100644
struct net_device dummy_dev;
struct net_device *netdev[MTK_MAX_DEVS];
struct mtk_mac *mac[MTK_MAX_DEVS];
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch b/target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch
index 28183b9098..727073ebcd 100644
--- a/target/linux/mediatek/patches-4.4/0088-net-next-mediatek-add-support-for-IRQ-grouping.patch
+++ b/target/linux/mediatek/patches-4.4/0096-net-next-mediatek-add-support-for-IRQ-grouping.patch
@@ -1,40 +1,23 @@
-From 41b4500871ab5b1ef27c6fb49ffd8aac8c7e5009 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
+From 190df1a9dbf4d8809b7f991194ce60e47f2290a2 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
Date: Wed, 23 Mar 2016 18:31:48 +0100
-Subject: [PATCH 88/91] net-next: mediatek: add support for IRQ grouping
+Subject: [PATCH 096/102] net-next: mediatek: add support for IRQ grouping
The ethernet core has 3 IRQs. using the IRQ grouping registers we are able
to separate TX and RX IRQs, which allows us to service them on separate
-cores. This patch splits the irq handler into 2 separate functiosn, one for
-TX and another for RX. The TX housekeeping is split out of the NAPI handler.
-Instead we use a tasklet to handle housekeeping.
+cores. This patch splits the irq handler into 2 separate functions, one for
+TX and another for RX. The TX housekeeping is split out into its own NAPI
+handler.
-Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: John Crispin <john@phrozen.org>
---
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 164 ++++++++++++++++++---------
- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 16 ++-
- 2 files changed, 124 insertions(+), 56 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 156 +++++++++++++++++----------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++-
+ 2 files changed, 111 insertions(+), 60 deletions(-)
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index f86d551..6557026 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -790,7 +790,7 @@ drop:
- }
-
- static int mtk_poll_rx(struct napi_struct *napi, int budget,
-- struct mtk_eth *eth, u32 rx_intr)
-+ struct mtk_eth *eth)
- {
- struct mtk_rx_ring *ring = &eth->rx_ring;
- int idx = ring->calc_idx;
-@@ -878,19 +878,18 @@ release_desc:
- }
-
- if (done < budget)
-- mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS);
-+ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
-
+@@ -905,14 +905,13 @@ release_desc:
return done;
}
@@ -51,20 +34,21 @@ index f86d551..6557026 100644
u32 cpu, dma;
static int condition;
int i;
-@@ -944,63 +943,80 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+@@ -964,63 +963,82 @@ static int mtk_poll_tx(struct mtk_eth *e
+ netdev_completed_queue(eth->netdev[i], done, bytes);
}
- /* read hw index again make sure no new tx packet */
+- /* read hw index again make sure no new tx packet */
- if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR))
- *tx_again = true;
- else
-+ if (cpu == dma && cpu == mtk_r32(eth, MTK_QTX_DRX_PTR))
- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
-
+- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
+-
- if (!total)
- return 0;
-
- if (atomic_read(&ring->free_count) > ring->thresh)
+ if (mtk_queue_stopped(eth) &&
+ (atomic_read(&ring->free_count) > ring->thresh))
mtk_wake_queue(eth);
- return total;
@@ -75,33 +59,30 @@ index f86d551..6557026 100644
+static void mtk_handle_status_irq(struct mtk_eth *eth)
{
- struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
-- u32 status, status2, mask, tx_intr, rx_intr, status_intr;
+- u32 status, status2, mask;
- int tx_done, rx_done;
- bool tx_again = false;
-
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
- status2 = mtk_r32(eth, MTK_INT_STATUS2);
-- tx_intr = MTK_TX_DONE_INT;
-- rx_intr = MTK_RX_DONE_INT;
-- status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
- tx_done = 0;
- rx_done = 0;
- tx_again = 0;
-
-- if (status & tx_intr)
+- if (status & MTK_TX_DONE_INT)
- tx_done = mtk_poll_tx(eth, budget, &tx_again);
-
-- if (status & rx_intr)
-- rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
+- if (status & MTK_RX_DONE_INT)
+- rx_done = mtk_poll_rx(napi, budget, eth);
+ u32 status2 = mtk_r32(eth, MTK_INT_STATUS2);
-+ u32 status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
- if (unlikely(status2 & status_intr)) {
+ if (unlikely(status2 & (MTK_GDM1_AF | MTK_GDM2_AF))) {
mtk_stats_update(eth);
- mtk_w32(eth, status_intr, MTK_INT_STATUS2);
+ mtk_w32(eth, (MTK_GDM1_AF | MTK_GDM2_AF),
+ MTK_INT_STATUS2);
}
+}
-
++
+static int mtk_napi_tx(struct napi_struct *napi, int budget)
+{
+ struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi);
@@ -109,10 +90,11 @@ index f86d551..6557026 100644
+ int tx_done = 0;
+
+ mtk_handle_status_irq(eth);
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
++ mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
+ tx_done = mtk_poll_tx(eth, budget);
+
if (unlikely(netif_msg_intr(eth))) {
++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
- netdev_info(eth->netdev[0],
- "done tx %d, rx %d, intr 0x%08x/0x%x\n",
@@ -132,7 +114,7 @@ index f86d551..6557026 100644
return budget;
napi_complete(napi);
-- mtk_irq_enable(eth, tx_intr | rx_intr);
+- mtk_irq_enable(eth, MTK_RX_DONE_INT | MTK_RX_DONE_INT);
+ mtk_irq_enable(eth, MTK_TX_DONE_INT);
+
+ return tx_done;
@@ -144,9 +126,12 @@ index f86d551..6557026 100644
+ u32 status, mask;
+ int rx_done = 0;
+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
++ mtk_handle_status_irq(eth);
++ mtk_w32(eth, MTK_RX_DONE_INT, MTK_QMTK_INT_STATUS);
+ rx_done = mtk_poll_rx(napi, budget, eth);
++
+ if (unlikely(netif_msg_intr(eth))) {
++ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+ mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+ dev_info(eth->dev,
+ "done rx %d, intr 0x%08x/0x%x\n",
@@ -165,7 +150,7 @@ index f86d551..6557026 100644
return rx_done;
}
-@@ -1237,22 +1253,44 @@ static void mtk_tx_timeout(struct net_device *dev)
+@@ -1256,22 +1274,26 @@ static void mtk_tx_timeout(struct net_de
schedule_work(&eth->pending_work);
}
@@ -173,49 +158,37 @@ index f86d551..6557026 100644
+static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
{
struct mtk_eth *eth = _eth;
- u32 status;
+- u32 status;
- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ status &= ~MTK_TX_DONE_INT;
-+
- if (unlikely(!status))
- return IRQ_NONE;
+- status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+- if (unlikely(!status))
+- return IRQ_NONE;
++ if (likely(napi_schedule_prep(&eth->rx_napi))) {
++ __napi_schedule(&eth->rx_napi);
++ mtk_irq_disable(eth, MTK_RX_DONE_INT);
++ }
- if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) {
-+ if (status & MTK_RX_DONE_INT) {
- if (likely(napi_schedule_prep(&eth->rx_napi)))
- __napi_schedule(&eth->rx_napi);
+- if (likely(napi_schedule_prep(&eth->rx_napi)))
+- __napi_schedule(&eth->rx_napi);
- } else {
- mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-+ mtk_irq_disable(eth, MTK_RX_DONE_INT);
-+ }
-+ mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
-+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_handle_irq_tx(int irq, void *_eth)
+{
+ struct mtk_eth *eth = _eth;
-+ u32 status;
-+
-+ status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
-+ status &= ~MTK_RX_DONE_INT;
-+
-+ if (unlikely(!status))
-+ return IRQ_NONE;
+
-+ if (status & MTK_TX_DONE_INT) {
-+ if (likely(napi_schedule_prep(&eth->tx_napi)))
-+ __napi_schedule(&eth->tx_napi);
++ if (likely(napi_schedule_prep(&eth->tx_napi))) {
++ __napi_schedule(&eth->tx_napi);
+ mtk_irq_disable(eth, MTK_TX_DONE_INT);
}
- mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT));
-+ mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
return IRQ_HANDLED;
}
-@@ -1265,7 +1303,7 @@ static void mtk_poll_controller(struct net_device *dev)
+@@ -1284,7 +1306,7 @@ static void mtk_poll_controller(struct n
u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
mtk_irq_disable(eth, int_mask);
@@ -224,7 +197,7 @@ index f86d551..6557026 100644
mtk_irq_enable(eth, int_mask);
}
#endif
-@@ -1301,6 +1339,7 @@ static int mtk_open(struct net_device *dev)
+@@ -1320,6 +1342,7 @@ static int mtk_open(struct net_device *d
if (err)
return err;
@@ -232,7 +205,7 @@ index f86d551..6557026 100644
napi_enable(&eth->rx_napi);
mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
}
-@@ -1349,6 +1388,7 @@ static int mtk_stop(struct net_device *dev)
+@@ -1368,6 +1391,7 @@ static int mtk_stop(struct net_device *d
return 0;
mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
@@ -240,7 +213,7 @@ index f86d551..6557026 100644
napi_disable(&eth->rx_napi);
mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
-@@ -1386,7 +1426,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
+@@ -1405,7 +1429,11 @@ static int __init mtk_hw_init(struct mtk
/* Enable RX VLan Offloading */
mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
@@ -253,7 +226,7 @@ index f86d551..6557026 100644
dev_name(eth->dev), eth);
if (err)
return err;
-@@ -1402,7 +1446,11 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
+@@ -1421,7 +1449,11 @@ static int __init mtk_hw_init(struct mtk
mtk_w32(eth, 0, MTK_RST_GL);
/* FE int grouping */
@@ -266,7 +239,7 @@ index f86d551..6557026 100644
for (i = 0; i < 2; i++) {
u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
-@@ -1450,7 +1498,9 @@ static void mtk_uninit(struct net_device *dev)
+@@ -1469,7 +1501,9 @@ static void mtk_uninit(struct net_device
phy_disconnect(mac->phy_dev);
mtk_mdio_cleanup(eth);
mtk_irq_disable(eth, ~0);
@@ -277,7 +250,7 @@ index f86d551..6557026 100644
}
static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-@@ -1725,10 +1775,10 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1744,10 +1778,10 @@ static int mtk_add_mac(struct mtk_eth *e
dev_err(eth->dev, "error bringing up device\n");
goto free_netdev;
}
@@ -290,7 +263,7 @@ index f86d551..6557026 100644
return 0;
-@@ -1745,6 +1795,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1764,6 +1798,7 @@ static int mtk_probe(struct platform_dev
struct mtk_soc_data *soc;
struct mtk_eth *eth;
int err;
@@ -298,7 +271,7 @@ index f86d551..6557026 100644
match = of_match_device(of_mtk_match, &pdev->dev);
soc = (struct mtk_soc_data *)match->data;
-@@ -1780,10 +1831,12 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1799,10 +1834,12 @@ static int mtk_probe(struct platform_dev
return PTR_ERR(eth->rstc);
}
@@ -315,7 +288,7 @@ index f86d551..6557026 100644
}
eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
-@@ -1824,7 +1877,9 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1843,7 +1880,9 @@ static int mtk_probe(struct platform_dev
* for NAPI to work
*/
init_dummy_netdev(&eth->dummy_dev);
@@ -326,7 +299,7 @@ index f86d551..6557026 100644
MTK_NAPI_WEIGHT);
platform_set_drvdata(pdev, eth);
-@@ -1845,6 +1900,7 @@ static int mtk_remove(struct platform_device *pdev)
+@@ -1864,6 +1903,7 @@ static int mtk_remove(struct platform_de
clk_disable_unprepare(eth->clk_gp1);
clk_disable_unprepare(eth->clk_gp2);
@@ -334,8 +307,6 @@ index f86d551..6557026 100644
netif_napi_del(&eth->rx_napi);
mtk_cleanup(eth);
platform_set_drvdata(pdev, NULL);
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 8220275..bf158f8 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -68,6 +68,10 @@
@@ -349,7 +320,7 @@ index 8220275..bf158f8 100644
/* QDMA TX Queue Configuration Registers */
#define MTK_QTX_CFG(x) (0x1800 + (x * 0x10))
#define QDMA_RES_THRES 4
-@@ -124,6 +128,11 @@
+@@ -125,6 +129,11 @@
#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
@@ -361,7 +332,7 @@ index 8220275..bf158f8 100644
/* QDMA Interrupt Status Register */
#define MTK_QDMA_INT_MASK 0x1A1C
-@@ -355,7 +364,8 @@ struct mtk_rx_ring {
+@@ -356,7 +365,8 @@ struct mtk_rx_ring {
* @dma_refcnt: track how many netdevs are using the DMA engine
* @tx_ring: Pointer to the memore holding info about the TX ring
* @rx_ring: Pointer to the memore holding info about the RX ring
@@ -371,7 +342,7 @@ index 8220275..bf158f8 100644
* @scratch_ring: Newer SoCs need memory for a second HW managed TX ring
* @phy_scratch_ring: physical address of scratch_ring
* @scratch_head: The scratch memory that scratch_ring points to.
-@@ -376,7 +386,7 @@ struct mtk_eth {
+@@ -377,7 +387,7 @@ struct mtk_eth {
struct net_device dummy_dev;
struct net_device *netdev[MTK_MAX_DEVS];
struct mtk_mac *mac[MTK_MAX_DEVS];
@@ -380,7 +351,7 @@ index 8220275..bf158f8 100644
u32 msg_enable;
unsigned long sysclk;
struct regmap *ethsys;
-@@ -384,6 +394,7 @@ struct mtk_eth {
+@@ -385,6 +395,7 @@ struct mtk_eth {
atomic_t dma_refcnt;
struct mtk_tx_ring tx_ring;
struct mtk_rx_ring rx_ring;
@@ -388,14 +359,3 @@ index 8220275..bf158f8 100644
struct napi_struct rx_napi;
struct mtk_tx_dma *scratch_ring;
dma_addr_t phy_scratch_ring;
-@@ -394,6 +405,7 @@ struct mtk_eth {
- struct clk *clk_gp2;
- struct mii_bus *mii_bus;
- struct work_struct pending_work;
-+
- };
-
- /* struct mtk_mac - the structure that holds the info about the MACs of the
---
-1.7.10.4
-
diff --git a/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch b/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch
new file mode 100644
index 0000000000..cc18be53b4
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0098-net-next-mediatek-only-trigger-the-tx-watchdog-reset.patch
@@ -0,0 +1,57 @@
+From cd1343c14328a5de1a58c47b81b8a2febb31d542 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Tue, 10 May 2016 11:16:30 +0200
+Subject: [PATCH 098/102] net-next: mediatek: only trigger the tx watchdog
+ reset when all devices are stalled
+
+Signed-off-by: Sean Wang <keyhaede@gmail.com>
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 14 ++++++++++++--
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1267,11 +1267,21 @@ static void mtk_tx_timeout(struct net_de
+ {
+ struct mtk_mac *mac = netdev_priv(dev);
+ struct mtk_eth *eth = mac->hw;
++ int i, reset = 0;
+
+ eth->netdev[mac->id]->stats.tx_errors++;
+ netif_err(eth, tx_err, dev,
+ "transmit timed out\n");
+- schedule_work(&eth->pending_work);
++
++ for (i = 0; i < MTK_MAC_COUNT; i++) {
++ if (!eth->netdev[i] ||
++ time_after(jiffies, dev_trans_start(eth->netdev[i]) +
++ MTK_WDT_TIMEOUT))
++ reset++;
++ }
++
++ if (reset == MTK_MAC_COUNT)
++ schedule_work(&eth->pending_work);
+ }
+
+ static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
+@@ -1765,7 +1775,7 @@ static int mtk_add_mac(struct mtk_eth *e
+ mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+ SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+- eth->netdev[id]->watchdog_timeo = 5 * HZ;
++ eth->netdev[id]->watchdog_timeo = MTK_WDT_TIMEOUT;
+ eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+ eth->netdev[id]->base_addr = (unsigned long)eth->base;
+ eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -15,6 +15,7 @@
+ #ifndef MTK_ETH_H
+ #define MTK_ETH_H
+
++#define MTK_WDT_TIMEOUT (4 * HZ)
+ #define MTK_QDMA_PAGE_SIZE 2048
+ #define MTK_MAX_RX_LENGTH 1536
+ #define MTK_TX_DMA_BUF_LEN 0x3fff
diff --git a/target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch
index f035b24e05..4d931fc0fa 100644
--- a/target/linux/mediatek/patches-4.4/0089-net-mediatek-add-gsw-mt7530-driver.patch
+++ b/target/linux/mediatek/patches-4.4/0101-net-mediatek-add-gsw-mt7530-driver.patch
@@ -1,7 +1,7 @@
-From 46f10e3c9c25668efb85babe9ac5e37d019c2794 Mon Sep 17 00:00:00 2001
+From 6b8a7257e7bcb56782c3f8048311670fe6a80209 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 11 Apr 2016 03:11:54 +0200
-Subject: [PATCH 89/91] net: mediatek add gsw/mt7530 driver
+Subject: [PATCH 101/102] net: mediatek add gsw/mt7530 driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
@@ -11,15 +11,13 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
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 | 4 +
- 7 files changed, 2198 insertions(+), 30 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +
+ 7 files changed, 2199 insertions(+), 30 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/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 @@
@@ -28,9 +26,6 @@ index aa3f1c8..82001c4 100644
-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..6fca8f2
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h
@@ -0,0 +1,251 @@
@@ -285,9 +280,6 @@ index 0000000..6fca8f2
+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..0c6b8a6
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c
@@ -0,0 +1,1084 @@
@@ -1375,9 +1367,6 @@ index 0000000..0c6b8a6
+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 @@
@@ -2189,9 +2178,6 @@ index 0000000..2e9d280
+
+ 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 @@
@@ -2215,8 +2201,6 @@ index 0000000..1fc8c62
+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 6557026..bb62b91 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -24,6 +24,9 @@
@@ -2229,7 +2213,7 @@ index 6557026..bb62b91 100644
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)
+@@ -69,7 +72,7 @@ static int mtk_mdio_busy_wait(struct mtk
return 0;
if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
break;
@@ -2238,7 +2222,7 @@ index 6557026..bb62b91 100644
}
dev_err(eth->dev, "mdio: MDIO timeout\n");
-@@ -1408,15 +1411,6 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
+@@ -1421,15 +1424,6 @@ static int __init mtk_hw_init(struct mtk
reset_control_deassert(eth->rstc);
usleep_range(10, 20);
@@ -2254,7 +2238,7 @@ index 6557026..bb62b91 100644
/* GE1, Force 1000M/FD, FC ON */
mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0));
-@@ -1439,6 +1433,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
+@@ -1452,6 +1446,8 @@ static int __init mtk_hw_init(struct mtk
if (err)
return err;
@@ -2262,8 +2246,8 @@ index 6557026..bb62b91 100644
+
/* disable delay and normal interrupt */
mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
- mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
-@@ -1466,6 +1462,8 @@ static int __init mtk_hw_init(struct mtk_eth *eth)
+ mtk_irq_disable(eth, ~0);
+@@ -1479,6 +1475,8 @@ static int __init mtk_hw_init(struct mtk
mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
}
@@ -2272,7 +2256,7 @@ index 6557026..bb62b91 100644
return 0;
}
-@@ -1721,7 +1719,7 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1734,7 +1732,7 @@ static int mtk_add_mac(struct mtk_eth *e
{
struct mtk_mac *mac;
const __be32 *_id = of_get_property(np, "reg", NULL);
@@ -2281,7 +2265,7 @@ index 6557026..bb62b91 100644
if (!_id) {
dev_err(eth->dev, "missing mac id\n");
-@@ -1755,8 +1753,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1768,8 +1766,8 @@ static int mtk_add_mac(struct mtk_eth *e
GFP_KERNEL);
if (!mac->hw_stats) {
dev_err(eth->dev, "failed to allocate counter memory\n");
@@ -2292,7 +2276,7 @@ index 6557026..bb62b91 100644
}
spin_lock_init(&mac->hw_stats->stats_lock);
mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
-@@ -1770,21 +1768,9 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+@@ -1783,21 +1781,9 @@ static int mtk_add_mac(struct mtk_eth *e
eth->netdev[id]->features |= MTK_HW_FEATURES;
eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
@@ -2314,7 +2298,7 @@ index 6557026..bb62b91 100644
}
static int mtk_probe(struct platform_device *pdev)
-@@ -1852,14 +1838,13 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1865,14 +1851,13 @@ static int mtk_probe(struct platform_dev
clk_prepare_enable(eth->clk_gp1);
clk_prepare_enable(eth->clk_gp2);
@@ -2332,7 +2316,7 @@ index 6557026..bb62b91 100644
for_each_child_of_node(pdev->dev.of_node, mac_np) {
if (!of_device_is_compatible(mac_np,
"mediatek,eth-mac"))
-@@ -1873,6 +1858,22 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -1886,6 +1871,22 @@ static int mtk_probe(struct platform_dev
goto err_free_dev;
}
@@ -2355,26 +2339,22 @@ index 6557026..bb62b91 100644
/* we run 2 devices on the same DMA ring so we need a dummy device
* for NAPI to work
*/
-diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index bf158f8..5093518 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -406,6 +406,8 @@ struct mtk_eth {
+@@ -407,6 +407,9 @@ struct mtk_eth {
+ struct clk *clk_gp2;
struct mii_bus *mii_bus;
struct work_struct pending_work;
-
++
+ struct device_node *switch_np;
+ void *sw_priv;
};
/* struct mtk_mac - the structure that holds the info about the MACs of the
-@@ -433,4 +435,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
+@@ -434,4 +437,6 @@ void mtk_stats_update_mac(struct mtk_mac
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+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/0102-net-mediatek-v4.4-backports.patch b/target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch
new file mode 100644
index 0000000000..3561b4020c
--- /dev/null
+++ b/target/linux/mediatek/patches-4.4/0102-net-mediatek-v4.4-backports.patch
@@ -0,0 +1,46 @@
+From c1ff5519a7fd849da5d169036d8175383f807962 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 11 Apr 2016 06:00:23 +0200
+Subject: [PATCH 102/102] net: mediatek: v4.4 backports
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -217,7 +217,7 @@ static int mtk_phy_connect_node(struct m
+
+ 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;
+@@ -1396,6 +1396,7 @@ static int mtk_stop(struct net_device *d
+ 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);
+
+@@ -1595,11 +1596,13 @@ static int mtk_set_settings(struct net_d
+ {
+ 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);
diff --git a/target/linux/mediatek/patches-4.4/0200-devicetree.patch b/target/linux/mediatek/patches-4.4/0200-devicetree.patch
index 0f2ba50885..eb743c7247 100644
--- a/target/linux/mediatek/patches-4.4/0200-devicetree.patch
+++ b/target/linux/mediatek/patches-4.4/0200-devicetree.patch
@@ -1,6 +1,6 @@
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
-@@ -775,6 +775,8 @@
+@@ -775,6 +775,8 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt6589-aquaris5.dtb \
mt6592-evb.dtb \
mt7623-evb.dtb \
diff --git a/target/linux/mediatek/patches-4.4/0100-block2mtd.patch b/target/linux/mediatek/patches-4.4/0201-block2mtd.patch
index 395884b730..395884b730 100644
--- a/target/linux/mediatek/patches-4.4/0100-block2mtd.patch
+++ b/target/linux/mediatek/patches-4.4/0201-block2mtd.patch