From c46ccb69d17e584479df849a107423175a143c83 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 24 Oct 2020 21:15:20 +0200 Subject: mediatek: mt7622: add Linux 5.10 support Switch mt7622 subtarget to Linux 5.10, it has been tested by many of us on several devices for a couple of weeks already. Signed-off-by: Felix Fietkau --- .../patches-5.10/100-dts-update-mt7622-rfb1.patch | 119 ++ .../patches-5.10/101-dts-update-mt7629-rfb.patch | 37 + .../patches-5.10/110-dts-fix-bpi2-console.patch | 10 + .../patches-5.10/111-dts-fix-bpi64-console.patch | 11 + .../130-dts-mt7629-add-snand-support.patch | 97 ++ .../131-dts-mt7622-add-snand-support.patch | 96 ++ .../140-dts-fix-wmac-support-for-mt7622-rfb1.patch | 18 + ...50-dts-mt7623-eip97-inside-secure-support.patch | 23 + .../200-phy-phy-mtk-tphy-Add-hifsys-support.patch | 66 ++ ...c-move-mtk-ecc-header-file-to-include-mtd.patch | 139 +++ .../310-mtd-spinand-disable-on-die-ECC.patch | 31 + ...-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch | 1246 ++++++++++++++++++++ .../patches-5.10/330-mtk-bmt-support.patch | 840 +++++++++++++ ...00-crypto-add-eip97-inside-secure-support.patch | 27 + .../401-crypto-fix-eip97-cache-incoherent.patch | 26 + .../patches-5.10/410-bt-mtk-serial-fix.patch | 33 + .../500-gsw-rtl8367s-mt7622-support.patch | 25 + ...bindings-PCI-Mediatek-Update-PCIe-binding.patch | 415 +++++++ ...ek-Use-regmap-to-get-shared-pcie-cfg-base.patch | 217 ++++ ...ediatek-Split-PCIe-node-for-MT2712-MT7622.patch | 417 +++++++ ...-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch | 203 ++++ ...ie-mediatek-fix-clearing-interrupt-status.patch | 24 + ...t-mtk_eth_soc-add-support-for-coherent-DM.patch | 85 ++ ...cie-mediatek-add-support-for-coherent-DMA.patch | 108 ++ 24 files changed, 4313 insertions(+) create mode 100644 target/linux/mediatek/patches-5.10/100-dts-update-mt7622-rfb1.patch create mode 100644 target/linux/mediatek/patches-5.10/101-dts-update-mt7629-rfb.patch create mode 100644 target/linux/mediatek/patches-5.10/110-dts-fix-bpi2-console.patch create mode 100644 target/linux/mediatek/patches-5.10/111-dts-fix-bpi64-console.patch create mode 100644 target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch create mode 100644 target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch create mode 100644 target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch create mode 100644 target/linux/mediatek/patches-5.10/150-dts-mt7623-eip97-inside-secure-support.patch create mode 100644 target/linux/mediatek/patches-5.10/200-phy-phy-mtk-tphy-Add-hifsys-support.patch create mode 100644 target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch create mode 100644 target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch create mode 100644 target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch create mode 100644 target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch create mode 100644 target/linux/mediatek/patches-5.10/400-crypto-add-eip97-inside-secure-support.patch create mode 100644 target/linux/mediatek/patches-5.10/401-crypto-fix-eip97-cache-incoherent.patch create mode 100644 target/linux/mediatek/patches-5.10/410-bt-mtk-serial-fix.patch create mode 100644 target/linux/mediatek/patches-5.10/500-gsw-rtl8367s-mt7622-support.patch create mode 100644 target/linux/mediatek/patches-5.10/600-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch create mode 100644 target/linux/mediatek/patches-5.10/601-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch create mode 100644 target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch create mode 100644 target/linux/mediatek/patches-5.10/603-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch create mode 100644 target/linux/mediatek/patches-5.10/610-pcie-mediatek-fix-clearing-interrupt-status.patch create mode 100644 target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch create mode 100644 target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch (limited to 'target/linux/mediatek/patches-5.10') diff --git a/target/linux/mediatek/patches-5.10/100-dts-update-mt7622-rfb1.patch b/target/linux/mediatek/patches-5.10/100-dts-update-mt7622-rfb1.patch new file mode 100644 index 0000000000..f4e77cf69c --- /dev/null +++ b/target/linux/mediatek/patches-5.10/100-dts-update-mt7622-rfb1.patch @@ -0,0 +1,119 @@ +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -1,7 +1,6 @@ + /* +- * Copyright (c) 2017 MediaTek Inc. +- * Author: Ming Huang +- * Sean Wang ++ * Copyright (c) 2018 MediaTek Inc. ++ * Author: Ryder Lee + * + * SPDX-License-Identifier: (GPL-2.0 OR MIT) + */ +@@ -23,7 +22,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; + }; + + cpus { +@@ -40,23 +39,22 @@ + + gpio-keys { + compatible = "gpio-keys"; +- poll-interval = <100>; + + factory { + label = "factory"; + linux,code = ; +- gpios = <&pio 0 0>; ++ gpios = <&pio 0 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "wps"; + linux,code = ; +- gpios = <&pio 102 0>; ++ gpios = <&pio 102 GPIO_ACTIVE_LOW>; + }; + }; + + memory { +- reg = <0 0x40000000 0 0x20000000>; ++ reg = <0 0x40000000 0 0x40000000>; + }; + + reg_1p8v: regulator-1p8v { +@@ -132,22 +130,22 @@ + + port@0 { + reg = <0>; +- label = "lan0"; ++ label = "lan1"; + }; + + port@1 { + reg = <1>; +- label = "lan1"; ++ label = "lan2"; + }; + + port@2 { + reg = <2>; +- label = "lan2"; ++ label = "lan3"; + }; + + port@3 { + reg = <3>; +- label = "lan3"; ++ label = "lan4"; + }; + + port@4 { +@@ -236,15 +234,28 @@ + + &pcie { + pinctrl-names = "default"; +- pinctrl-0 = <&pcie0_pins>; ++ pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; + status = "okay"; + + pcie@0,0 { + status = "okay"; + }; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; + }; + + &pio { ++ /* Attention: GPIO 90 is used to switch between PCIe@1,0 and ++ * SATA functions. i.e. output-high: PCIe, output-low: SATA ++ */ ++ asm_sel { ++ gpio-hog; ++ gpios = <90 GPIO_ACTIVE_HIGH>; ++ output-high; ++ }; ++ + /* eMMC is shared pin with parallel NAND */ + emmc_pins_default: emmc-pins-default { + mux { +@@ -511,11 +522,11 @@ + }; + + &sata { +- status = "okay"; ++ status = "disabled"; + }; + + &sata_phy { +- status = "okay"; ++ status = "disabled"; + }; + + &spi0 { diff --git a/target/linux/mediatek/patches-5.10/101-dts-update-mt7629-rfb.patch b/target/linux/mediatek/patches-5.10/101-dts-update-mt7629-rfb.patch new file mode 100644 index 0000000000..8d3e283315 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/101-dts-update-mt7629-rfb.patch @@ -0,0 +1,37 @@ +--- a/arch/arm/boot/dts/mt7629-rfb.dts ++++ b/arch/arm/boot/dts/mt7629-rfb.dts +@@ -18,6 +18,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n8"; + }; + + gpio-keys { +@@ -69,6 +70,7 @@ + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; ++ mtd-mac-address = <&factory 0x2a>; + phy-mode = "2500base-x"; + fixed-link { + speed = <2500>; +@@ -80,6 +82,7 @@ + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; ++ mtd-mac-address = <&factory 0x24>; + phy-mode = "gmii"; + phy-handle = <&phy0>; + }; +@@ -133,8 +136,9 @@ + }; + + partition@b0000 { +- label = "kernel"; ++ label = "firmware"; + reg = <0xb0000 0xb50000>; ++ compatible = "denx,fit"; + }; + }; + }; diff --git a/target/linux/mediatek/patches-5.10/110-dts-fix-bpi2-console.patch b/target/linux/mediatek/patches-5.10/110-dts-fix-bpi2-console.patch new file mode 100644 index 0000000000..c696e7d369 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/110-dts-fix-bpi2-console.patch @@ -0,0 +1,10 @@ +--- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts ++++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +@@ -19,6 +19,7 @@ + + chosen { + stdout-path = "serial2:115200n8"; ++ bootargs = "console=ttyS2,115200n8"; + }; + + connector { diff --git a/target/linux/mediatek/patches-5.10/111-dts-fix-bpi64-console.patch b/target/linux/mediatek/patches-5.10/111-dts-fix-bpi64-console.patch new file mode 100644 index 0000000000..07a2eae245 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/111-dts-fix-bpi64-console.patch @@ -0,0 +1,11 @@ +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -22,7 +22,7 @@ + + chosen { + stdout-path = "serial0:115200n8"; +- bootargs = "earlycon=uart8250,mmio32,0x11002000 swiotlb=512"; ++ bootargs = "earlycon=uart8250,mmio32,0x11002000 console=ttyS0,115200n1 swiotlb=512"; + }; + + cpus { diff --git a/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch b/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch new file mode 100644 index 0000000000..479694b400 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/130-dts-mt7629-add-snand-support.patch @@ -0,0 +1,97 @@ +From c813fbe806257c574240770ef716fbee19f7dbfa Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou +Date: Thu, 6 Jun 2019 16:29:04 +0800 +Subject: [PATCH] spi: spi-mem: Mediatek: Add SPI Nand support for MT7629 + +Signed-off-by: Xiangsheng Hou +--- + arch/arm/boot/dts/mt7629-rfb.dts | 45 ++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/mt7629.dtsi | 22 ++++++++++++++++ + 3 files changed, 79 insertions(+) + +--- a/arch/arm/boot/dts/mt7629.dtsi ++++ b/arch/arm/boot/dts/mt7629.dtsi +@@ -272,6 +272,28 @@ + status = "disabled"; + }; + ++ bch: ecc@1100e000 { ++ compatible = "mediatek,mt7622-ecc"; ++ reg = <0x1100e000 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_NFIECC_PD>; ++ clock-names = "nfiecc_clk"; ++ status = "disabled"; ++ }; ++ ++ snfi: spi@1100d000 { ++ compatible = "mediatek,mt7629-snfi"; ++ reg = <0x1100d000 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, ++ <&pericfg CLK_PERI_SNFI_PD>; ++ clock-names = "nfi_clk", "spi_clk"; ++ ecc-engine = <&bch>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + spi: spi@1100a000 { + compatible = "mediatek,mt7629-spi", + "mediatek,mt7622-spi"; +--- a/arch/arm/boot/dts/mt7629-rfb.dts ++++ b/arch/arm/boot/dts/mt7629-rfb.dts +@@ -249,6 +249,52 @@ + }; + }; + ++&bch { ++ status = "okay"; ++}; ++ ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ status = "okay"; ++ ++ spi_nand@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ spi-max-frequency = <104000000>; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "Bootloader"; ++ reg = <0x00000 0x0100000>; ++ read-only; ++ }; ++ ++ partition@100000 { ++ label = "Config"; ++ reg = <0x100000 0x0040000>; ++ }; ++ ++ partition@140000 { ++ label = "factory"; ++ reg = <0x140000 0x0080000>; ++ }; ++ ++ partition@1c0000 { ++ label = "firmware"; ++ reg = <0x1c0000 0x1000000>; ++ }; ++ ++ }; ++ }; ++}; ++ + &spi { + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; diff --git a/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch new file mode 100644 index 0000000000..de96162e8a --- /dev/null +++ b/target/linux/mediatek/patches-5.10/131-dts-mt7622-add-snand-support.patch @@ -0,0 +1,96 @@ +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -554,6 +554,19 @@ + status = "disabled"; + }; + ++ snfi: spi@1100d000 { ++ compatible = "mediatek,mt7622-snfi"; ++ reg = <0 0x1100d000 0 0x1000>; ++ interrupts = ; ++ clocks = <&pericfg CLK_PERI_NFI_PD>, ++ <&pericfg CLK_PERI_SNFI_PD>; ++ clock-names = "nfi_clk", "spi_clk"; ++ ecc-engine = <&bch>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ + nor_flash: spi@11014000 { + compatible = "mediatek,mt7622-nor", + "mediatek,mt8173-nor"; +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -85,7 +85,7 @@ + }; + + &bch { +- status = "disabled"; ++ status = "okay"; + }; + + &btif { +@@ -529,6 +529,62 @@ + status = "disabled"; + }; + ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&serial_nand_pins>; ++ status = "okay"; ++ ++ spi_nand@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spi-nand"; ++ spi-max-frequency = <104000000>; ++ reg = <0>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "Preloader"; ++ reg = <0x00000 0x0080000>; ++ read-only; ++ }; ++ ++ partition@80000 { ++ label = "ATF"; ++ reg = <0x80000 0x0040000>; ++ }; ++ ++ partition@c0000 { ++ label = "Bootloader"; ++ reg = <0xc0000 0x0080000>; ++ }; ++ ++ partition@140000 { ++ label = "Config"; ++ reg = <0x140000 0x0080000>; ++ }; ++ ++ partition@1c0000 { ++ label = "Factory"; ++ reg = <0x1c0000 0x0100000>; ++ }; ++ ++ partition@200000 { ++ label = "firmware"; ++ reg = <0x2c0000 0x2000000>; ++ }; ++ ++ partition@2200000 { ++ label = "User_data"; ++ reg = <0x22c0000 0x4000000>; ++ }; ++ }; ++ }; ++}; ++ + &spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spic0_pins>; diff --git a/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch b/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch new file mode 100644 index 0000000000..d6d471520f --- /dev/null +++ b/target/linux/mediatek/patches-5.10/140-dts-fix-wmac-support-for-mt7622-rfb1.patch @@ -0,0 +1,18 @@ +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -567,7 +567,7 @@ + reg = <0x140000 0x0080000>; + }; + +- partition@1c0000 { ++ factory: partition@1c0000 { + label = "Factory"; + reg = <0x1c0000 0x0100000>; + }; +@@ -626,5 +626,6 @@ + }; + + &wmac { ++ mediatek,mtd-eeprom = <&factory 0x0000>; + status = "okay"; + }; diff --git a/target/linux/mediatek/patches-5.10/150-dts-mt7623-eip97-inside-secure-support.patch b/target/linux/mediatek/patches-5.10/150-dts-mt7623-eip97-inside-secure-support.patch new file mode 100644 index 0000000000..38947a3a94 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/150-dts-mt7623-eip97-inside-secure-support.patch @@ -0,0 +1,23 @@ +--- a/arch/arm/boot/dts/mt7623.dtsi ++++ b/arch/arm/boot/dts/mt7623.dtsi +@@ -949,17 +949,14 @@ + }; + + crypto: crypto@1b240000 { +- compatible = "mediatek,eip97-crypto"; ++ compatible = "inside-secure,safexcel-eip97"; + reg = <0 0x1b240000 0 0x20000>; + interrupts = , + , + , +- , +- ; ++ ; ++ interrupt-names = "ring0", "ring1", "ring2", "ring3"; + clocks = <ðsys CLK_ETHSYS_CRYPTO>; +- clock-names = "cryp"; +- power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; +- status = "disabled"; + }; + + bdpsys: syscon@1c000000 { diff --git a/target/linux/mediatek/patches-5.10/200-phy-phy-mtk-tphy-Add-hifsys-support.patch b/target/linux/mediatek/patches-5.10/200-phy-phy-mtk-tphy-Add-hifsys-support.patch new file mode 100644 index 0000000000..bd24ddc0c0 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/200-phy-phy-mtk-tphy-Add-hifsys-support.patch @@ -0,0 +1,66 @@ +From 28f9a5e2a3f5441ab5594669ed82da11e32277a9 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +Date: Mon, 30 Apr 2018 14:38:01 +0200 +Subject: [PATCH] phy: phy-mtk-tphy: Add hifsys-support + +--- + drivers/phy/mediatek/phy-mtk-tphy.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/drivers/phy/mediatek/phy-mtk-tphy.c ++++ b/drivers/phy/mediatek/phy-mtk-tphy.c +@@ -15,6 +15,8 @@ + #include + #include + #include ++#include ++#include + + /* version V1 sub-banks offset base address */ + /* banks shared by multiple phys */ +@@ -267,6 +269,9 @@ + #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) + #define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) + ++#define HIF_SYSCFG1 0x14 ++#define HIF_SYSCFG1_PHY2_MASK (0x3 << 20) ++ + enum mtk_phy_version { + MTK_PHY_V1 = 1, + MTK_PHY_V2, +@@ -315,6 +320,7 @@ struct mtk_tphy { + void __iomem *sif_base; /* only shared sif */ + const struct mtk_phy_pdata *pdata; + struct mtk_phy_instance **phys; ++ struct regmap *hif; + int nphys; + int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */ + int src_coef; /* coefficient for slew rate calibrate */ +@@ -634,6 +640,10 @@ static void pcie_phy_instance_init(struc + if (tphy->pdata->version != MTK_PHY_V1) + return; + ++ if (tphy->hif) ++ regmap_update_bits(tphy->hif, HIF_SYSCFG1, ++ HIF_SYSCFG1_PHY2_MASK, 0); ++ + tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0); + tmp &= ~(P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H); + tmp |= P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2); +@@ -1134,6 +1144,16 @@ static int mtk_tphy_probe(struct platfor + &tphy->src_ref_clk); + device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef); + ++ if (of_find_property(np, "mediatek,phy-switch", NULL)) { ++ tphy->hif = syscon_regmap_lookup_by_phandle(np, ++ "mediatek,phy-switch"); ++ if (IS_ERR(tphy->hif)) { ++ dev_err(&pdev->dev, ++ "missing \"mediatek,phy-switch\" phandle\n"); ++ return PTR_ERR(tphy->hif); ++ } ++ } ++ + port = 0; + for_each_child_of_node(np, child_np) { + struct mtk_phy_instance *instance; diff --git a/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch b/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch new file mode 100644 index 0000000000..d9ab339fa8 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/300-mtd-mtk-ecc-move-mtk-ecc-header-file-to-include-mtd.patch @@ -0,0 +1,139 @@ +From a2479dc254ebe31c84fbcfda73f35e2321576494 Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou +Date: Tue, 19 Mar 2019 13:57:38 +0800 +Subject: [PATCH 1/6] mtd: mtk ecc: move mtk ecc header file to include/mtd + +Change-Id: I8dc1d30e21b40d68ef5efd9587012f82970156a5 +Signed-off-by: Xiangsheng Hou +--- + drivers/mtd/nand/raw/mtk_ecc.c | 3 +-- + drivers/mtd/nand/raw/mtk_nand.c | 2 +- + {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h | 0 + 3 files changed, 2 insertions(+), 3 deletions(-) + rename {drivers/mtd/nand/raw => include/linux/mtd}/mtk_ecc.h (100%) + +--- a/drivers/mtd/nand/raw/mtk_ecc.c ++++ b/drivers/mtd/nand/raw/mtk_ecc.c +@@ -15,8 +15,7 @@ + #include + #include + #include +- +-#include "mtk_ecc.h" ++#include + + #define ECC_IDLE_MASK BIT(0) + #define ECC_IRQ_EN BIT(0) +--- a/drivers/mtd/nand/raw/mtk_nand.c ++++ b/drivers/mtd/nand/raw/mtk_nand.c +@@ -17,7 +17,7 @@ + #include + #include + #include +-#include "mtk_ecc.h" ++#include + + /* NAND controller register definition */ + #define NFI_CNFG (0x00) +--- /dev/null ++++ b/include/linux/mtd/mtk_ecc.h +@@ -0,0 +1,49 @@ ++/* ++ * MTK SDG1 ECC controller ++ * ++ * Copyright (c) 2016 Mediatek ++ * Authors: Xiaolei Li ++ * Jorge Ramirez-Ortiz ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__ ++#define __DRIVERS_MTD_NAND_MTK_ECC_H__ ++ ++#include ++ ++enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1}; ++enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE}; ++ ++struct device_node; ++struct mtk_ecc; ++ ++struct mtk_ecc_stats { ++ u32 corrected; ++ u32 bitflips; ++ u32 failed; ++}; ++ ++struct mtk_ecc_config { ++ enum mtk_ecc_operation op; ++ enum mtk_ecc_mode mode; ++ dma_addr_t addr; ++ u32 strength; ++ u32 sectors; ++ u32 len; ++}; ++ ++int mtk_ecc_encode(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_done(struct mtk_ecc *, enum mtk_ecc_operation); ++int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); ++void mtk_ecc_disable(struct mtk_ecc *); ++void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p); ++unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc); ++ ++struct mtk_ecc *of_mtk_ecc_get(struct device_node *); ++void mtk_ecc_release(struct mtk_ecc *); ++ ++#endif +--- a/drivers/mtd/nand/raw/mtk_ecc.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +-/* +- * MTK SDG1 ECC controller +- * +- * Copyright (c) 2016 Mediatek +- * Authors: Xiaolei Li +- * Jorge Ramirez-Ortiz +- */ +- +-#ifndef __DRIVERS_MTD_NAND_MTK_ECC_H__ +-#define __DRIVERS_MTD_NAND_MTK_ECC_H__ +- +-#include +- +-enum mtk_ecc_mode {ECC_DMA_MODE = 0, ECC_NFI_MODE = 1}; +-enum mtk_ecc_operation {ECC_ENCODE, ECC_DECODE}; +- +-struct device_node; +-struct mtk_ecc; +- +-struct mtk_ecc_stats { +- u32 corrected; +- u32 bitflips; +- u32 failed; +-}; +- +-struct mtk_ecc_config { +- enum mtk_ecc_operation op; +- enum mtk_ecc_mode mode; +- dma_addr_t addr; +- u32 strength; +- u32 sectors; +- u32 len; +-}; +- +-int mtk_ecc_encode(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_done(struct mtk_ecc *, enum mtk_ecc_operation); +-int mtk_ecc_enable(struct mtk_ecc *, struct mtk_ecc_config *); +-void mtk_ecc_disable(struct mtk_ecc *); +-void mtk_ecc_adjust_strength(struct mtk_ecc *ecc, u32 *p); +-unsigned int mtk_ecc_get_parity_bits(struct mtk_ecc *ecc); +- +-struct mtk_ecc *of_mtk_ecc_get(struct device_node *); +-void mtk_ecc_release(struct mtk_ecc *); +- +-#endif diff --git a/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch b/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch new file mode 100644 index 0000000000..e608113865 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/310-mtd-spinand-disable-on-die-ECC.patch @@ -0,0 +1,31 @@ +From b341f120cfc9ca1dfd48364b7f36ac2c1fbdea43 Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou +Date: Wed, 3 Apr 2019 16:30:01 +0800 +Subject: [PATCH 3/6] mtd: spinand: disable on-die ECC + +Change-Id: I9745adaed5295202fabbe8ab8947885c57a5b847 +Signed-off-by: Xiangsheng Hou +--- + drivers/mtd/nand/spi/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -493,7 +493,7 @@ static int spinand_mtd_read(struct mtd_i + int ret = 0; + + if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout) +- enable_ecc = true; ++ enable_ecc = false; + + mutex_lock(&spinand->lock); + +@@ -541,7 +541,7 @@ static int spinand_mtd_write(struct mtd_ + int ret = 0; + + if (ops->mode != MTD_OPS_RAW && mtd->ooblayout) +- enable_ecc = true; ++ enable_ecc = false; + + mutex_lock(&spinand->lock); + diff --git a/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch b/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch new file mode 100644 index 0000000000..53e2aed51e --- /dev/null +++ b/target/linux/mediatek/patches-5.10/320-spi-spi-mem-MediaTek-Add-SPI-NAND-Flash-interface-dr.patch @@ -0,0 +1,1246 @@ +From 1ecb38eabd90efe93957d0a822a167560c39308a Mon Sep 17 00:00:00 2001 +From: Xiangsheng Hou +Date: Wed, 20 Mar 2019 16:19:51 +0800 +Subject: [PATCH 6/6] spi: spi-mem: MediaTek: Add SPI NAND Flash interface + driver for MediaTek MT7622 + +Change-Id: I3e78406bb9b46b0049d3988a5c71c7069e4f809c +Signed-off-by: Xiangsheng Hou +--- + drivers/spi/Kconfig | 9 + + drivers/spi/Makefile | 1 + + drivers/spi/spi-mtk-snfi.c | 1183 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 1193 insertions(+) + create mode 100644 drivers/spi/spi-mtk-snfi.c + +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -67,6 +67,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mp + obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o + obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o + obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o ++obj-$(CONFIG_SPI_MTK_SNFI) += spi-mtk-snfi.o + obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o + obj-$(CONFIG_SPI_MTK_NOR) += spi-mtk-nor.o + obj-$(CONFIG_SPI_MXIC) += spi-mxic.o +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -495,6 +495,15 @@ config SPI_MT65XX + say Y or M here.If you are not sure, say N. + SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. + ++config SPI_MTK_SNFI ++ tristate "MediaTek SPI NAND interface" ++ select MTD_SPI_NAND ++ help ++ This selects the SPI NAND FLASH interface(SNFI), ++ which could be found on MediaTek Soc. ++ Say Y or M here.If you are not sure, say N. ++ Note Parallel Nand and SPI NAND is alternative on MediaTek SoCs. ++ + config SPI_MT7621 + tristate "MediaTek MT7621 SPI Controller" + depends on RALINK || COMPILE_TEST +--- /dev/null ++++ b/drivers/spi/spi-mtk-snfi.c +@@ -0,0 +1,1200 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for MediaTek SPI Nand interface ++ * ++ * Copyright (C) 2018 MediaTek Inc. ++ * Authors: Xiangsheng Hou ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* NAND controller register definition */ ++/* NFI control */ ++#define NFI_CNFG 0x00 ++#define CNFG_DMA 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_PROGRAM (3UL << 12) ++#define CNFG_OP_CUST (6UL << 12) ++#define NFI_PAGEFMT 0x04 ++#define PAGEFMT_512 0 ++#define PAGEFMT_2K 1 ++#define PAGEFMT_4K 2 ++#define PAGEFMT_FDM_SHIFT 8 ++#define PAGEFMT_FDM_ECC_SHIFT 12 ++#define NFI_CON 0x08 ++#define CON_FIFO_FLUSH BIT(0) ++#define CON_NFI_RST BIT(1) ++#define CON_BRD BIT(8) ++#define CON_BWR BIT(9) ++#define CON_SEC_SHIFT 12 ++#define NFI_INTR_EN 0x10 ++#define INTR_AHB_DONE_EN BIT(6) ++#define NFI_INTR_STA 0x14 ++#define NFI_CMD 0x20 ++#define NFI_STA 0x60 ++#define STA_EMP_PAGE BIT(12) ++#define NAND_FSM_MASK (0x1f << 24) ++#define NFI_FSM_MASK (0xf << 16) ++#define NFI_ADDRCNTR 0x70 ++#define CNTR_MASK GENMASK(16, 12) ++#define ADDRCNTR_SEC_SHIFT 12 ++#define ADDRCNTR_SEC(val) \ ++ (((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT) ++#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_MASTER_STA 0x224 ++#define MASTER_STA_MASK 0x0fff ++/* NFI_SPI control */ ++#define SNFI_MAC_OUTL 0x504 ++#define SNFI_MAC_INL 0x508 ++#define SNFI_RD_CTL2 0x510 ++#define RD_CMD_MASK 0x00ff ++#define RD_DUMMY_SHIFT 8 ++#define SNFI_RD_CTL3 0x514 ++#define RD_ADDR_MASK 0xffff ++#define SNFI_MISC_CTL 0x538 ++#define RD_MODE_X2 BIT(16) ++#define RD_MODE_X4 (2UL << 16) ++#define RD_QDUAL_IO (4UL << 16) ++#define RD_MODE_MASK (7UL << 16) ++#define RD_CUSTOM_EN BIT(6) ++#define WR_CUSTOM_EN BIT(7) ++#define WR_X4_EN BIT(20) ++#define SW_RST BIT(28) ++#define SNFI_MISC_CTL2 0x53c ++#define WR_LEN_SHIFT 16 ++#define SNFI_PG_CTL1 0x524 ++#define WR_LOAD_CMD_SHIFT 8 ++#define SNFI_PG_CTL2 0x528 ++#define WR_LOAD_ADDR_MASK 0xffff ++#define SNFI_MAC_CTL 0x500 ++#define MAC_WIP BIT(0) ++#define MAC_WIP_READY BIT(1) ++#define MAC_TRIG BIT(2) ++#define MAC_EN BIT(3) ++#define MAC_SIO_SEL BIT(4) ++#define SNFI_STA_CTL1 0x550 ++#define SPI_STATE_IDLE 0xf ++#define SNFI_CNFG 0x55c ++#define SNFI_MODE_EN BIT(0) ++#define SNFI_GPRAM_DATA 0x800 ++#define SNFI_GPRAM_MAX_LEN 16 ++ ++/* Dummy command trigger NFI to spi mode */ ++#define NAND_CMD_DUMMYREAD 0x00 ++#define NAND_CMD_DUMMYPROG 0x80 ++ ++#define MTK_TIMEOUT 500000 ++#define MTK_RESET_TIMEOUT 1000000 ++#define MTK_SNFC_MIN_SPARE 16 ++#define KB(x) ((x) * 1024UL) ++ ++/* ++ * supported spare size of each IP. ++ * order should be the same with the spare size bitfiled defination of ++ * register NFI_PAGEFMT. ++ */ ++static const u8 spare_size_mt7622[] = { ++ 16, 26, 27, 28 ++}; ++ ++struct mtk_snfi_caps { ++ const u8 *spare_size; ++ u8 num_spare_size; ++ u32 nand_sec_size; ++ u8 nand_fdm_size; ++ u8 nand_fdm_ecc_size; ++ u8 ecc_parity_bits; ++ u8 pageformat_spare_shift; ++ u8 bad_mark_swap; ++}; ++ ++struct mtk_snfi_bad_mark_ctl { ++ void (*bm_swap)(struct spi_mem *mem, u8 *buf, int raw); ++ u32 sec; ++ u32 pos; ++}; ++ ++struct mtk_snfi_nand_chip { ++ struct mtk_snfi_bad_mark_ctl bad_mark; ++ u32 spare_per_sector; ++}; ++ ++struct mtk_snfi_clk { ++ struct clk *nfi_clk; ++ struct clk *spi_clk; ++}; ++ ++struct mtk_snfi { ++ const struct mtk_snfi_caps *caps; ++ struct mtk_snfi_nand_chip snfi_nand; ++ struct mtk_snfi_clk clk; ++ struct mtk_ecc_config ecc_cfg; ++ struct mtk_ecc *ecc; ++ struct completion done; ++ struct device *dev; ++ ++ void __iomem *regs; ++ ++ u8 *buffer; ++}; ++ ++static inline u8 *oob_ptr(struct spi_mem *mem, int i) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u8 *poi; ++ ++ /* map the sector's FDM data to free oob: ++ * the beginning of the oob area stores the FDM data of bad mark ++ */ ++ ++ if (i < snfi_nand->bad_mark.sec) ++ poi = spinand->oobbuf + (i + 1) * snfi->caps->nand_fdm_size; ++ else if (i == snfi_nand->bad_mark.sec) ++ poi = spinand->oobbuf; ++ else ++ poi = spinand->oobbuf + i * snfi->caps->nand_fdm_size; ++ ++ return poi; ++} ++ ++static inline int mtk_data_len(struct spi_mem *mem) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ ++ return snfi->caps->nand_sec_size + snfi_nand->spare_per_sector; ++} ++ ++static inline u8 *mtk_oob_ptr(struct spi_mem *mem, ++ const u8 *p, int i) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ ++ return (u8 *)p + i * mtk_data_len(mem) + snfi->caps->nand_sec_size; ++} ++ ++static void mtk_snfi_bad_mark_swap(struct spi_mem *mem, ++ u8 *buf, int raw) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 bad_pos = snfi_nand->bad_mark.pos; ++ ++ if (raw) ++ bad_pos += snfi_nand->bad_mark.sec * mtk_data_len(mem); ++ else ++ bad_pos += snfi_nand->bad_mark.sec * snfi->caps->nand_sec_size; ++ ++ swap(spinand->oobbuf[0], buf[bad_pos]); ++} ++ ++static void mtk_snfi_set_bad_mark_ctl(struct mtk_snfi_bad_mark_ctl *bm_ctl, ++ struct spi_mem *mem) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ ++ bm_ctl->bm_swap = mtk_snfi_bad_mark_swap; ++ bm_ctl->sec = mtd->writesize / mtk_data_len(mem); ++ bm_ctl->pos = mtd->writesize % mtk_data_len(mem); ++} ++ ++static void mtk_snfi_mac_enable(struct mtk_snfi *snfi) ++{ ++ u32 mac; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac &= ~MAC_SIO_SEL; ++ mac |= MAC_EN; ++ ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++} ++ ++static int mtk_snfi_mac_trigger(struct mtk_snfi *snfi) ++{ ++ u32 mac, reg; ++ int ret = 0; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac |= MAC_TRIG; ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, ++ reg & MAC_WIP_READY, 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling wip ready for read timeout\n"); ++ return -EIO; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + SNFI_MAC_CTL, reg, ++ !(reg & MAC_WIP), 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling flash update timeout\n"); ++ return -EIO; ++ } ++ ++ return ret; ++} ++ ++static void mtk_snfi_mac_leave(struct mtk_snfi *snfi) ++{ ++ u32 mac; ++ ++ mac = readl(snfi->regs + SNFI_MAC_CTL); ++ mac &= ~(MAC_TRIG | MAC_EN | MAC_SIO_SEL); ++ writel(mac, snfi->regs + SNFI_MAC_CTL); ++} ++ ++static int mtk_snfi_mac_op(struct mtk_snfi *snfi) ++{ ++ int ret = 0; ++ ++ mtk_snfi_mac_enable(snfi); ++ ++ ret = mtk_snfi_mac_trigger(snfi); ++ if (ret) ++ return ret; ++ ++ mtk_snfi_mac_leave(snfi); ++ ++ return ret; ++} ++ ++static irqreturn_t mtk_snfi_irq(int irq, void *id) ++{ ++ struct mtk_snfi *snfi = id; ++ u16 sta, ien; ++ ++ sta = readw(snfi->regs + NFI_INTR_STA); ++ ien = readw(snfi->regs + NFI_INTR_EN); ++ ++ if (!(sta & ien)) ++ return IRQ_NONE; ++ ++ writew(~sta & ien, snfi->regs + NFI_INTR_EN); ++ complete(&snfi->done); ++ ++ return IRQ_HANDLED; ++} ++ ++static int mtk_snfi_enable_clk(struct device *dev, struct mtk_snfi_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->spi_clk); ++ if (ret) { ++ dev_err(dev, "failed to enable spi clk\n"); ++ clk_disable_unprepare(clk->nfi_clk); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void mtk_snfi_disable_clk(struct mtk_snfi_clk *clk) ++{ ++ clk_disable_unprepare(clk->nfi_clk); ++ clk_disable_unprepare(clk->spi_clk); ++} ++ ++static int mtk_snfi_reset(struct mtk_snfi *snfi) ++{ ++ u32 val; ++ int ret; ++ ++ /* SW reset controller */ ++ val = readl(snfi->regs + SNFI_MISC_CTL) | SW_RST; ++ writel(val, snfi->regs + SNFI_MISC_CTL); ++ ++ ret = readw_poll_timeout(snfi->regs + SNFI_STA_CTL1, val, ++ !(val & SPI_STATE_IDLE), 50, ++ MTK_RESET_TIMEOUT); ++ if (ret) { ++ dev_warn(snfi->dev, "spi state active in reset [0x%x] = 0x%x\n", ++ SNFI_STA_CTL1, val); ++ return ret; ++ } ++ ++ val = readl(snfi->regs + SNFI_MISC_CTL); ++ val &= ~SW_RST; ++ writel(val, snfi->regs + SNFI_MISC_CTL); ++ ++ /* reset all registers and force the NFI master to terminate */ ++ writew(CON_FIFO_FLUSH | CON_NFI_RST, snfi->regs + NFI_CON); ++ ret = readw_poll_timeout(snfi->regs + NFI_STA, val, ++ !(val & (NFI_FSM_MASK | NAND_FSM_MASK)), 50, ++ MTK_RESET_TIMEOUT); ++ if (ret) { ++ dev_warn(snfi->dev, "nfi active in reset [0x%x] = 0x%x\n", ++ NFI_STA, val); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mtk_snfi_set_spare_per_sector(struct spinand_device *spinand, ++ const struct mtk_snfi_caps *caps, ++ u32 *sps) ++{ ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ const u8 *spare = caps->spare_size; ++ u32 sectors, i, closest_spare = 0; ++ ++ sectors = mtd->writesize / caps->nand_sec_size; ++ *sps = mtd->oobsize / sectors; ++ ++ if (*sps < MTK_SNFC_MIN_SPARE) ++ return -EINVAL; ++ ++ for (i = 0; i < caps->num_spare_size; i++) { ++ if (*sps >= spare[i] && spare[i] >= spare[closest_spare]) { ++ closest_spare = i; ++ if (*sps == spare[i]) ++ break; ++ } ++ } ++ ++ *sps = spare[closest_spare]; ++ ++ return 0; ++} ++ ++static void mtk_snfi_read_fdm_data(struct spi_mem *mem, ++ u32 sectors) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ u32 vall, valm; ++ int i, j; ++ u8 *oobptr; ++ ++ for (i = 0; i < sectors; i++) { ++ oobptr = oob_ptr(mem, i); ++ vall = readl(snfi->regs + NFI_FDML(i)); ++ valm = readl(snfi->regs + NFI_FDMM(i)); ++ ++ for (j = 0; j < caps->nand_fdm_size; j++) ++ oobptr[j] = (j >= 4 ? valm : vall) >> ((j % 4) * 8); ++ } ++} ++ ++static void mtk_snfi_write_fdm_data(struct spi_mem *mem, ++ u32 sectors) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ u32 vall, valm; ++ int i, j; ++ u8 *oobptr; ++ ++ for (i = 0; i < sectors; i++) { ++ oobptr = oob_ptr(mem, i); ++ vall = 0; ++ valm = 0; ++ for (j = 0; j < 8; j++) { ++ if (j < 4) ++ vall |= (j < caps->nand_fdm_size ? oobptr[j] : ++ 0xff) << (j * 8); ++ else ++ valm |= (j < caps->nand_fdm_size ? oobptr[j] : ++ 0xff) << ((j - 4) * 8); ++ } ++ writel(vall, snfi->regs + NFI_FDML(i)); ++ writel(valm, snfi->regs + NFI_FDMM(i)); ++ } ++} ++ ++static int mtk_snfi_update_ecc_stats(struct spi_mem *mem, ++ u8 *buf, u32 sectors) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtk_ecc_stats stats; ++ int rc, i; ++ ++ rc = readl(snfi->regs + NFI_STA) & STA_EMP_PAGE; ++ if (rc) { ++ memset(buf, 0xff, sectors * snfi->caps->nand_sec_size); ++ for (i = 0; i < sectors; i++) ++ memset(spinand->oobbuf, 0xff, ++ snfi->caps->nand_fdm_size); ++ return 0; ++ } ++ ++ mtk_ecc_get_stats(snfi->ecc, &stats, sectors); ++ mtd->ecc_stats.corrected += stats.corrected; ++ mtd->ecc_stats.failed += stats.failed; ++ ++ return 0; ++} ++ ++static int mtk_snfi_hw_runtime_config(struct spi_mem *mem) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ const struct mtk_snfi_caps *caps = snfi->caps; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 fmt, spare, i = 0; ++ int ret; ++ ++ ret = mtk_snfi_set_spare_per_sector(spinand, caps, &spare); ++ if (ret) ++ return ret; ++ ++ /* calculate usable oob bytes for ecc parity data */ ++ snfi_nand->spare_per_sector = spare; ++ spare -= caps->nand_fdm_size; ++ ++ nand->memorg.oobsize = snfi_nand->spare_per_sector ++ * (mtd->writesize / caps->nand_sec_size); ++ mtd->oobsize = nanddev_per_page_oobsize(nand); ++ ++ snfi->ecc_cfg.strength = (spare << 3) / caps->ecc_parity_bits; ++ mtk_ecc_adjust_strength(snfi->ecc, &snfi->ecc_cfg.strength); ++ ++ switch (mtd->writesize) { ++ case 512: ++ fmt = PAGEFMT_512; ++ break; ++ case KB(2): ++ fmt = PAGEFMT_2K; ++ break; ++ case KB(4): ++ fmt = PAGEFMT_4K; ++ break; ++ default: ++ dev_err(snfi->dev, "invalid page len: %d\n", mtd->writesize); ++ return -EINVAL; ++ } ++ ++ /* Setup PageFormat */ ++ while (caps->spare_size[i] != snfi_nand->spare_per_sector) { ++ i++; ++ if (i == (caps->num_spare_size - 1)) { ++ dev_err(snfi->dev, "invalid spare size %d\n", ++ snfi_nand->spare_per_sector); ++ return -EINVAL; ++ } ++ } ++ ++ fmt |= i << caps->pageformat_spare_shift; ++ fmt |= caps->nand_fdm_size << PAGEFMT_FDM_SHIFT; ++ fmt |= caps->nand_fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT; ++ writel(fmt, snfi->regs + NFI_PAGEFMT); ++ ++ snfi->ecc_cfg.len = caps->nand_sec_size + caps->nand_fdm_ecc_size; ++ ++ mtk_snfi_set_bad_mark_ctl(&snfi_nand->bad_mark, mem); ++ ++ return 0; ++} ++ ++static int mtk_snfi_read_from_cache(struct spi_mem *mem, ++ const struct spi_mem_op *op, int oob_on) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 reg, len, col_addr = 0; ++ int dummy_cycle, ret; ++ dma_addr_t dma_addr; ++ ++ len = sectors * (snfi->caps->nand_sec_size ++ + snfi_nand->spare_per_sector); ++ ++ dma_addr = dma_map_single(snfi->dev, snfi->buffer, ++ len, DMA_FROM_DEVICE); ++ ret = dma_mapping_error(snfi->dev, dma_addr); ++ if (ret) { ++ dev_err(snfi->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* set Read cache command and dummy cycle */ ++ dummy_cycle = (op->dummy.nbytes << 3) >> (ffs(op->dummy.buswidth) - 1); ++ reg = ((op->cmd.opcode & RD_CMD_MASK) | ++ (dummy_cycle << RD_DUMMY_SHIFT)); ++ writel(reg, snfi->regs + SNFI_RD_CTL2); ++ ++ writel((col_addr & RD_ADDR_MASK), snfi->regs + SNFI_RD_CTL3); ++ ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg |= RD_CUSTOM_EN; ++ reg &= ~(RD_MODE_MASK | WR_X4_EN); ++ ++ /* set data and addr buswidth */ ++ if (op->data.buswidth == 4) ++ reg |= RD_MODE_X4; ++ else if (op->data.buswidth == 2) ++ reg |= RD_MODE_X2; ++ ++ if (op->addr.buswidth == 4 || op->addr.buswidth == 2) ++ reg |= RD_QDUAL_IO; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ writel(len, snfi->regs + SNFI_MISC_CTL2); ++ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); ++ reg = readw(snfi->regs + NFI_CNFG); ++ reg |= CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | CNFG_OP_CUST; ++ ++ if (!oob_on) { ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ writew(reg, snfi->regs + NFI_CNFG); ++ ++ snfi->ecc_cfg.mode = ECC_NFI_MODE; ++ snfi->ecc_cfg.sectors = sectors; ++ snfi->ecc_cfg.op = ECC_DECODE; ++ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); ++ if (ret) { ++ dev_err(snfi->dev, "ecc enable failed\n"); ++ /* clear NFI_CNFG */ ++ reg &= ~(CNFG_READ_EN | CNFG_DMA_BURST_EN | CNFG_DMA | ++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); ++ writew(reg, snfi->regs + NFI_CNFG); ++ goto out; ++ } ++ } else { ++ writew(reg, snfi->regs + NFI_CNFG); ++ } ++ ++ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); ++ ++ init_completion(&snfi->done); ++ ++ /* set dummy command to trigger NFI enter SPI mode */ ++ writew(NAND_CMD_DUMMYREAD, snfi->regs + NFI_CMD); ++ reg = readl(snfi->regs + NFI_CON) | CON_BRD; ++ writew(reg, snfi->regs + NFI_CON); ++ ++ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); ++ if (!ret) { ++ dev_err(snfi->dev, "read ahb done timeout\n"); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + NFI_BYTELEN, reg, ++ ADDRCNTR_SEC(reg) >= sectors, 10, ++ MTK_TIMEOUT); ++ if (ret < 0) { ++ dev_err(snfi->dev, "polling read byte len timeout\n"); ++ ret = -EIO; ++ } else { ++ if (!oob_on) { ++ ret = mtk_ecc_wait_done(snfi->ecc, ECC_DECODE); ++ if (ret) { ++ dev_warn(snfi->dev, "wait ecc done timeout\n"); ++ } else { ++ mtk_snfi_update_ecc_stats(mem, snfi->buffer, ++ sectors); ++ mtk_snfi_read_fdm_data(mem, sectors); ++ } ++ } ++ } ++ ++ if (oob_on) ++ goto out; ++ ++ mtk_ecc_disable(snfi->ecc); ++out: ++ dma_unmap_single(snfi->dev, dma_addr, len, DMA_FROM_DEVICE); ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg &= ~RD_CUSTOM_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ return ret; ++} ++ ++static int mtk_snfi_write_to_cache(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ int oob_on) ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ u32 sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 reg, len, col_addr = 0; ++ dma_addr_t dma_addr; ++ int ret; ++ ++ len = sectors * (snfi->caps->nand_sec_size ++ + snfi_nand->spare_per_sector); ++ ++ dma_addr = dma_map_single(snfi->dev, snfi->buffer, len, ++ DMA_TO_DEVICE); ++ ret = dma_mapping_error(snfi->dev, dma_addr); ++ if (ret) { ++ dev_err(snfi->dev, "dma mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* set program load cmd and address */ ++ reg = (op->cmd.opcode << WR_LOAD_CMD_SHIFT); ++ writel(reg, snfi->regs + SNFI_PG_CTL1); ++ writel(col_addr & WR_LOAD_ADDR_MASK, snfi->regs + SNFI_PG_CTL2); ++ ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg |= WR_CUSTOM_EN; ++ reg &= ~(RD_MODE_MASK | WR_X4_EN); ++ ++ if (op->data.buswidth == 4) ++ reg |= WR_X4_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ writel(len << WR_LEN_SHIFT, snfi->regs + SNFI_MISC_CTL2); ++ writew(sectors << CON_SEC_SHIFT, snfi->regs + NFI_CON); ++ ++ reg = readw(snfi->regs + NFI_CNFG); ++ reg &= ~(CNFG_READ_EN | CNFG_BYTE_RW); ++ reg |= CNFG_DMA | CNFG_DMA_BURST_EN | CNFG_OP_PROGRAM; ++ ++ if (!oob_on) { ++ reg |= CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN; ++ writew(reg, snfi->regs + NFI_CNFG); ++ ++ snfi->ecc_cfg.mode = ECC_NFI_MODE; ++ snfi->ecc_cfg.op = ECC_ENCODE; ++ ret = mtk_ecc_enable(snfi->ecc, &snfi->ecc_cfg); ++ if (ret) { ++ dev_err(snfi->dev, "ecc enable failed\n"); ++ /* clear NFI_CNFG */ ++ reg &= ~(CNFG_DMA_BURST_EN | CNFG_DMA | ++ CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); ++ writew(reg, snfi->regs + NFI_CNFG); ++ dma_unmap_single(snfi->dev, dma_addr, len, ++ DMA_FROM_DEVICE); ++ goto out; ++ } ++ /* write OOB into the FDM registers (OOB area in MTK NAND) */ ++ mtk_snfi_write_fdm_data(mem, sectors); ++ } else { ++ writew(reg, snfi->regs + NFI_CNFG); ++ } ++ writel(lower_32_bits(dma_addr), snfi->regs + NFI_STRADDR); ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(INTR_AHB_DONE_EN, snfi->regs + NFI_INTR_EN); ++ ++ init_completion(&snfi->done); ++ ++ /* set dummy command to trigger NFI enter SPI mode */ ++ writew(NAND_CMD_DUMMYPROG, snfi->regs + NFI_CMD); ++ reg = readl(snfi->regs + NFI_CON) | CON_BWR; ++ writew(reg, snfi->regs + NFI_CON); ++ ++ ret = wait_for_completion_timeout(&snfi->done, msecs_to_jiffies(500)); ++ if (!ret) { ++ dev_err(snfi->dev, "custom program done timeout\n"); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ret = -ETIMEDOUT; ++ goto ecc_disable; ++ } ++ ++ ret = readl_poll_timeout_atomic(snfi->regs + NFI_ADDRCNTR, reg, ++ ADDRCNTR_SEC(reg) >= sectors, ++ 10, MTK_TIMEOUT); ++ if (ret) ++ dev_err(snfi->dev, "hwecc write timeout\n"); ++ ++ecc_disable: ++ mtk_ecc_disable(snfi->ecc); ++ ++out: ++ dma_unmap_single(snfi->dev, dma_addr, len, DMA_TO_DEVICE); ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ reg = readl(snfi->regs + SNFI_MISC_CTL); ++ reg &= ~WR_CUSTOM_EN; ++ writel(reg, snfi->regs + SNFI_MISC_CTL); ++ ++ return ret; ++} ++ ++static int mtk_snfi_read(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 col_addr = op->addr.val; ++ int i, ret, sectors, oob_on = false; ++ ++ if (col_addr == mtd->writesize) ++ oob_on = true; ++ ++ ret = mtk_snfi_read_from_cache(mem, op, oob_on); ++ if (ret) { ++ dev_warn(snfi->dev, "read from cache fail\n"); ++ return ret; ++ } ++ ++ sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ for (i = 0; i < sectors; i++) { ++ if (oob_on) ++ memcpy(oob_ptr(mem, i), ++ mtk_oob_ptr(mem, snfi->buffer, i), ++ snfi->caps->nand_fdm_size); ++ ++ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) ++ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, ++ oob_on); ++ } ++ ++ if (!oob_on) ++ memcpy(spinand->databuf, snfi->buffer, mtd->writesize); ++ ++ return ret; ++} ++ ++static int mtk_snfi_write(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct mtk_snfi_nand_chip *snfi_nand = &snfi->snfi_nand; ++ u32 ret, i, sectors, col_addr = op->addr.val; ++ int oob_on = false; ++ ++ if (col_addr == mtd->writesize) ++ oob_on = true; ++ ++ sectors = mtd->writesize / snfi->caps->nand_sec_size; ++ memset(snfi->buffer, 0xff, mtd->writesize + mtd->oobsize); ++ ++ if (!oob_on) ++ memcpy(snfi->buffer, spinand->databuf, mtd->writesize); ++ ++ for (i = 0; i < sectors; i++) { ++ if (i == snfi_nand->bad_mark.sec && snfi->caps->bad_mark_swap) ++ snfi_nand->bad_mark.bm_swap(mem, snfi->buffer, oob_on); ++ ++ if (oob_on) ++ memcpy(mtk_oob_ptr(mem, snfi->buffer, i), ++ oob_ptr(mem, i), ++ snfi->caps->nand_fdm_size); ++ } ++ ++ ret = mtk_snfi_write_to_cache(mem, op, oob_on); ++ if (ret) ++ dev_warn(snfi->dev, "write to cache fail\n"); ++ ++ return ret; ++} ++ ++static int mtk_snfi_command_exec(struct mtk_snfi *snfi, ++ const u8 *txbuf, u8 *rxbuf, ++ const u32 txlen, const u32 rxlen) ++{ ++ u32 tmp, i, j, reg, m; ++ u8 *p_tmp = (u8 *)(&tmp); ++ int ret = 0; ++ ++ /* Moving tx data to NFI_SPI GPRAM */ ++ for (i = 0, m = 0; i < txlen; ) { ++ for (j = 0, tmp = 0; i < txlen && j < 4; i++, j++) ++ p_tmp[j] = txbuf[i]; ++ ++ writel(tmp, snfi->regs + SNFI_GPRAM_DATA + m); ++ m += 4; ++ } ++ ++ writel(txlen, snfi->regs + SNFI_MAC_OUTL); ++ writel(rxlen, snfi->regs + SNFI_MAC_INL); ++ ret = mtk_snfi_mac_op(snfi); ++ if (ret) ++ return ret; ++ ++ /* For NULL input data, this loop will be skipped */ ++ if (rxlen) ++ for (i = 0, m = 0; i < rxlen; ) { ++ reg = readl(snfi->regs + ++ SNFI_GPRAM_DATA + m); ++ for (j = 0; i < rxlen && j < 4; i++, j++, rxbuf++) { ++ if (m == 0 && i == 0) ++ j = i + txlen; ++ *rxbuf = (reg >> (j * 8)) & 0xFF; ++ } ++ m += 4; ++ } ++ ++ return ret; ++} ++ ++/* ++ * mtk_snfi_exec_op - to process command/data to send to the ++ * SPI NAND by mtk controller ++ */ ++static int mtk_snfi_exec_op(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++ ++{ ++ struct mtk_snfi *snfi = spi_controller_get_devdata(mem->spi->master); ++ struct spinand_device *spinand = spi_mem_get_drvdata(mem); ++ struct mtd_info *mtd = spinand_to_mtd(spinand); ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ const struct spi_mem_op *read_cache; ++ const struct spi_mem_op *write_cache; ++ const struct spi_mem_op *update_cache; ++ u32 tmpbufsize, txlen = 0, rxlen = 0; ++ u8 *txbuf, *rxbuf = NULL, *buf; ++ int i, ret = 0; ++ ++ ret = mtk_snfi_reset(snfi); ++ if (ret) { ++ dev_warn(snfi->dev, "reset spi memory controller fail\n"); ++ return ret; ++ } ++ ++ /*if bbt initial, framework have detect nand information */ ++ if (nand->bbt.cache) { ++ read_cache = spinand->op_templates.read_cache; ++ write_cache = spinand->op_templates.write_cache; ++ update_cache = spinand->op_templates.update_cache; ++ ++ ret = mtk_snfi_hw_runtime_config(mem); ++ if (ret) ++ return ret; ++ ++ /* For Read/Write with cache, Erase use framework flow */ ++ if (op->cmd.opcode == read_cache->cmd.opcode) { ++ ret = mtk_snfi_read(mem, op); ++ if (ret) ++ dev_warn(snfi->dev, "snfi read fail\n"); ++ ++ return ret; ++ } else if ((op->cmd.opcode == write_cache->cmd.opcode) ++ || (op->cmd.opcode == update_cache->cmd.opcode)) { ++ ret = mtk_snfi_write(mem, op); ++ if (ret) ++ dev_warn(snfi->dev, "snfi write fail\n"); ++ ++ return ret; ++ } ++ } ++ ++ tmpbufsize = sizeof(op->cmd.opcode) + op->addr.nbytes + ++ op->dummy.nbytes + op->data.nbytes; ++ ++ txbuf = kzalloc(tmpbufsize, GFP_KERNEL); ++ if (!txbuf) ++ return -ENOMEM; ++ ++ txbuf[txlen++] = op->cmd.opcode; ++ ++ if (op->addr.nbytes) ++ for (i = 0; i < op->addr.nbytes; i++) ++ txbuf[txlen++] = op->addr.val >> ++ (8 * (op->addr.nbytes - i - 1)); ++ ++ txlen += op->dummy.nbytes; ++ ++ if (op->data.dir == SPI_MEM_DATA_OUT) ++ for (i = 0; i < op->data.nbytes; i++) { ++ buf = (u8 *)op->data.buf.out; ++ txbuf[txlen++] = buf[i]; ++ } ++ ++ if (op->data.dir == SPI_MEM_DATA_IN) { ++ rxbuf = (u8 *)op->data.buf.in; ++ rxlen += op->data.nbytes; ++ } ++ ++ ret = mtk_snfi_command_exec(snfi, txbuf, rxbuf, txlen, rxlen); ++ kfree(txbuf); ++ ++ return ret; ++} ++ ++static int mtk_snfi_init(struct mtk_snfi *snfi) ++{ ++ int ret; ++ ++ /* Reset the state machine and data FIFO */ ++ ret = mtk_snfi_reset(snfi); ++ if (ret) { ++ dev_warn(snfi->dev, "MTK reset controller fail\n"); ++ return ret; ++ } ++ ++ snfi->buffer = devm_kzalloc(snfi->dev, 4096 + 256, GFP_KERNEL); ++ if (!snfi->buffer) ++ return -ENOMEM; ++ ++ /* Clear interrupt, read clear. */ ++ readw(snfi->regs + NFI_INTR_STA); ++ writew(0, snfi->regs + NFI_INTR_EN); ++ ++ writel(0, snfi->regs + NFI_CON); ++ writel(0, snfi->regs + NFI_CNFG); ++ ++ /* Change to NFI_SPI mode. */ ++ writel(SNFI_MODE_EN, snfi->regs + SNFI_CNFG); ++ ++ return 0; ++} ++ ++static int mtk_snfi_check_buswidth(u8 width) ++{ ++ switch (width) { ++ case 1: ++ case 2: ++ case 4: ++ return 0; ++ ++ default: ++ break; ++ } ++ ++ return -ENOTSUPP; ++} ++ ++static bool mtk_snfi_supports_op(struct spi_mem *mem, ++ const struct spi_mem_op *op) ++{ ++ int ret = 0; ++ ++ /* For MTK Spi Nand controller, cmd buswidth just support 1 bit*/ ++ if (op->cmd.buswidth != 1) ++ ret = -ENOTSUPP; ++ ++ if (op->addr.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->addr.buswidth); ++ ++ if (op->dummy.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->dummy.buswidth); ++ ++ if (op->data.nbytes) ++ ret |= mtk_snfi_check_buswidth(op->data.buswidth); ++ ++ if (ret) ++ return false; ++ ++ return true; ++} ++ ++static const struct spi_controller_mem_ops mtk_snfi_ops = { ++ .supports_op = mtk_snfi_supports_op, ++ .exec_op = mtk_snfi_exec_op, ++}; ++ ++static const struct mtk_snfi_caps snfi_mt7622 = { ++ .spare_size = spare_size_mt7622, ++ .num_spare_size = 4, ++ .nand_sec_size = 512, ++ .nand_fdm_size = 8, ++ .nand_fdm_ecc_size = 1, ++ .ecc_parity_bits = 13, ++ .pageformat_spare_shift = 4, ++ .bad_mark_swap = 0, ++}; ++ ++static const struct mtk_snfi_caps snfi_mt7629 = { ++ .spare_size = spare_size_mt7622, ++ .num_spare_size = 4, ++ .nand_sec_size = 512, ++ .nand_fdm_size = 8, ++ .nand_fdm_ecc_size = 1, ++ .ecc_parity_bits = 13, ++ .pageformat_spare_shift = 4, ++ .bad_mark_swap = 1, ++}; ++ ++static const struct of_device_id mtk_snfi_id_table[] = { ++ { .compatible = "mediatek,mt7622-snfi", .data = &snfi_mt7622, }, ++ { .compatible = "mediatek,mt7629-snfi", .data = &snfi_mt7629, }, ++ { /* sentinel */ } ++}; ++ ++static int mtk_snfi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct spi_controller *ctlr; ++ struct mtk_snfi *snfi; ++ struct resource *res; ++ int ret = 0, irq; ++ ++ ctlr = spi_alloc_master(&pdev->dev, sizeof(*snfi)); ++ if (!ctlr) ++ return -ENOMEM; ++ ++ snfi = spi_controller_get_devdata(ctlr); ++ snfi->caps = of_device_get_match_data(dev); ++ snfi->dev = dev; ++ ++ snfi->ecc = of_mtk_ecc_get(np); ++ if (IS_ERR_OR_NULL(snfi->ecc)) ++ goto err_put_master; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ snfi->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(snfi->regs)) { ++ ret = PTR_ERR(snfi->regs); ++ goto release_ecc; ++ } ++ ++ /* find the clocks */ ++ snfi->clk.nfi_clk = devm_clk_get(dev, "nfi_clk"); ++ if (IS_ERR(snfi->clk.nfi_clk)) { ++ dev_err(dev, "no nfi clk\n"); ++ ret = PTR_ERR(snfi->clk.nfi_clk); ++ goto release_ecc; ++ } ++ ++ snfi->clk.spi_clk = devm_clk_get(dev, "spi_clk"); ++ if (IS_ERR(snfi->clk.spi_clk)) { ++ dev_err(dev, "no spi clk\n"); ++ ret = PTR_ERR(snfi->clk.spi_clk); ++ goto release_ecc; ++ } ++ ++ ret = mtk_snfi_enable_clk(dev, &snfi->clk); ++ if (ret) ++ goto release_ecc; ++ ++ /* find the irq */ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "no snfi irq resource\n"); ++ ret = -EINVAL; ++ goto clk_disable; ++ } ++ ++ ret = devm_request_irq(dev, irq, mtk_snfi_irq, 0, "mtk-snfi", snfi); ++ if (ret) { ++ dev_err(dev, "failed to request snfi 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; ++ } ++ ++ ctlr->dev.of_node = np; ++ ctlr->mem_ops = &mtk_snfi_ops; ++ ++ platform_set_drvdata(pdev, snfi); ++ ret = mtk_snfi_init(snfi); ++ if (ret) { ++ dev_err(dev, "failed to init snfi\n"); ++ goto clk_disable; ++ } ++ ++ ret = devm_spi_register_master(dev, ctlr); ++ if (ret) ++ goto clk_disable; ++ ++ return 0; ++ ++clk_disable: ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++release_ecc: ++ mtk_ecc_release(snfi->ecc); ++ ++err_put_master: ++ spi_master_put(ctlr); ++ ++ dev_err(dev, "MediaTek SPI NAND interface probe failed %d\n", ret); ++ return ret; ++} ++ ++static int mtk_snfi_remove(struct platform_device *pdev) ++{ ++ struct mtk_snfi *snfi = platform_get_drvdata(pdev); ++ ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++ return 0; ++} ++ ++static int mtk_snfi_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct mtk_snfi *snfi = platform_get_drvdata(pdev); ++ ++ mtk_snfi_disable_clk(&snfi->clk); ++ ++ return 0; ++} ++ ++static int mtk_snfi_resume(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_snfi *snfi = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = mtk_snfi_enable_clk(dev, &snfi->clk); ++ if (ret) ++ return ret; ++ ++ ret = mtk_snfi_init(snfi); ++ if (ret) ++ dev_err(dev, "failed to init snfi controller\n"); ++ ++ return ret; ++} ++ ++static struct platform_driver mtk_snfi_driver = { ++ .driver = { ++ .name = "mtk-snfi", ++ .of_match_table = mtk_snfi_id_table, ++ }, ++ .probe = mtk_snfi_probe, ++ .remove = mtk_snfi_remove, ++ .suspend = mtk_snfi_suspend, ++ .resume = mtk_snfi_resume, ++}; ++ ++module_platform_driver(mtk_snfi_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Xiangsheng Hou "); ++MODULE_DESCRIPTION("Mediatek SPI Memory Interface Driver"); diff --git a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch new file mode 100644 index 0000000000..5c20952611 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch @@ -0,0 +1,840 @@ +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -15,6 +15,10 @@ config MTD_NAND_ECC + bool + depends on MTD_NAND_CORE + ++config MTD_NAND_MTK_BMT ++ bool "Support MediaTek NAND Bad-block Management Table" ++ default n ++ + endmenu + + endmenu +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -2,6 +2,7 @@ + + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o ++obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o + + obj-y += onenand/ + obj-y += raw/ +--- /dev/null ++++ b/drivers/mtd/nand/mtk_bmt.c +@@ -0,0 +1,766 @@ ++/* ++ * Copyright (c) 2017 MediaTek Inc. ++ * Author: Xiangsheng Hou ++ * Copyright (c) 2020 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAIN_SIGNATURE_OFFSET 0 ++#define OOB_SIGNATURE_OFFSET 1 ++#define BBPOOL_RATIO 2 ++ ++#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) ++ ++/* Maximum 8k blocks */ ++#define BB_TABLE_MAX 0x2000U ++#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) ++#define BMT_TBL_DEF_VAL 0x0 ++ ++/* ++ * Burner Bad Block Table ++ * --------- Only support SLC Nand Chips!!!!!!!!!!! ---------- ++ */ ++ ++struct bbbt { ++ char signature[3]; ++ /* This version is used to distinguish the legacy and new algorithm */ ++#define BBMT_VERSION 2 ++ unsigned char version; ++ /* Below 2 tables will be written in SLC */ ++ u16 bb_tbl[BB_TABLE_MAX]; ++ struct bbmt { ++ u16 block; ++#define NO_MAPPED 0 ++#define NORMAL_MAPPED 1 ++#define BMT_MAPPED 2 ++ u16 mapped; ++ } bmt_tbl[BMT_TABLE_MAX]; ++}; ++ ++static struct bmt_desc { ++ struct mtd_info *mtd; ++ ++ int (*_read_oob) (struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops); ++ int (*_write_oob) (struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops); ++ const struct nand_ops *nand_ops; ++ ++ struct bbbt *bbt; ++ ++ struct dentry *debugfs_dir; ++ ++ u32 pg_size; ++ u32 blk_size; ++ u16 pg_shift; ++ u16 blk_shift; ++ /* bbt logical address */ ++ u16 pool_lba; ++ /* bbt physical address */ ++ u16 pool_pba; ++ /* Maximum count of bad blocks that the vendor guaranteed */ ++ u16 bb_max; ++ /* Total blocks of the Nand Chip */ ++ u16 total_blks; ++ /* The block(n) BMT is located at (bmt_tbl[n]) */ ++ u16 bmt_blk_idx; ++ /* How many pages needs to store 'struct bbbt' */ ++ u32 bmt_pgs; ++ ++ /* to compensate for driver level remapping */ ++ u8 oob_offset; ++} bmtd = {0}; ++ ++static unsigned char *nand_bbt_buf; ++static unsigned char *nand_data_buf; ++ ++/* -------- Unit conversions -------- */ ++static inline u32 blk_pg(u16 block) ++{ ++ return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift)); ++} ++ ++/* -------- Nand operations wrapper -------- */ ++static inline int ++bbt_nand_read(u32 page, unsigned char *dat, int dat_len, ++ unsigned char *fdm, int fdm_len) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .ooboffs = bmtd.oob_offset, ++ .oobbuf = fdm, ++ .ooblen = fdm_len, ++ .datbuf = dat, ++ .len = dat_len, ++ }; ++ ++ return bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); ++} ++ ++static inline int bbt_nand_erase(u16 block) ++{ ++ struct nand_device *nand = mtd_to_nanddev(bmtd.mtd); ++ loff_t addr = (loff_t)block << bmtd.blk_shift; ++ struct nand_pos pos; ++ ++ nanddev_offs_to_pos(nand, addr, &pos); ++ return bmtd.nand_ops->erase(nand, &pos); ++} ++ ++/* -------- Bad Blocks Management -------- */ ++static int ++read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len) ++{ ++ u32 len = bmtd.bmt_pgs << bmtd.pg_shift; ++ ++ return bbt_nand_read(blk_pg(block), dat, len, fdm, fdm_len); ++} ++ ++static int write_bmt(u16 block, unsigned char *dat) ++{ ++ struct mtd_oob_ops ops = { ++ .mode = MTD_OPS_PLACE_OOB, ++ .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, ++ .oobbuf = "bmt", ++ .ooblen = 3, ++ .datbuf = dat, ++ .len = bmtd.bmt_pgs << bmtd.pg_shift, ++ }; ++ loff_t addr = (loff_t)block << bmtd.blk_shift; ++ ++ return bmtd._write_oob(bmtd.mtd, addr, &ops); ++} ++ ++static u16 find_valid_block(u16 block) ++{ ++ u8 fdm[4]; ++ int ret; ++ int loop = 0; ++ ++retry: ++ if (block >= bmtd.total_blks) ++ return 0; ++ ++ ret = bbt_nand_read(blk_pg(block), nand_data_buf, bmtd.pg_size, ++ fdm, sizeof(fdm)); ++ /* Read the 1st byte of FDM to judge whether it's a bad ++ * or not ++ */ ++ if (ret || fdm[0] != 0xff) { ++ pr_info("nand: found bad block 0x%x\n", block); ++ if (loop >= bmtd.bb_max) { ++ pr_info("nand: FATAL ERR: too many bad blocks!!\n"); ++ return 0; ++ } ++ ++ loop++; ++ block++; ++ goto retry; ++ } ++ ++ return block; ++} ++ ++/* Find out all bad blocks, and fill in the mapping table */ ++static int scan_bad_blocks(struct bbbt *bbt) ++{ ++ int i; ++ u16 block = 0; ++ ++ /* First time download, the block0 MUST NOT be a bad block, ++ * this is guaranteed by vendor ++ */ ++ bbt->bb_tbl[0] = 0; ++ ++ /* ++ * Construct the mapping table of Normal data area(non-PMT/BMTPOOL) ++ * G - Good block; B - Bad block ++ * --------------------------- ++ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| ++ * --------------------------- ++ * What bb_tbl[i] looks like: ++ * physical block(i): ++ * 0 1 2 3 4 5 6 7 8 9 a b c ++ * mapped block(bb_tbl[i]): ++ * 0 1 3 6 7 8 9 b ...... ++ * ATTENTION: ++ * If new bad block ocurred(n), search bmt_tbl to find ++ * a available block(x), and fill in the bb_tbl[n] = x; ++ */ ++ for (i = 1; i < bmtd.pool_lba; i++) { ++ bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1); ++ BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]); ++ if (bbt->bb_tbl[i] == 0) ++ return -1; ++ } ++ ++ /* Physical Block start Address of BMT pool */ ++ bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1; ++ if (bmtd.pool_pba >= bmtd.total_blks - 2) { ++ pr_info("nand: FATAL ERR: Too many bad blocks!!\n"); ++ return -1; ++ } ++ ++ BBT_LOG("pool_pba=0x%x", bmtd.pool_pba); ++ i = 0; ++ block = bmtd.pool_pba; ++ /* ++ * The bmt table is used for runtime bad block mapping ++ * G - Good block; B - Bad block ++ * --------------------------- ++ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| ++ * --------------------------- ++ * block: 0 1 2 3 4 5 6 7 8 9 a b c ++ * What bmt_tbl[i] looks like in initial state: ++ * i: ++ * 0 1 2 3 4 5 6 7 ++ * bmt_tbl[i].block: ++ * 0 1 3 6 7 8 9 b ++ * bmt_tbl[i].mapped: ++ * N N N N N N N B ++ * N - Not mapped(Available) ++ * M - Mapped ++ * B - BMT ++ * ATTENTION: ++ * BMT always in the last valid block in pool ++ */ ++ while ((block = find_valid_block(block)) != 0) { ++ bbt->bmt_tbl[i].block = block; ++ bbt->bmt_tbl[i].mapped = NO_MAPPED; ++ BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block); ++ block++; ++ i++; ++ } ++ ++ /* i - How many available blocks in pool, which is the length of bmt_tbl[] ++ * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block ++ */ ++ bmtd.bmt_blk_idx = i - 1; ++ bbt->bmt_tbl[bmtd.bmt_blk_idx].mapped = BMT_MAPPED; ++ ++ if (i < 1) { ++ pr_info("nand: FATAL ERR: no space to store BMT!!\n"); ++ return -1; ++ } ++ ++ pr_info("[BBT] %d available blocks in BMT pool\n", i); ++ ++ return 0; ++} ++ ++static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm) ++{ ++ struct bbbt *bbt = (struct bbbt *)buf; ++ u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET; ++ ++ ++ if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 && ++ memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) { ++ if (bbt->version == BBMT_VERSION) ++ return true; ++ } ++ BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x", ++ sig[0], sig[1], sig[2], ++ fdm[1], fdm[2], fdm[3]); ++ return false; ++} ++ ++static u16 get_bmt_index(struct bbmt *bmt) ++{ ++ int i = 0; ++ ++ while (bmt[i].block != BMT_TBL_DEF_VAL) { ++ if (bmt[i].mapped == BMT_MAPPED) ++ return i; ++ i++; ++ } ++ return 0; ++} ++ ++static struct bbbt *scan_bmt(u16 block) ++{ ++ u8 fdm[4]; ++ ++ if (block < bmtd.pool_lba) ++ return NULL; ++ ++ if (read_bmt(block, nand_bbt_buf, fdm, sizeof(fdm))) ++ return scan_bmt(block - 1); ++ ++ if (is_valid_bmt(nand_bbt_buf, fdm)) { ++ bmtd.bmt_blk_idx = get_bmt_index(((struct bbbt *)nand_bbt_buf)->bmt_tbl); ++ if (bmtd.bmt_blk_idx == 0) { ++ pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); ++ return NULL; ++ } ++ pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); ++ return (struct bbbt *)nand_bbt_buf; ++ } else ++ return scan_bmt(block - 1); ++} ++ ++/* Write the Burner Bad Block Table to Nand Flash ++ * n - write BMT to bmt_tbl[n] ++ */ ++static u16 upload_bmt(struct bbbt *bbt, int n) ++{ ++ u16 block; ++ ++retry: ++ if (n < 0 || bbt->bmt_tbl[n].mapped == NORMAL_MAPPED) { ++ pr_info("nand: FATAL ERR: no space to store BMT!\n"); ++ return (u16)-1; ++ } ++ ++ block = bbt->bmt_tbl[n].block; ++ BBT_LOG("n = 0x%x, block = 0x%x", n, block); ++ if (bbt_nand_erase(block)) { ++ bbt->bmt_tbl[n].block = 0; ++ /* erase failed, try the previous block: bmt_tbl[n - 1].block */ ++ n--; ++ goto retry; ++ } ++ ++ /* The signature offset is fixed set to 0, ++ * oob signature offset is fixed set to 1 ++ */ ++ memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3); ++ bbt->version = BBMT_VERSION; ++ ++ if (write_bmt(block, (unsigned char *)bbt)) { ++ bbt->bmt_tbl[n].block = 0; ++ ++ /* write failed, try the previous block in bmt_tbl[n - 1] */ ++ n--; ++ goto retry; ++ } ++ ++ /* Return the current index(n) of BMT pool (bmt_tbl[n]) */ ++ return n; ++} ++ ++static u16 find_valid_block_in_pool(struct bbbt *bbt) ++{ ++ int i; ++ ++ if (bmtd.bmt_blk_idx == 0) ++ goto error; ++ ++ for (i = 0; i < bmtd.bmt_blk_idx; i++) { ++ if (bbt->bmt_tbl[i].block != 0 && bbt->bmt_tbl[i].mapped == NO_MAPPED) { ++ bbt->bmt_tbl[i].mapped = NORMAL_MAPPED; ++ return bbt->bmt_tbl[i].block; ++ } ++ } ++ ++error: ++ pr_info("nand: FATAL ERR: BMT pool is run out!\n"); ++ return 0; ++} ++ ++/* We met a bad block, mark it as bad and map it to a valid block in pool, ++ * if it's a write failure, we need to write the data to mapped block ++ */ ++static bool update_bmt(u16 block) ++{ ++ u16 mapped_blk; ++ struct bbbt *bbt; ++ ++ bbt = bmtd.bbt; ++ mapped_blk = find_valid_block_in_pool(bbt); ++ if (mapped_blk == 0) ++ return false; ++ ++ /* Map new bad block to available block in pool */ ++ bbt->bb_tbl[block] = mapped_blk; ++ bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); ++ ++ return true; ++} ++ ++u16 get_mapping_block_index(int block) ++{ ++ int mapping_block; ++ ++ if (block < bmtd.pool_lba) ++ mapping_block = bmtd.bbt->bb_tbl[block]; ++ else ++ mapping_block = block; ++ BBT_LOG("0x%x mapped to 0x%x", block, mapping_block); ++ ++ return mapping_block; ++} ++ ++static int ++mtk_bmt_read(struct mtd_info *mtd, loff_t from, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_oob_ops cur_ops = *ops; ++ int retry_count = 0; ++ loff_t cur_from; ++ int ret; ++ ++ ops->retlen = 0; ++ ops->oobretlen = 0; ++ ++ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { ++ u32 offset = from & (bmtd.blk_size - 1); ++ u32 block = from >> bmtd.blk_shift; ++ u32 cur_block; ++ ++ cur_block = get_mapping_block_index(block); ++ cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; ++ ++ cur_ops.oobretlen = 0; ++ cur_ops.retlen = 0; ++ cur_ops.len = min_t(u32, mtd->erasesize - offset, ++ ops->len - ops->retlen); ++ ret = bmtd._read_oob(mtd, cur_from, &cur_ops); ++ if (ret < 0) { ++ update_bmt(block); ++ if (retry_count++ < 10) ++ continue; ++ ++ return ret; ++ } ++ ++ ops->retlen += cur_ops.retlen; ++ ops->oobretlen += cur_ops.oobretlen; ++ ++ cur_ops.datbuf += cur_ops.retlen; ++ cur_ops.oobbuf += cur_ops.oobretlen; ++ cur_ops.ooblen -= cur_ops.oobretlen; ++ ++ if (!cur_ops.len) ++ cur_ops.len = mtd->erasesize - offset; ++ ++ from += cur_ops.len; ++ retry_count = 0; ++ } ++ ++ return 0; ++} ++ ++static int ++mtk_bmt_write(struct mtd_info *mtd, loff_t to, ++ struct mtd_oob_ops *ops) ++{ ++ struct mtd_oob_ops cur_ops = *ops; ++ int retry_count = 0; ++ loff_t cur_to; ++ int ret; ++ ++ ops->retlen = 0; ++ ops->oobretlen = 0; ++ ++ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { ++ u32 offset = to & (bmtd.blk_size - 1); ++ u32 block = to >> bmtd.blk_shift; ++ u32 cur_block; ++ ++ cur_block = get_mapping_block_index(block); ++ cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; ++ ++ cur_ops.oobretlen = 0; ++ cur_ops.retlen = 0; ++ cur_ops.len = min_t(u32, bmtd.blk_size - offset, ++ ops->len - ops->retlen); ++ ret = bmtd._write_oob(mtd, cur_to, &cur_ops); ++ if (ret < 0) { ++ update_bmt(block); ++ if (retry_count++ < 10) ++ continue; ++ ++ return ret; ++ } ++ ++ ops->retlen += cur_ops.retlen; ++ ops->oobretlen += cur_ops.oobretlen; ++ ++ cur_ops.datbuf += cur_ops.retlen; ++ cur_ops.oobbuf += cur_ops.oobretlen; ++ cur_ops.ooblen -= cur_ops.oobretlen; ++ ++ if (!cur_ops.len) ++ cur_ops.len = mtd->erasesize - offset; ++ ++ to += cur_ops.len; ++ retry_count = 0; ++ } ++ ++ return 0; ++} ++ ++ ++ ++static int ++mtk_bmt_erase(struct nand_device *nand, const struct nand_pos *pos) ++{ ++ struct nand_pos new_pos = *pos; ++ int retry_count = 0; ++ int ret; ++ ++retry: ++ new_pos.eraseblock = get_mapping_block_index(pos->eraseblock); ++ ++ ret = bmtd.nand_ops->erase(nand, &new_pos); ++ if (ret) { ++ update_bmt(pos->eraseblock); ++ if (retry_count++ < 10) ++ goto retry; ++ } ++ ++ return ret; ++} ++ ++static bool ++mtk_bmt_isbad(struct nand_device *nand, const struct nand_pos *pos) ++{ ++ struct nand_pos new_pos = *pos; ++ int retry_count = 0; ++ bool ret; ++ ++retry: ++ new_pos.eraseblock = get_mapping_block_index(pos->eraseblock); ++ ++ ret = bmtd.nand_ops->isbad(nand, &new_pos); ++ if (ret) { ++ update_bmt(pos->eraseblock); ++ if (retry_count++ < 10) ++ goto retry; ++ } ++ ++ return ret; ++} ++ ++static int ++mtk_bmt_markbad(struct nand_device *nand, const struct nand_pos *pos) ++{ ++ struct nand_pos new_pos = *pos; ++ ++ new_pos.eraseblock = get_mapping_block_index(new_pos.eraseblock); ++ update_bmt(pos->eraseblock); ++ ++ return bmtd.nand_ops->markbad(nand, &new_pos); ++} ++ ++static void ++mtk_bmt_replace_ops(struct mtd_info *mtd) ++{ ++ static const struct nand_ops mtk_bmt_nand_ops = { ++ .erase = mtk_bmt_erase, ++ .isbad = mtk_bmt_isbad, ++ .markbad = mtk_bmt_markbad, ++ }; ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ ++ bmtd.nand_ops = nand->ops; ++ bmtd._read_oob = mtd->_read_oob; ++ bmtd._write_oob = mtd->_write_oob; ++ ++ mtd->_read_oob = mtk_bmt_read; ++ mtd->_write_oob = mtk_bmt_write; ++ nand->ops = &mtk_bmt_nand_ops; ++} ++ ++static int mtk_bmt_debug_mark_good(void *data, u64 val) ++{ ++ u32 block = val >> bmtd.blk_shift; ++ ++ bmtd.bbt->bb_tbl[block] = block; ++ bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); ++ ++ return 0; ++} ++ ++static int mtk_bmt_debug_mark_bad(void *data, u64 val) ++{ ++ u32 block = val >> bmtd.blk_shift; ++ ++ update_bmt(block); ++ ++ return 0; ++} ++ ++DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); ++DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); ++ ++static void ++mtk_bmt_add_debugfs(void) ++{ ++ struct dentry *dir; ++ ++ dir = bmtd.debugfs_dir = debugfs_create_dir("mtk-bmt", NULL); ++ if (!dir) ++ return; ++ ++ debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); ++ debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); ++} ++ ++void mtk_bmt_detach(struct mtd_info *mtd) ++{ ++ struct nand_device *nand = mtd_to_nanddev(mtd); ++ ++ if (bmtd.mtd != mtd) ++ return; ++ ++ if (bmtd.debugfs_dir) ++ debugfs_remove_recursive(bmtd.debugfs_dir); ++ bmtd.debugfs_dir = NULL; ++ ++ kfree(nand_bbt_buf); ++ kfree(nand_data_buf); ++ ++ mtd->_read_oob = bmtd._read_oob; ++ mtd->_write_oob = bmtd._write_oob; ++ mtd->size = bmtd.total_blks << bmtd.blk_shift; ++ nand->ops = bmtd.nand_ops; ++ ++ memset(&bmtd, 0, sizeof(bmtd)); ++} ++ ++/* total_blocks - The total count of blocks that the Nand Chip has */ ++int mtk_bmt_attach(struct mtd_info *mtd) ++{ ++ struct device_node *np; ++ struct bbbt *bbt; ++ u32 bufsz; ++ u32 block; ++ u16 total_blocks, pmt_block; ++ int ret = 0; ++ u32 bmt_pool_size; ++ ++ if (bmtd.mtd) ++ return -ENOSPC; ++ ++ np = mtd_get_of_node(mtd); ++ if (!np) ++ return 0; ++ ++ if (!of_property_read_bool(np, "mediatek,bmt-v2")) ++ return 0; ++ ++ if (of_property_read_u32(np, "mediatek,bmt-pool-size", ++ &bmt_pool_size) != 0) ++ bmt_pool_size = 80; ++ ++ if (of_property_read_u8(np, "mediatek,bmt-oob-offset", ++ &bmtd.oob_offset) != 0) ++ bmtd.oob_offset = 8; ++ ++ bmtd.mtd = mtd; ++ mtk_bmt_replace_ops(mtd); ++ ++ bmtd.blk_size = mtd->erasesize; ++ bmtd.blk_shift = ffs(bmtd.blk_size) - 1; ++ bmtd.pg_size = mtd->writesize; ++ bmtd.pg_shift = ffs(bmtd.pg_size) - 1; ++ total_blocks = mtd->size >> bmtd.blk_shift; ++ pmt_block = total_blocks - bmt_pool_size - 2; ++ ++ mtd->size = pmt_block << bmtd.blk_shift; ++ ++ /* ++ * --------------------------------------- ++ * | PMT(2blks) | BMT POOL(totalblks * 2%) | ++ * --------------------------------------- ++ * ^ ^ ++ * | | ++ * pmt_block pmt_block + 2blocks(pool_lba) ++ * ++ * ATTETION!!!!!! ++ * The blocks ahead of the boundary block are stored in bb_tbl ++ * and blocks behind are stored in bmt_tbl ++ */ ++ ++ bmtd.pool_lba = (u16)(pmt_block + 2); ++ bmtd.total_blks = total_blocks; ++ bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; ++ ++ /* 3 buffers we need */ ++ bufsz = round_up(sizeof(struct bbbt), bmtd.pg_size); ++ bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; ++ ++ nand_bbt_buf = kzalloc(bufsz, GFP_KERNEL); ++ nand_data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL); ++ ++ if (!nand_bbt_buf || !nand_data_buf) { ++ pr_info("nand: FATAL ERR: allocate buffer failed!\n"); ++ ret = -1; ++ goto error; ++ } ++ ++ memset(nand_bbt_buf, 0xff, bufsz); ++ memset(nand_data_buf, 0xff, bmtd.pg_size); ++ ++ BBT_LOG("bbtbuf=0x%p(0x%x) dat=0x%p(0x%x)", ++ nand_bbt_buf, bufsz, nand_data_buf, bmtd.pg_size); ++ BBT_LOG("pool_lba=0x%x total_blks=0x%x bb_max=0x%x", ++ bmtd.pool_lba, bmtd.total_blks, bmtd.bb_max); ++ ++ /* Scanning start from the first page of the last block ++ * of whole flash ++ */ ++ bbt = scan_bmt(bmtd.total_blks - 1); ++ if (!bbt) { ++ /* BMT not found */ ++ if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { ++ pr_info("nand: FATAL: Too many blocks, can not support!\n"); ++ ret = -1; ++ goto error; ++ } ++ ++ bbt = (struct bbbt *)nand_bbt_buf; ++ memset(bbt->bmt_tbl, BMT_TBL_DEF_VAL, sizeof(bbt->bmt_tbl)); ++ ++ if (scan_bad_blocks(bbt)) { ++ ret = -1; ++ goto error; ++ } ++ ++ /* BMT always in the last valid block in pool */ ++ bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); ++ block = bbt->bmt_tbl[bmtd.bmt_blk_idx].block; ++ pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); ++ ++ if (bmtd.bmt_blk_idx == 0) ++ pr_info("nand: Warning: no available block in BMT pool!\n"); ++ else if (bmtd.bmt_blk_idx == (u16)-1) { ++ ret = -1; ++ goto error; ++ } ++ } ++ mtk_bmt_add_debugfs(); ++ ++ bmtd.bbt = bbt; ++ return 0; ++ ++error: ++ mtk_bmt_detach(mtd); ++ return ret; ++} ++ ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); ++MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); ++ +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) + { +@@ -1139,6 +1140,8 @@ static int spinand_probe(struct spi_mem + if (ret) + return ret; + ++ mtk_bmt_attach(mtd); ++ + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + goto err_spinand_cleanup; +@@ -1164,6 +1167,7 @@ static int spinand_remove(struct spi_mem + if (ret) + return ret; + ++ mtk_bmt_detach(mtd); + spinand_cleanup(spinand); + + return 0; +--- /dev/null ++++ b/include/linux/mtd/mtk_bmt.h +@@ -0,0 +1,18 @@ ++#ifndef __MTK_BMT_H ++#define __MTK_BMT_H ++ ++#ifdef CONFIG_MTD_NAND_MTK_BMT ++int mtk_bmt_attach(struct mtd_info *mtd); ++void mtk_bmt_detach(struct mtd_info *mtd); ++#else ++static inline int mtk_bmt_attach(struct mtd_info *mtd) ++{ ++ return 0; ++} ++ ++static inline void mtk_bmt_detach(struct mtd_info *mtd) ++{ ++} ++#endif ++ ++#endif diff --git a/target/linux/mediatek/patches-5.10/400-crypto-add-eip97-inside-secure-support.patch b/target/linux/mediatek/patches-5.10/400-crypto-add-eip97-inside-secure-support.patch new file mode 100644 index 0000000000..e0941a9550 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/400-crypto-add-eip97-inside-secure-support.patch @@ -0,0 +1,27 @@ +--- a/drivers/crypto/inside-secure/safexcel.c ++++ b/drivers/crypto/inside-secure/safexcel.c +@@ -600,6 +600,14 @@ static int safexcel_hw_init(struct safex + val |= EIP197_MST_CTRL_TX_MAX_CMD(5); + writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); + } ++ /* ++ * Set maximum number of TX commands to 2^4 = 16 for EIP97 HW2.1/HW2.3 ++ */ ++ else { ++ val = 0; ++ val |= EIP97_MST_CTRL_TX_MAX_CMD(4); ++ writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL); ++ } + + /* Configure wr/rd cache values */ + writel(EIP197_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) | +--- a/drivers/crypto/inside-secure/safexcel.h ++++ b/drivers/crypto/inside-secure/safexcel.h +@@ -314,6 +314,7 @@ + #define EIP197_MST_CTRL_RD_CACHE(n) (((n) & 0xf) << 0) + #define EIP197_MST_CTRL_WD_CACHE(n) (((n) & 0xf) << 4) + #define EIP197_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 20) ++#define EIP97_MST_CTRL_TX_MAX_CMD(n) (((n) & 0xf) << 4) + #define EIP197_MST_CTRL_BYTE_SWAP BIT(24) + #define EIP197_MST_CTRL_NO_BYTE_SWAP BIT(25) + #define EIP197_MST_CTRL_BYTE_SWAP_BITS GENMASK(25, 24) diff --git a/target/linux/mediatek/patches-5.10/401-crypto-fix-eip97-cache-incoherent.patch b/target/linux/mediatek/patches-5.10/401-crypto-fix-eip97-cache-incoherent.patch new file mode 100644 index 0000000000..be2bffb749 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/401-crypto-fix-eip97-cache-incoherent.patch @@ -0,0 +1,26 @@ +--- a/drivers/crypto/inside-secure/safexcel.h ++++ b/drivers/crypto/inside-secure/safexcel.h +@@ -736,6 +736,9 @@ enum safexcel_eip_version { + /* Priority we use for advertising our algorithms */ + #define SAFEXCEL_CRA_PRIORITY 300 + ++/* System cache line size */ ++#define SYSTEM_CACHELINE_SIZE 64 ++ + /* SM3 digest result for zero length message */ + #define EIP197_SM3_ZEROM_HASH "\x1A\xB2\x1D\x83\x55\xCF\xA1\x7F" \ + "\x8E\x61\x19\x48\x31\xE8\x1A\x8F" \ +--- a/drivers/crypto/inside-secure/safexcel_hash.c ++++ b/drivers/crypto/inside-secure/safexcel_hash.c +@@ -53,9 +53,9 @@ struct safexcel_ahash_req { + u8 block_sz; /* block size, only set once */ + u8 digest_sz; /* output digest size, only set once */ + __le32 state[SHA3_512_BLOCK_SIZE / +- sizeof(__le32)] __aligned(sizeof(__le32)); ++ sizeof(__le32)] __aligned(SYSTEM_CACHELINE_SIZE); + +- u64 len; ++ u64 len __aligned(SYSTEM_CACHELINE_SIZE); + u64 processed; + + u8 cache[HASH_CACHE_SIZE] __aligned(sizeof(u32)); diff --git a/target/linux/mediatek/patches-5.10/410-bt-mtk-serial-fix.patch b/target/linux/mediatek/patches-5.10/410-bt-mtk-serial-fix.patch new file mode 100644 index 0000000000..2e474dd5fe --- /dev/null +++ b/target/linux/mediatek/patches-5.10/410-bt-mtk-serial-fix.patch @@ -0,0 +1,33 @@ +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -82,6 +82,7 @@ struct serial8250_config { + #define UART_CAP_MINI (1 << 17) /* Mini UART on BCM283X family lacks: + * STOP PARITY EPAR SPAR WLEN5 WLEN6 + */ ++#define UART_CAP_NMOD (1 << 18) /* UART doesn't do termios */ + + #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ + #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -287,7 +287,7 @@ static const struct serial8250_config ua + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, +- .flags = UART_CAP_FIFO, ++ .flags = UART_CAP_FIFO | UART_CAP_NMOD, + }, + [PORT_NPCM] = { + .name = "Nuvoton 16550", +@@ -2687,6 +2687,11 @@ serial8250_do_set_termios(struct uart_po + unsigned long flags; + unsigned int baud, quot, frac = 0; + ++ if (up->capabilities & UART_CAP_NMOD) { ++ termios->c_cflag = 0; ++ return; ++ } ++ + if (up->capabilities & UART_CAP_MINI) { + termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR); + if ((termios->c_cflag & CSIZE) == CS5 || diff --git a/target/linux/mediatek/patches-5.10/500-gsw-rtl8367s-mt7622-support.patch b/target/linux/mediatek/patches-5.10/500-gsw-rtl8367s-mt7622-support.patch new file mode 100644 index 0000000000..bdd482def3 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/500-gsw-rtl8367s-mt7622-support.patch @@ -0,0 +1,25 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -334,6 +334,12 @@ config ROCKCHIP_PHY + help + Currently supports the integrated Ethernet PHY. + ++config RTL8367S_GSW ++ tristate "rtl8367 Gigabit Switch support for mt7622" ++ depends on NET_VENDOR_MEDIATEK ++ help ++ This driver supports rtl8367s in mt7622 ++ + config SMSC_PHY + tristate "SMSC PHYs" + help +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -88,6 +88,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o + obj-$(CONFIG_REALTEK_PHY) += realtek.o + obj-$(CONFIG_RENESAS_PHY) += uPD60620.o + obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o ++obj-$(CONFIG_RTL8367S_GSW) += rtk/ + obj-$(CONFIG_SMSC_PHY) += smsc.o + obj-$(CONFIG_STE10XP) += ste10Xp.o + obj-$(CONFIG_TERANETICS_PHY) += teranetics.o diff --git a/target/linux/mediatek/patches-5.10/600-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch b/target/linux/mediatek/patches-5.10/600-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch new file mode 100644 index 0000000000..02e4c130ea --- /dev/null +++ b/target/linux/mediatek/patches-5.10/600-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch @@ -0,0 +1,415 @@ +From patchwork Thu May 28 06:16:45 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Chuanjia Liu +X-Patchwork-Id: 11574793 +Return-Path: + +Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org + [172.30.200.123]) + by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 391201392 + for ; + Thu, 28 May 2020 06:20:27 +0000 (UTC) +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mail.kernel.org (Postfix) with ESMTPS id 104F620657 + for ; + Thu, 28 May 2020 06:20:27 +0000 (UTC) +Authentication-Results: mail.kernel.org; + dkim=pass (2048-bit key) header.d=lists.infradead.org + header.i=@lists.infradead.org header.b="raZHaWxs"; + dkim=fail reason="signature verification failed" (1024-bit key) + header.d=mediatek.com header.i=@mediatek.com header.b="YztrByG/" +DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 104F620657 +Authentication-Results: mail.kernel.org; + dmarc=fail (p=none dis=none) header.from=mediatek.com +Authentication-Results: mail.kernel.org; + spf=none + smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20170209; h=Sender: + Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: + List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: + Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + List-Owner; bh=aVtKU+Ey8KEM97+S66fz9ZMo+H8BP570jhAAvaRsNWc=; b=raZHaWxsfCxsrd + Byn/w1oLN/J82ApnNdBBXixq9Qj0uXIU2tBVqkiQ9lG6QDk7uguxQSJLeTqrsI/uxQmCI/PGQtZdP + sH0oboi2sbQSqJ/1ud4uL2pPaiLRJCxINF5oWjoZMsjn/b2fWvn52P6vTr/dxDTaabiVhY0HL0J+X + 7YGc1aYtO76HZHE2ke3puR42QkI8hE9E2cEhiLWeuUiLdUBegNM5MdYftu4nJTcCXnAeJjp/wIpYG + 7X737N9cmanDf6Bxr2bNPgaYzH+m7JK6eGxuAvWo0+PE9OX7MLrXY3KjixcjD/b0he0mfEM++gBAq + KBYKl5wh1mnlR2WIWXew==; +Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBtx-0005JC-DJ; Thu, 28 May 2020 06:20:25 +0000 +Received: from mailgw01.mediatek.com ([216.200.240.184]) + by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBtW-0002f2-75; Thu, 28 May 2020 06:20:01 +0000 +X-UUID: d5cb6d96c2a5421796c2f8a284ff3670-20200527 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=mediatek.com; + s=dk; + h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; + bh=EqjC+5cHgv6eykN7FPf2mtwK9UivJ3XSCE0jEvb8h+8=; + b=YztrByG/Ia304l9KDPBwoHFYkFCN6qBXPqwZgg56CA9VitadAg2+K1VgfEU+oHqsqcsGAMdZTRMQh17tpm4bJParw6MMzAQ28te2TcxvQMV8PZMkerJdZyyYblI7ybauPWuofAQgQMtuwSKVii8eTRJbf99OZ9vDGJP3zo2j1wU=; +X-UUID: d5cb6d96c2a5421796c2f8a284ff3670-20200527 +Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by + mailgw01.mediatek.com + (envelope-from ) + (musrelay.mediatek.com ESMTP with TLS) + with ESMTP id 681958707; Wed, 27 May 2020 22:20:16 -0800 +Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by + MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Wed, 27 May 2020 23:18:52 -0700 +Received: from mtkcas07.mediatek.inc (172.21.101.84) by + mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Thu, 28 May 2020 14:18:49 +0800 +Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc + (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend + Transport; Thu, 28 May 2020 14:18:47 +0800 +From: +To: , , +Subject: [PATCH v2 1/4] dt-bindings: PCI: Mediatek: Update PCIe binding +Date: Thu, 28 May 2020 14:16:45 +0800 +Message-ID: <20200528061648.32078-2-chuanjia.liu@mediatek.com> +X-Mailer: git-send-email 2.18.0 +In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +References: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +MIME-Version: 1.0 +X-MTK: N +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20200527_231958_261064_608CC03E +X-CRM114-Status: GOOD ( 13.95 ) +X-Spam-Score: -0.2 (/) +X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: + Content analysis details: (-0.2 points) + pts rule name description + ---- ---------------------- + -------------------------------------------------- + -0.0 SPF_PASS SPF: sender matches SPF record + 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record + 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 + encoding + -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from + author's domain + 0.1 DKIM_SIGNED Message has a DKIM or DK signature, + not necessarily + valid + -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature + -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from + envelope-from domain + 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay + lines +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.29 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com, + srv_heupstream@mediatek.com, "chuanjia.liu" , + linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, + jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org, + yong.wu@mediatek.com, bhelgaas@google.com, + linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org + +From: "chuanjia.liu" + +There are two independent PCIe controllers in MT2712/MT7622 platform, +and each of them should contain an independent MSI domain. + +In current architecture, MSI domain will be inherited from the root +bridge, and all of the devices will share the same MSI domain. +Hence that, the PCIe devices will not work properly if the irq number +which required is more than 32. + +Split the PCIe node for MT2712/MT7622 platform to fix MSI issue and +comply with the hardware design. + +Signed-off-by: chuanjia.liu +--- + .../bindings/pci/mediatek-pcie-cfg.yaml | 38 +++++ + .../devicetree/bindings/pci/mediatek-pcie.txt | 144 +++++++++++------- + 2 files changed, 129 insertions(+), 53 deletions(-) + create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie-cfg.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-cfg.yaml +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/pci/mediatek-pcie-cfg.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Mediatek PCIECFG controller ++ ++maintainers: ++ - Chuanjia Liu ++ - Jianjun Wang ++ ++description: | ++ The MediaTek PCIECFG controller controls some feature about ++ LTSSM, ASPM and so on. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - mediatek,mt7622-pciecfg ++ - mediatek,mt7629-pciecfg ++ - const: syscon ++ ++ reg: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ ++examples: ++ - | ++ pciecfg: pciecfg@1a140000 { ++ compatible = "mediatek,mt7622-pciecfg", "syscon"; ++ reg = <0 0x1a140000 0 0x1000>; ++ }; ++... +--- a/Documentation/devicetree/bindings/pci/mediatek-pcie.txt ++++ b/Documentation/devicetree/bindings/pci/mediatek-pcie.txt +@@ -8,7 +8,7 @@ Required properties: + "mediatek,mt7623-pcie" + "mediatek,mt7629-pcie" + - device_type: Must be "pci" +-- reg: Base addresses and lengths of the PCIe subsys and root ports. ++- reg: Base addresses and lengths of the root ports. + - reg-names: Names of the above areas to use during resource lookup. + - #address-cells: Address representation for root ports (must be 3) + - #size-cells: Size representation for root ports (must be 2) +@@ -19,10 +19,10 @@ Required properties: + - sys_ckN :transaction layer and data link layer clock + Required entries for MT2701/MT7623: + - free_ck :for reference clock of PCIe subsys +- Required entries for MT2712/MT7622: ++ Required entries for MT2712/MT7622/MT7629: + - ahb_ckN :AHB slave interface operating clock for CSR access and RC + initiated MMIO access +- Required entries for MT7622: ++ Required entries for MT7622/MT7629: + - axi_ckN :application layer MMIO channel operating clock + - aux_ckN :pe2_mac_bridge and pe2_mac_core operating clock when + pcie_mac_ck/pcie_pipe_ck is turned off +@@ -47,10 +47,13 @@ Required properties for MT7623/MT2701: + - reset-names: Must be "pcie-rst0", "pcie-rst1", "pcie-rstN".. based on the + number of root ports. + +-Required properties for MT2712/MT7622: ++Required properties for MT2712/MT7622/MT7629: + -interrupts: A list of interrupt outputs of the controller, must have one + entry for each PCIe port + ++Required properties for MT7622/MT7629: ++- mediatek,pcie-subsys: Should be a phandle of the pciecfg node. ++ + In addition, the device tree node must have sub-nodes describing each + PCIe port interface, having the following mandatory properties: + +@@ -143,56 +146,73 @@ Examples for MT7623: + + Examples for MT2712: + +- pcie: pcie@11700000 { ++ pcie1: pcie@112ff000 { + compatible = "mediatek,mt2712-pcie"; + device_type = "pci"; +- reg = <0 0x11700000 0 0x1000>, +- <0 0x112ff000 0 0x1000>; +- reg-names = "port0", "port1"; ++ reg = <0 0x112ff000 0 0x1000>; ++ reg-names = "port1"; + #address-cells = <3>; + #size-cells = <2>; +- interrupts = , +- ; +- clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>, +- <&topckgen CLK_TOP_PE2_MAC_P1_SEL>, +- <&pericfg CLK_PERI_PCIE0>, ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&topckgen CLK_TOP_PE2_MAC_P1_SEL>, + <&pericfg CLK_PERI_PCIE1>; +- clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1"; +- phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>; +- phy-names = "pcie-phy0", "pcie-phy1"; ++ clock-names = "sys_ck1", "ahb_ck1"; ++ phys = <&u3port1 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy1"; + bus-range = <0x00 0xff>; +- ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ ranges = <0x82000000 0 0x11400000 0x0 0x11400000 0 0x300000>; ++ status = "disabled"; + +- pcie0: pcie@0,0 { +- reg = <0x0000 0 0 0 0>; ++ slot1: pcie@1,0 { ++ reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0 0 0 1 &pcie_intc0 0>, +- <0 0 0 2 &pcie_intc0 1>, +- <0 0 0 3 &pcie_intc0 2>, +- <0 0 0 4 &pcie_intc0 3>; +- pcie_intc0: interrupt-controller { ++ interrupt-map = <0 0 0 1 &pcie_intc1 0>, ++ <0 0 0 2 &pcie_intc1 1>, ++ <0 0 0 3 &pcie_intc1 2>, ++ <0 0 0 4 &pcie_intc1 3>; ++ pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; ++ }; + +- pcie1: pcie@1,0 { +- reg = <0x0800 0 0 0 0>; ++ pcie0: pcie@11700000 { ++ compatible = "mediatek,mt2712-pcie"; ++ device_type = "pci"; ++ reg = <0 0x11700000 0 0x1000>; ++ reg-names = "port0"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>, ++ <&pericfg CLK_PERI_PCIE0>; ++ clock-names = "sys_ck0", "ahb_ck0"; ++ phys = <&u3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy0"; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ status = "disabled"; ++ ++ slot0: pcie@0,0 { ++ reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0 0 0 1 &pcie_intc1 0>, +- <0 0 0 2 &pcie_intc1 1>, +- <0 0 0 3 &pcie_intc1 2>, +- <0 0 0 4 &pcie_intc1 3>; +- pcie_intc1: interrupt-controller { ++ interrupt-map = <0 0 0 1 &pcie_intc0 0>, ++ <0 0 0 2 &pcie_intc0 1>, ++ <0 0 0 3 &pcie_intc0 2>, ++ <0 0 0 4 &pcie_intc0 3>; ++ pcie_intc0: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; +@@ -202,39 +222,31 @@ Examples for MT2712: + + Examples for MT7622: + +- pcie: pcie@1a140000 { ++ pcie0: pcie@1a143000 { + compatible = "mediatek,mt7622-pcie"; + device_type = "pci"; +- reg = <0 0x1a140000 0 0x1000>, +- <0 0x1a143000 0 0x1000>, +- <0 0x1a145000 0 0x1000>; +- reg-names = "subsys", "port0", "port1"; ++ reg = <0 0x1a143000 0 0x1000>; ++ reg-names = "port0"; ++ mediatek,pcie-cfg = <&pciecfg>; + #address-cells = <3>; + #size-cells = <2>; +- interrupts = , +- ; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; + clocks = <&pciesys CLK_PCIE_P0_MAC_EN>, +- <&pciesys CLK_PCIE_P1_MAC_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, +- <&pciesys CLK_PCIE_P1_AHB_EN>, + <&pciesys CLK_PCIE_P0_AUX_EN>, +- <&pciesys CLK_PCIE_P1_AUX_EN>, + <&pciesys CLK_PCIE_P0_AXI_EN>, +- <&pciesys CLK_PCIE_P1_AXI_EN>, + <&pciesys CLK_PCIE_P0_OBFF_EN>, +- <&pciesys CLK_PCIE_P1_OBFF_EN>, +- <&pciesys CLK_PCIE_P0_PIPE_EN>, +- <&pciesys CLK_PCIE_P1_PIPE_EN>; +- clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1", +- "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1", +- "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1"; +- phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>; +- phy-names = "pcie-phy0", "pcie-phy1"; ++ <&pciesys CLK_PCIE_P0_PIPE_EN>; ++ clock-names = "sys_ck0", "ahb_ck0", "aux_ck0", ++ "axi_ck0", "obff_ck0", "pipe_ck0"; ++ + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; +- ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ ranges = <0x82000000 0 0x20000000 0 0x20000000 0 0x8000000>; ++ status = "disabled"; + +- pcie0: pcie@0,0 { ++ slot0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; +@@ -251,8 +263,34 @@ Examples for MT7622: + #interrupt-cells = <1>; + }; + }; ++ }; ++ ++ pcie1: pcie@1a145000 { ++ compatible = "mediatek,mt7622-pcie"; ++ device_type = "pci"; ++ reg = <0 0x1a145000 0 0x1000>; ++ reg-names = "port1"; ++ mediatek,pcie-cfg = <&pciecfg>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&pciesys CLK_PCIE_P1_MAC_EN>, ++ /* designer has connect RC1 with p0_ahb clock */ ++ <&pciesys CLK_PCIE_P0_AHB_EN>, ++ <&pciesys CLK_PCIE_P1_AUX_EN>, ++ <&pciesys CLK_PCIE_P1_AXI_EN>, ++ <&pciesys CLK_PCIE_P1_OBFF_EN>, ++ <&pciesys CLK_PCIE_P1_PIPE_EN>; ++ clock-names = "sys_ck1", "ahb_ck1", "aux_ck1", ++ "axi_ck1", "obff_ck1", "pipe_ck1"; ++ ++ power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x28000000 0 0x28000000 0 0x8000000>; ++ status = "disabled"; + +- pcie1: pcie@1,0 { ++ slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; diff --git a/target/linux/mediatek/patches-5.10/601-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch b/target/linux/mediatek/patches-5.10/601-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch new file mode 100644 index 0000000000..9c18565319 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/601-PCI-mediatek-Use-regmap-to-get-shared-pcie-cfg-base.patch @@ -0,0 +1,217 @@ +From patchwork Thu May 28 06:16:46 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Chuanjia Liu +X-Patchwork-Id: 11574781 +Return-Path: + +Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org + [172.30.200.123]) + by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0A99B60D + for ; + Thu, 28 May 2020 06:19:04 +0000 (UTC) +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mail.kernel.org (Postfix) with ESMTPS id DCC99208FE + for ; + Thu, 28 May 2020 06:19:03 +0000 (UTC) +Authentication-Results: mail.kernel.org; + dkim=pass (2048-bit key) header.d=lists.infradead.org + header.i=@lists.infradead.org header.b="SpOi0ueF"; + dkim=fail reason="signature verification failed" (1024-bit key) + header.d=mediatek.com header.i=@mediatek.com header.b="UGIBoIEG" +DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DCC99208FE +Authentication-Results: mail.kernel.org; + dmarc=fail (p=none dis=none) header.from=mediatek.com +Authentication-Results: mail.kernel.org; + spf=none + smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20170209; h=Sender: + Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: + List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: + Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + List-Owner; bh=LIr5poLUT/UdH6/akh/pnICGGa3rUBkN+4FhE1DyOrU=; b=SpOi0ueFcoJ/ka + 4esa6cDd5oU4fp0z684ZVPaVvvhm/azSZBBMYinHaAW6EvzKcMNYIX9grP8eg/728lEPNTKVq0I8H + PQZ9KvD4uTu8Opo1hD8LsRSLr+YLpNKt3KPOY/4gpwQ97uU9rI5PwkuAxPBgR949Vh5EiG0Vaww1H + Ep+I5BFRn2LVVQZP1Z7U0A0VUcOTLJ4znoWRLEXxtM9/Wd4hwQsrEPQszeDFti/RbwGfJ5efOb5UL + fhwBzSxELEzAAgH7env/XD2sSSpVf2Qsn6WO8D3ZepMtWrRtARiaRKSNxSBQTg2SSHcjmBSJSzcX+ + w8wqWaUMs0crlBuZWS1g==; +Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBsc-0001tI-88; Thu, 28 May 2020 06:19:02 +0000 +Received: from mailgw01.mediatek.com ([216.200.240.184]) + by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBsZ-0001rp-6g; Thu, 28 May 2020 06:19:01 +0000 +X-UUID: beeaf5765357439c91eab1f67ca7ef43-20200527 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=mediatek.com; + s=dk; + h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; + bh=+IjWjsF/DhknqZB+lLSZ50cyvxDap+8w4tvqhp8Dv68=; + b=UGIBoIEGJUuq5pEvYEad1HVGpiv6yma+94hva83D2gD8lYmihRWkpJxB2yn+dVtNm7ZXXoQBf+jvvULOmslJgs1HZTLJTnjpdvLmQqo42OXRXSVpTE49HdRkJZDAIWIAReBfOEkFgNxcIX3uedrtnww/NLJ2lagrYPG5ET4lI2E=; +X-UUID: beeaf5765357439c91eab1f67ca7ef43-20200527 +Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com + (envelope-from ) + (musrelay.mediatek.com ESMTP with TLS) + with ESMTP id 603406343; Wed, 27 May 2020 22:19:17 -0800 +Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by + MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Wed, 27 May 2020 23:18:47 -0700 +Received: from mtkcas07.mediatek.inc (172.21.101.84) by + mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Thu, 28 May 2020 14:18:51 +0800 +Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc + (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend + Transport; Thu, 28 May 2020 14:18:49 +0800 +From: +To: , , +Subject: [PATCH v2 2/4] PCI: mediatek: Use regmap to get shared pcie-cfg base +Date: Thu, 28 May 2020 14:16:46 +0800 +Message-ID: <20200528061648.32078-3-chuanjia.liu@mediatek.com> +X-Mailer: git-send-email 2.18.0 +In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +References: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +MIME-Version: 1.0 +X-MTK: N +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20200527_231859_251275_BED2B1E2 +X-CRM114-Status: GOOD ( 11.62 ) +X-Spam-Score: -0.2 (/) +X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: + Content analysis details: (-0.2 points) + pts rule name description + ---- ---------------------- + -------------------------------------------------- + -0.0 SPF_PASS SPF: sender matches SPF record + 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record + 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 + encoding + -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from + author's domain + 0.1 DKIM_SIGNED Message has a DKIM or DK signature, + not necessarily + valid + -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature + -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from + envelope-from domain + 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay + lines +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.29 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com, + srv_heupstream@mediatek.com, "chuanjia.liu" , + linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, + jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org, + yong.wu@mediatek.com, bhelgaas@google.com, + linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org + +From: "chuanjia.liu" + +Use regmap to get shared pcie-cfg base and change +the method to get pcie irq. + +Signed-off-by: chuanjia.liu +--- + drivers/pci/controller/pcie-mediatek.c | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -23,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #include "../pci.h" +@@ -205,6 +207,7 @@ struct mtk_pcie_port { + * struct mtk_pcie - PCIe host information + * @dev: pointer to PCIe device + * @base: IO mapped register base ++ * @cfg: IO mapped register map for PCIe config + * @free_ck: free-run reference clock + * @mem: non-prefetchable memory resource + * @ports: pointer to PCIe port information +@@ -213,6 +216,7 @@ struct mtk_pcie_port { + struct mtk_pcie { + struct device *dev; + void __iomem *base; ++ struct regmap *cfg; + struct clk *free_ck; + + struct list_head ports; +@@ -648,7 +652,7 @@ static int mtk_pcie_setup_irq(struct mtk + return err; + } + +- port->irq = platform_get_irq(pdev, port->slot); ++ port->irq = platform_get_irq_byname(pdev, "pcie_irq"); + if (port->irq < 0) + return port->irq; + +@@ -674,12 +678,11 @@ static int mtk_pcie_startup_port_v2(stru + if (!mem) + return -EINVAL; + +- /* MT7622 platforms need to enable LTSSM and ASPM from PCIe subsys */ +- if (pcie->base) { +- val = readl(pcie->base + PCIE_SYS_CFG_V2); +- val |= PCIE_CSR_LTSSM_EN(port->slot) | +- PCIE_CSR_ASPM_L1_EN(port->slot); +- writel(val, pcie->base + PCIE_SYS_CFG_V2); ++ /* MT7622/MT7629 platforms need to enable LTSSM and ASPM. */ ++ if (pcie->cfg) { ++ val = PCIE_CSR_LTSSM_EN(port->slot) | ++ PCIE_CSR_ASPM_L1_EN(port->slot); ++ regmap_update_bits(pcie->cfg, PCIE_SYS_CFG_V2, val, val); + } + + /* Assert all reset signals */ +@@ -983,6 +986,7 @@ static int mtk_pcie_subsys_powerup(struc + struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *regs; ++ struct device_node *cfg_node; + int err; + + /* get shared registers, which are optional */ +@@ -995,6 +999,13 @@ static int mtk_pcie_subsys_powerup(struc + } + } + ++ cfg_node = of_parse_phandle(dev->of_node, "mediatek,pcie-cfg", 0); ++ if (cfg_node) { ++ pcie->cfg = syscon_node_to_regmap(cfg_node); ++ if (IS_ERR(pcie->cfg)) ++ return PTR_ERR(pcie->cfg); ++ } ++ + pcie->free_ck = devm_clk_get(dev, "free_ck"); + if (IS_ERR(pcie->free_ck)) { + if (PTR_ERR(pcie->free_ck) == -EPROBE_DEFER) diff --git a/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch b/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch new file mode 100644 index 0000000000..fa4a6ce2db --- /dev/null +++ b/target/linux/mediatek/patches-5.10/602-arm64-dts-mediatek-Split-PCIe-node-for-MT2712-MT7622.patch @@ -0,0 +1,417 @@ +From patchwork Thu May 28 06:16:47 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Chuanjia Liu +X-Patchwork-Id: 11574785 +Return-Path: + +Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org + [172.30.200.123]) + by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 933301391 + for ; + Thu, 28 May 2020 06:19:16 +0000 (UTC) +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mail.kernel.org (Postfix) with ESMTPS id D19F02078C + for ; + Thu, 28 May 2020 06:19:15 +0000 (UTC) +Authentication-Results: mail.kernel.org; + dkim=pass (2048-bit key) header.d=lists.infradead.org + header.i=@lists.infradead.org header.b="s8K7t7DF"; + dkim=fail reason="signature verification failed" (1024-bit key) + header.d=mediatek.com header.i=@mediatek.com header.b="RhX81Iqp" +DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D19F02078C +Authentication-Results: mail.kernel.org; + dmarc=fail (p=none dis=none) header.from=mediatek.com +Authentication-Results: mail.kernel.org; + spf=none + smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20170209; h=Sender: + Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: + List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: + Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + List-Owner; bh=NHyHqNMcE7LW10MwduOJoKiWe8cv+XayY+L6WDZeSu0=; b=s8K7t7DFh1iQ5w + eGvuMRgXEQv/YWRuSZRyX8lx8R2H9IuawEIgkhO6lEo6xv0VdsRuj8SptfoWg5afCItMhih373M21 + 6sUy3tEiuKGgklfxLU0reLEkaATkKRGLJDY3eSSs1mvZDrydKuZLDTka+YDGaiESlOhqMr95Nm6YM + yK8O00qTwSRPJUILRsBv1e/Kz8NRCmYhs56snABJkKeJ51NRAkb20R6qGTEd6UyBlz3jTVYwluLgF + bdqzywDT6+BNg/Agh6Zd+v2PpO4cmwCpGm62+3UUyZkfi/aQ4qZ/AFAfSQI+3ZBAgsKMC1PGifOi/ + FgGxIvAUk6atBy7DAHuw==; +Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBsn-00025C-EF; Thu, 28 May 2020 06:19:13 +0000 +Received: from mailgw01.mediatek.com ([216.200.240.184]) + by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeBsZ-0001s4-6j; Thu, 28 May 2020 06:19:01 +0000 +X-UUID: c6210e6371fa445db0ae40a8b8a7a0a1-20200527 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=mediatek.com; + s=dk; + h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; + bh=X9AwTdbhpWmlWY4LjTm8KLq4Cca3YI9UnyCX3O0BAak=; + b=RhX81Iqp0mWhBDyMQMFSEtt23+DGAWoin1SrFGP1bzp6GEtu38b2pK5RJVBshJtuxi/a1uMXZjeDsHJn02VGdNA07FrzZ7jq6YYEL+8cJs2DnhySmNElZazXPv2vKu9TWygfilTT24h/u8V/eszuRuhkdoUKWol8LwDlPl9gskg=; +X-UUID: c6210e6371fa445db0ae40a8b8a7a0a1-20200527 +Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com + (envelope-from ) + (musrelay.mediatek.com ESMTP with TLS) + with ESMTP id 7561992; Wed, 27 May 2020 22:19:17 -0800 +Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by + MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Wed, 27 May 2020 23:18:47 -0700 +Received: from mtkcas07.mediatek.inc (172.21.101.84) by + mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Thu, 28 May 2020 14:18:52 +0800 +Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc + (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend + Transport; Thu, 28 May 2020 14:18:51 +0800 +From: +To: , , +Subject: [PATCH v2 3/4] arm64: dts: mediatek: Split PCIe node for + MT2712/MT7622 +Date: Thu, 28 May 2020 14:16:47 +0800 +Message-ID: <20200528061648.32078-4-chuanjia.liu@mediatek.com> +X-Mailer: git-send-email 2.18.0 +In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +References: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +MIME-Version: 1.0 +X-MTK: N +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20200527_231859_253529_B6751C5A +X-CRM114-Status: GOOD ( 12.20 ) +X-Spam-Score: -0.2 (/) +X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: + Content analysis details: (-0.2 points) + pts rule name description + ---- ---------------------- + -------------------------------------------------- + -0.0 SPF_PASS SPF: sender matches SPF record + 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record + 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 + encoding + -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from + author's domain + 0.1 DKIM_SIGNED Message has a DKIM or DK signature, + not necessarily + valid + -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature + -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from + envelope-from domain + 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay + lines +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.29 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com, + srv_heupstream@mediatek.com, "chuanjia.liu" , + linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, + jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org, + yong.wu@mediatek.com, bhelgaas@google.com, + linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org + +From: "chuanjia.liu" + +There are two independent PCIe controllers in MT2712/MT7622 platform, +and each of them should contain an independent MSI domain. + +In current architecture, MSI domain will be inherited from the root +bridge, and all of the devices will share the same MSI domain. +Hence that, the PCIe devices will not work properly if the irq number +which required is more than 32. + +Split the PCIe node for MT2712/MT7622 platform to fix MSI issue and +comply with the hardware design. + +Signed-off-by: chuanjia.liu +--- + arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 75 +++++++++++-------- + .../dts/mediatek/mt7622-bananapi-bpi-r64.dts | 16 ++-- + arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts | 6 +- + arch/arm64/boot/dts/mediatek/mt7622.dtsi | 68 +++++++++++------ + 4 files changed, 96 insertions(+), 69 deletions(-) + +--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi +@@ -915,60 +915,73 @@ + }; + }; + +- pcie: pcie@11700000 { ++ pcie1: pcie@112ff000 { + compatible = "mediatek,mt2712-pcie"; + device_type = "pci"; +- reg = <0 0x11700000 0 0x1000>, +- <0 0x112ff000 0 0x1000>; +- reg-names = "port0", "port1"; ++ reg = <0 0x112ff000 0 0x1000>; ++ reg-names = "port1"; + #address-cells = <3>; + #size-cells = <2>; +- interrupts = , +- ; +- clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>, +- <&topckgen CLK_TOP_PE2_MAC_P1_SEL>, +- <&pericfg CLK_PERI_PCIE0>, ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&topckgen CLK_TOP_PE2_MAC_P1_SEL>, + <&pericfg CLK_PERI_PCIE1>; +- clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1"; +- phys = <&u3port0 PHY_TYPE_PCIE>, <&u3port1 PHY_TYPE_PCIE>; +- phy-names = "pcie-phy0", "pcie-phy1"; ++ clock-names = "sys_ck1", "ahb_ck1"; ++ phys = <&u3port1 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy1"; + bus-range = <0x00 0xff>; +- ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ ranges = <0x82000000 0 0x11400000 0x0 0x11400000 0 0x300000>; ++ status = "disabled"; + +- pcie0: pcie@0,0 { +- device_type = "pci"; +- status = "disabled"; +- reg = <0x0000 0 0 0 0>; ++ slot1: pcie@1,0 { ++ reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0 0 0 1 &pcie_intc0 0>, +- <0 0 0 2 &pcie_intc0 1>, +- <0 0 0 3 &pcie_intc0 2>, +- <0 0 0 4 &pcie_intc0 3>; +- pcie_intc0: interrupt-controller { ++ interrupt-map = <0 0 0 1 &pcie_intc1 0>, ++ <0 0 0 2 &pcie_intc1 1>, ++ <0 0 0 3 &pcie_intc1 2>, ++ <0 0 0 4 &pcie_intc1 3>; ++ pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; ++ }; + +- pcie1: pcie@1,0 { +- device_type = "pci"; +- status = "disabled"; +- reg = <0x0800 0 0 0 0>; ++ pcie0: pcie@11700000 { ++ compatible = "mediatek,mt2712-pcie"; ++ device_type = "pci"; ++ reg = <0 0x11700000 0 0x1000>; ++ reg-names = "port0"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>, ++ <&pericfg CLK_PERI_PCIE0>; ++ clock-names = "sys_ck0", "ahb_ck0"; ++ phys = <&u3port0 PHY_TYPE_PCIE>; ++ phy-names = "pcie-phy0"; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ status = "disabled"; ++ ++ slot0: pcie@0,0 { ++ reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0 0 0 1 &pcie_intc1 0>, +- <0 0 0 2 &pcie_intc1 1>, +- <0 0 0 3 &pcie_intc1 2>, +- <0 0 0 4 &pcie_intc1 3>; +- pcie_intc1: interrupt-controller { ++ interrupt-map = <0 0 0 1 &pcie_intc0 0>, ++ <0 0 0 2 &pcie_intc0 1>, ++ <0 0 0 3 &pcie_intc0 2>, ++ <0 0 0 4 &pcie_intc0 3>; ++ pcie_intc0: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; +--- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +@@ -257,18 +257,16 @@ + }; + }; + +-&pcie { ++&pcie0 { + pinctrl-names = "default"; +- pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; ++ pinctrl-0 = <&pcie0_pins>; + status = "okay"; ++}; + +- pcie@0,0 { +- status = "okay"; +- }; +- +- pcie@1,0 { +- status = "okay"; +- }; ++&pcie1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie1_pins>; ++ status = "okay"; + }; + + &pio { +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -792,45 +792,41 @@ + #reset-cells = <1>; + }; + +- pcie: pcie@1a140000 { ++ pciecfg: pciecfg@1a140000 { ++ compatible = "mediatek,mt7622-pciecfg", "syscon"; ++ reg = <0 0x1a140000 0 0x1000>; ++ }; ++ ++ pcie0: pcie@1a143000 { + compatible = "mediatek,mt7622-pcie"; + device_type = "pci"; +- reg = <0 0x1a140000 0 0x1000>, +- <0 0x1a143000 0 0x1000>, +- <0 0x1a145000 0 0x1000>; +- reg-names = "subsys", "port0", "port1"; ++ reg = <0 0x1a143000 0 0x1000>; ++ reg-names = "port0"; ++ mediatek,pcie-cfg = <&pciecfg>; + #address-cells = <3>; + #size-cells = <2>; +- interrupts = , +- ; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; + clocks = <&pciesys CLK_PCIE_P0_MAC_EN>, +- <&pciesys CLK_PCIE_P1_MAC_EN>, +- <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P0_AUX_EN>, +- <&pciesys CLK_PCIE_P1_AUX_EN>, + <&pciesys CLK_PCIE_P0_AXI_EN>, +- <&pciesys CLK_PCIE_P1_AXI_EN>, + <&pciesys CLK_PCIE_P0_OBFF_EN>, +- <&pciesys CLK_PCIE_P1_OBFF_EN>, +- <&pciesys CLK_PCIE_P0_PIPE_EN>, +- <&pciesys CLK_PCIE_P1_PIPE_EN>; +- clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1", +- "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1", +- "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1"; ++ <&pciesys CLK_PCIE_P0_PIPE_EN>; ++ clock-names = "sys_ck0", "ahb_ck0", "aux_ck0", ++ "axi_ck0", "obff_ck0", "pipe_ck0"; ++ + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; +- ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; ++ ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>; + status = "disabled"; + +- pcie0: pcie@0,0 { ++ slot0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; +- status = "disabled"; +- + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, +@@ -842,15 +838,39 @@ + #interrupt-cells = <1>; + }; + }; ++ }; + +- pcie1: pcie@1,0 { ++ pcie1: pcie@1a145000 { ++ compatible = "mediatek,mt7622-pcie"; ++ device_type = "pci"; ++ reg = <0 0x1a145000 0 0x1000>; ++ reg-names = "port1"; ++ mediatek,pcie-cfg = <&pciecfg>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; ++ clocks = <&pciesys CLK_PCIE_P1_MAC_EN>, ++ /* designer has connect RC1 with p0_ahb clock */ ++ <&pciesys CLK_PCIE_P0_AHB_EN>, ++ <&pciesys CLK_PCIE_P1_AUX_EN>, ++ <&pciesys CLK_PCIE_P1_AXI_EN>, ++ <&pciesys CLK_PCIE_P1_OBFF_EN>, ++ <&pciesys CLK_PCIE_P1_PIPE_EN>; ++ clock-names = "sys_ck1", "ahb_ck1", "aux_ck1", ++ "axi_ck1", "obff_ck1", "pipe_ck1"; ++ ++ power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; ++ bus-range = <0x00 0xff>; ++ ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>; ++ status = "disabled"; ++ ++ slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; +- status = "disabled"; +- + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, +--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts +@@ -232,18 +232,16 @@ + }; + }; + +-&pcie { ++&pcie0 { + pinctrl-names = "default"; +- pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; ++ pinctrl-0 = <&pcie0_pins>; + status = "okay"; ++}; + +- pcie@0,0 { +- status = "okay"; +- }; +- +- pcie@1,0 { +- status = "okay"; +- }; ++&pcie1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie1_pins>; ++ status = "okay"; + }; + + &pio { diff --git a/target/linux/mediatek/patches-5.10/603-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch b/target/linux/mediatek/patches-5.10/603-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch new file mode 100644 index 0000000000..799cc31ab7 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/603-ARM-dts-mediatek-Update-mt7629-PCIe-node.patch @@ -0,0 +1,203 @@ +From patchwork Thu May 28 06:16:48 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Chuanjia Liu +X-Patchwork-Id: 11574797 +Return-Path: + +Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org + [172.30.200.123]) + by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 30A5E1392 + for ; + Thu, 28 May 2020 06:29:05 +0000 (UTC) +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by mail.kernel.org (Postfix) with ESMTPS id 08B6320721 + for ; + Thu, 28 May 2020 06:29:05 +0000 (UTC) +Authentication-Results: mail.kernel.org; + dkim=pass (2048-bit key) header.d=lists.infradead.org + header.i=@lists.infradead.org header.b="auhxDafY"; + dkim=fail reason="signature verification failed" (1024-bit key) + header.d=mediatek.com header.i=@mediatek.com header.b="Kj09Arxb" +DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 08B6320721 +Authentication-Results: mail.kernel.org; + dmarc=fail (p=none dis=none) header.from=mediatek.com +Authentication-Results: mail.kernel.org; + spf=none + smtp.mailfrom=linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20170209; h=Sender: + Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: + List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: + Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + List-Owner; bh=+QPxF1vlOH7StIZYuXJa3V40x8QVDxCLF9AFXHblB9M=; b=auhxDafYBeaUZO + aYp2KVO8Aie0v4tYtRwBon7hF+x55JwD78SAxQR2RsSvrlOo9cMYYby+ToUWflVUWQ60FapAl+w+l + nkEjIOrLBErHwxNOcsD8T5kjyCBMqlz4OMAQYUDNJ3fSugRlGhOtxkjCGd9ebB8N2Rvu6/U8P1A9n + P15mEQoc+RLonR1+9mBgwTEXErjsraxkimTD4Txsp4IvMs3UdsMkP+r3OT5S/p+Uj6O9ES0h7xIon + aL79KaVqRLHrfZxnrVwuGiecAiTp8qLy9clHuJU32NA6ZcXH1OnWipKApgp8Ck7ys80WPKaMrat9B + XuskJ63w13DZAbCVvuGQ==; +Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeC2J-00014n-M9; Thu, 28 May 2020 06:29:03 +0000 +Received: from mailgw02.mediatek.com ([216.200.240.185]) + by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) + id 1jeC2H-00013t-Li; Thu, 28 May 2020 06:29:03 +0000 +X-UUID: a4877c1586e64afeb2d6172e10605d2b-20200527 +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=mediatek.com; + s=dk; + h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; + bh=CIwcBFK1x0LbOjDt1BG6/knHFxDHRiqj8ov/jWEZDBY=; + b=Kj09ArxbnLVTc9bpaVPT3jQrIVjhL87sSYyVF9dFypS976k78Ce9gZd0f4K3zAZbYZHYoQtuyOQ9TOeufQfgD+Cr+j5VR7pTdO2E1iXHFs/eQAz5gAjvjlK01z1JiunrLnn9dvIr6c1gEkjQHny0VpuZ1duxx79jwYusg/Nw6Wc=; +X-UUID: a4877c1586e64afeb2d6172e10605d2b-20200527 +Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by + mailgw02.mediatek.com + (envelope-from ) + (musrelay.mediatek.com ESMTP with TLS) + with ESMTP id 899663677; Wed, 27 May 2020 22:29:21 -0800 +Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by + MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Wed, 27 May 2020 23:18:50 -0700 +Received: from mtkcas07.mediatek.inc (172.21.101.84) by + mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id + 15.0.1497.2; Thu, 28 May 2020 14:18:54 +0800 +Received: from localhost.localdomain (10.17.3.153) by mtkcas07.mediatek.inc + (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend + Transport; Thu, 28 May 2020 14:18:52 +0800 +From: +To: , , +Subject: [PATCH v2 4/4] ARM: dts: mediatek: Update mt7629 PCIe node +Date: Thu, 28 May 2020 14:16:48 +0800 +Message-ID: <20200528061648.32078-5-chuanjia.liu@mediatek.com> +X-Mailer: git-send-email 2.18.0 +In-Reply-To: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +References: <20200528061648.32078-1-chuanjia.liu@mediatek.com> +MIME-Version: 1.0 +X-MTK: N +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20200527_232901_719172_E5A99C62 +X-CRM114-Status: GOOD ( 11.61 ) +X-Spam-Score: -0.2 (/) +X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: + Content analysis details: (-0.2 points) + pts rule name description + ---- ---------------------- + -------------------------------------------------- + -0.0 SPF_PASS SPF: sender matches SPF record + 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record + 0.0 MIME_BASE64_TEXT RAW: Message text disguised using base64 + encoding + -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from + author's domain + 0.1 DKIM_SIGNED Message has a DKIM or DK signature, + not necessarily + valid + -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature + -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from + envelope-from domain + 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay + lines +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.29 +Precedence: list +List-Id: +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Cc: devicetree@vger.kernel.org, lorenzo.pieralisi@arm.com, + srv_heupstream@mediatek.com, "chuanjia.liu" , + linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, + jianjun.wang@mediatek.com, linux-mediatek@lists.infradead.org, + yong.wu@mediatek.com, bhelgaas@google.com, + linux-arm-kernel@lists.infradead.org, amurray@thegoodpenguin.co.uk +Sender: "Linux-mediatek" +Errors-To: + linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org + +From: "chuanjia.liu" + +Remove unused property and add pciecfg node. + +Signed-off-by: chuanjia.liu +--- + arch/arm/boot/dts/mt7629-rfb.dts | 3 ++- + arch/arm/boot/dts/mt7629.dtsi | 23 +++++++++++++---------- + 2 files changed, 15 insertions(+), 11 deletions(-) + +--- a/arch/arm/boot/dts/mt7629-rfb.dts ++++ b/arch/arm/boot/dts/mt7629-rfb.dts +@@ -144,9 +144,10 @@ + }; + }; + +-&pcie { ++&pcie1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; ++ status = "okay"; + }; + + &pciephy1 { +--- a/arch/arm/boot/dts/mt7629.dtsi ++++ b/arch/arm/boot/dts/mt7629.dtsi +@@ -382,16 +382,21 @@ + #reset-cells = <1>; + }; + +- pcie: pcie@1a140000 { ++ pciecfg: pciecfg@1a140000 { ++ compatible = "mediatek,mt7629-pciecfg", "syscon"; ++ reg = <0x1a140000 0x1000>; ++ }; ++ ++ pcie1: pcie@1a145000 { + compatible = "mediatek,mt7629-pcie"; + device_type = "pci"; +- reg = <0x1a140000 0x1000>, +- <0x1a145000 0x1000>; +- reg-names = "subsys","port1"; ++ reg = <0x1a145000 0x1000>; ++ reg-names = "port1"; ++ mediatek,pcie-cfg = <&pciecfg>; + #address-cells = <3>; + #size-cells = <2>; +- interrupts = , +- ; ++ interrupts = ; ++ interrupt-names = "pcie_irq"; + clocks = <&pciesys CLK_PCIE_P1_MAC_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P1_AUX_EN>, +@@ -412,21 +417,19 @@ + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x20000000 0 0x10000000>; ++ status = "disabled"; + +- pcie1: pcie@1,0 { +- device_type = "pci"; ++ slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; +- num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; +- + pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; diff --git a/target/linux/mediatek/patches-5.10/610-pcie-mediatek-fix-clearing-interrupt-status.patch b/target/linux/mediatek/patches-5.10/610-pcie-mediatek-fix-clearing-interrupt-status.patch new file mode 100644 index 0000000000..7b74a8ac73 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/610-pcie-mediatek-fix-clearing-interrupt-status.patch @@ -0,0 +1,24 @@ +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:33:27 +0200 +Subject: [PATCH] pcie-mediatek: fix clearing interrupt status + +Clearing the status needs to happen after running the handler, otherwise +we will get an extra spurious interrupt after the cause has been cleared + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -613,10 +613,10 @@ static void mtk_pcie_intr_handler(struct + if (status & INTX_MASK) { + for_each_set_bit_from(bit, &status, PCI_NUM_INTX + INTX_SHIFT) { + /* Clear the INTx */ +- writel(1 << bit, port->base + PCIE_INT_STATUS); + virq = irq_find_mapping(port->irq_domain, + bit - INTX_SHIFT); + generic_handle_irq(virq); ++ writel(1 << bit, port->base + PCIE_INT_STATUS); + } + } + diff --git a/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch b/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch new file mode 100644 index 0000000000..8c9194e5f2 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/700-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch @@ -0,0 +1,85 @@ +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:36:06 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent DMA + +It improves performance by eliminating the need for a cache flush on rx and tx + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -357,7 +357,7 @@ + }; + + cci_control2: slave-if@5000 { +- compatible = "arm,cci-400-ctrl-if"; ++ compatible = "arm,cci-400-ctrl-if", "syscon"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; +@@ -967,6 +967,8 @@ + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys>; ++ mediatek,cci-control = <&cci_control2>; ++ dma-coherent; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2482,6 +2483,13 @@ static int mtk_hw_init(struct mtk_eth *e + if (ret) + goto err_disable_pm; + ++ if (of_dma_is_coherent(eth->dev->of_node)) { ++ u32 mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | ++ ETHSYS_DMA_AG_MAP_PPE; ++ ++ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, mask, mask); ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + ret = device_reset(eth->dev); + if (ret) { +@@ -3061,6 +3069,16 @@ static int mtk_probe(struct platform_dev + } + } + ++ if (of_dma_is_coherent(pdev->dev.of_node)) { ++ struct regmap *cci; ++ ++ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, ++ "mediatek,cci-control"); ++ /* enable CPU/bus coherency */ ++ if (!IS_ERR(cci)) ++ regmap_write(cci, 0, 3); ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), + GFP_KERNEL); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -437,6 +437,12 @@ + #define RSTCTRL_FE BIT(6) + #define RSTCTRL_PPE BIT(31) + ++/* ethernet dma channel agent map */ ++#define ETHSYS_DMA_AG_MAP 0x408 ++#define ETHSYS_DMA_AG_MAP_PDMA BIT(0) ++#define ETHSYS_DMA_AG_MAP_QDMA BIT(1) ++#define ETHSYS_DMA_AG_MAP_PPE BIT(2) ++ + /* SGMII subsystem config registers */ + /* Register to auto-negotiation restart */ + #define SGMSYS_PCS_CONTROL_1 0x0 diff --git a/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch b/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch new file mode 100644 index 0000000000..503cc8937d --- /dev/null +++ b/target/linux/mediatek/patches-5.10/710-pci-pcie-mediatek-add-support-for-coherent-DMA.patch @@ -0,0 +1,108 @@ +From: Felix Fietkau +Date: Fri, 4 Sep 2020 18:42:42 +0200 +Subject: [PATCH] pci: pcie-mediatek: add support for coherent DMA + +It improves performance by eliminating the need for a cache flush for DMA on +attached devices + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -803,6 +803,8 @@ + reg = <0 0x1a143000 0 0x1000>; + reg-names = "port0"; + mediatek,pcie-cfg = <&pciecfg>; ++ mediatek,hifsys = <&hifsys>; ++ mediatek,cci-control = <&cci_control2>; + #address-cells = <3>; + #size-cells = <2>; + interrupts = ; +@@ -820,6 +822,7 @@ + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x8000000>; + status = "disabled"; ++ dma-coherent; + + slot0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; +@@ -846,6 +849,8 @@ + reg = <0 0x1a145000 0 0x1000>; + reg-names = "port1"; + mediatek,pcie-cfg = <&pciecfg>; ++ mediatek,hifsys = <&hifsys>; ++ mediatek,cci-control = <&cci_control2>; + #address-cells = <3>; + #size-cells = <2>; + interrupts = ; +@@ -864,6 +869,7 @@ + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x28000000 0x0 0x28000000 0 0x8000000>; + status = "disabled"; ++ dma-coherent; + + slot1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; +@@ -923,6 +929,11 @@ + }; + }; + ++ hifsys: syscon@1af00000 { ++ compatible = "mediatek,mt7622-hifsys", "syscon"; ++ reg = <0 0x1af00000 0 0x70>; ++ }; ++ + ethsys: syscon@1b000000 { + compatible = "mediatek,mt7622-ethsys", + "syscon"; +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -139,6 +140,11 @@ + #define PCIE_LINK_STATUS_V2 0x804 + #define PCIE_PORT_LINKUP_V2 BIT(10) + ++/* DMA channel mapping */ ++#define HIFSYS_DMA_AG_MAP 0x008 ++#define HIFSYS_DMA_AG_MAP_PCIE0 BIT(0) ++#define HIFSYS_DMA_AG_MAP_PCIE1 BIT(1) ++ + struct mtk_pcie_port; + + /** +@@ -1040,6 +1046,27 @@ static int mtk_pcie_setup(struct mtk_pci + struct mtk_pcie_port *port, *tmp; + int err; + ++ if (of_dma_is_coherent(node)) { ++ struct regmap *con; ++ u32 mask; ++ ++ con = syscon_regmap_lookup_by_phandle(node, ++ "mediatek,cci-control"); ++ /* enable CPU/bus coherency */ ++ if (!IS_ERR(con)) ++ regmap_write(con, 0, 3); ++ ++ con = syscon_regmap_lookup_by_phandle(node, ++ "mediatek,hifsys"); ++ if (IS_ERR(con)) { ++ dev_err(dev, "missing hifsys node\n"); ++ return PTR_ERR(con); ++ } ++ ++ mask = HIFSYS_DMA_AG_MAP_PCIE0 | HIFSYS_DMA_AG_MAP_PCIE1; ++ regmap_update_bits(con, HIFSYS_DMA_AG_MAP, mask, mask); ++ } ++ + for_each_available_child_of_node(node, child) { + int slot; + -- cgit v1.2.3