diff options
44 files changed, 130 insertions, 9770 deletions
diff --git a/target/linux/ramips/patches-5.4/0001-MIPS-ralink-Add-rt3352-SPI_CS1-pinmux.patch b/target/linux/ramips/patches-5.4/0001-MIPS-ralink-Add-rt3352-SPI_CS1-pinmux.patch deleted file mode 100644 index 4f803dfd0d..0000000000 --- a/target/linux/ramips/patches-5.4/0001-MIPS-ralink-Add-rt3352-SPI_CS1-pinmux.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 35d017947401d9f449a7e55e52506744e0c62577 Mon Sep 17 00:00:00 2001 -From: Mathias Kresin <dev@kresin.me> -Date: Wed, 22 Aug 2018 22:38:06 +0200 -Subject: [PATCH] MIPS: ralink: Add rt3352 SPI_CS1 pinmux - -The rt3352 has a pin that can be used as second spi chip select, -watchdog reset or GPIO. The pinmux setup was missing the definition of -said pin. - -The pin is configured via the same bit on rt5350, so reuse the existing -macro. - -Signed-off-by: Mathias Kresin <dev@kresin.me> -Signed-off-by: Paul Burton <paul.burton@mips.com> -Patchwork: https://patchwork.linux-mips.org/patch/20301/ -Cc: John Crispin <john@phrozen.org> -Cc: Ralf Baechle <ralf@linux-mips.org> -Cc: James Hogan <jhogan@kernel.org> -Cc: linux-mips@linux-mips.org -Cc: linux-kernel@vger.kernel.org ---- - arch/mips/ralink/rt305x.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/arch/mips/ralink/rt305x.c -+++ b/arch/mips/ralink/rt305x.c -@@ -49,6 +49,10 @@ static struct rt2880_pmx_func rgmii_func - static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) }; - static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) }; - static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) }; -+static struct rt2880_pmx_func rt3352_cs1_func[] = { -+ FUNC("spi_cs1", 0, 45, 1), -+ FUNC("wdg_cs1", 1, 45, 1), -+}; - - static struct rt2880_pmx_group rt3050_pinmux_data[] = { - GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), -@@ -75,6 +79,7 @@ static struct rt2880_pmx_group rt3352_pi - GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA), - GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA), - GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED), -+ GRP("spi_cs1", rt3352_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1), - { 0 } - }; - diff --git a/target/linux/ramips/patches-5.4/0002-MIPS-pci-rt2880-set-pci-controller-of_node.patch b/target/linux/ramips/patches-5.4/0002-MIPS-pci-rt2880-set-pci-controller-of_node.patch deleted file mode 100644 index 7ac092cfb0..0000000000 --- a/target/linux/ramips/patches-5.4/0002-MIPS-pci-rt2880-set-pci-controller-of_node.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0eb1cfffd5433d8dce3e4163a5cd9accc6000856 Mon Sep 17 00:00:00 2001 -From: Tobias Wolf <dev-NTEO@vplace.de> -Date: Wed, 5 Sep 2018 08:51:26 +0200 -Subject: [PATCH] MIPS: pci-rt2880: set pci controller of_node - -Set the PCI controller of_node such that PCI devices can be -instantiated via device tree. - -Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de> -Signed-off-by: Mathias Kresin <dev@kresin.me> -Acked-by: John Crispin <john@phrozen.org> -Signed-off-by: Paul Burton <paul.burton@mips.com> -Patchwork: https://patchwork.linux-mips.org/patch/20423/ -Cc: Ralf Baechle <ralf@linux-mips.org> -Cc: James Hogan <jhogan@kernel.org> -Cc: linux-mips@linux-mips.org -Cc: linux-kernel@vger.kernel.org ---- - arch/mips/pci/pci-rt2880.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/arch/mips/pci/pci-rt2880.c -+++ b/arch/mips/pci/pci-rt2880.c -@@ -246,6 +246,8 @@ static int rt288x_pci_probe(struct platf - rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000); - (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0); - -+ rt2880_pci_controller.of_node = pdev->dev.of_node; -+ - register_pci_controller(&rt2880_pci_controller); - return 0; - } diff --git a/target/linux/ramips/patches-5.4/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch b/target/linux/ramips/patches-5.4/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch index 77f2622b9d..fa923f1829 100644 --- a/target/linux/ramips/patches-5.4/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch +++ b/target/linux/ramips/patches-5.4/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch @@ -16,27 +16,27 @@ Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de> --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c -@@ -369,6 +369,8 @@ static unsigned long __init bootmap_byte - return ALIGN(bytes, sizeof(long)); - } - +@@ -285,6 +285,8 @@ static unsigned long __init init_initrd( + * Initialize the bootmem allocator. It also setup initrd related data + * if needed. + */ +static int usermem __initdata; + + #if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA)) + static void __init bootmem_init(void) - { - unsigned long reserved_end; -@@ -442,7 +444,7 @@ static void __init bootmem_init(void) +@@ -323,7 +325,7 @@ static void __init bootmem_init(void) /* * Reserve any memory between the start of RAM and PHYS_OFFSET */ - if (ramstart > PHYS_OFFSET) + if (usermem && ramstart > PHYS_OFFSET) - add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, - BOOT_MEM_RESERVED); + memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET); -@@ -652,8 +654,6 @@ static void __init bootmem_init(void) - * initialization hook for anything else was introduced. - */ + if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) { +@@ -384,8 +386,6 @@ static void __init bootmem_init(void) + + #endif /* CONFIG_SGI_IP27 */ -static int usermem __initdata; - diff --git a/target/linux/ramips/patches-5.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch b/target/linux/ramips/patches-5.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch deleted file mode 100644 index b6f1ce93f4..0000000000 --- a/target/linux/ramips/patches-5.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch +++ /dev/null @@ -1,861 +0,0 @@ -From fec11d4e8dc5cc79bcd7c8fd55038ac21ac39965 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 16 Mar 2014 05:22:39 +0000 -Subject: [PATCH 04/53] MIPS: ralink: add MT7621 pcie driver - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/pci/Makefile | 1 + - arch/mips/pci/pci-mt7621.c | 813 ++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 814 insertions(+) - create mode 100644 arch/mips/pci/pci-mt7621.c - ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -47,6 +47,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops - obj-$(CONFIG_LANTIQ) += fixup-lantiq.o - obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o - obj-$(CONFIG_SOC_MT7620) += pci-mt7620.o -+obj-$(CONFIG_SOC_MT7621) += pci-mt7621.o - obj-$(CONFIG_SOC_RT288X) += pci-rt2880.o - obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o - obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o ---- /dev/null -+++ b/arch/mips/pci/pci-mt7621.c -@@ -0,0 +1,836 @@ -+/************************************************************************** -+ * -+ * BRIEF MODULE DESCRIPTION -+ * PCI init for Ralink RT2880 solution -+ * -+ * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw) -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * -+ ************************************************************************** -+ * May 2007 Bruce Chang -+ * Initial Release -+ * -+ * May 2009 Bruce Chang -+ * support RT2880/RT3883 PCIe -+ * -+ * May 2011 Bruce Chang -+ * support RT6855/MT7620 PCIe -+ * -+ ************************************************************************** -+ */ -+ -+#include <linux/types.h> -+#include <linux/pci.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/version.h> -+#include <asm/pci.h> -+#include <asm/io.h> -+#include <asm/mips-cm.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/of.h> -+#include <linux/of_pci.h> -+#include <linux/of_irq.h> -+#include <linux/platform_device.h> -+ -+#include <ralink_regs.h> -+ -+extern void pcie_phy_init(void); -+extern void chk_phy_pll(void); -+ -+/* -+ * These functions and structures provide the BIOS scan and mapping of the PCI -+ * devices. -+ */ -+ -+#define CONFIG_PCIE_PORT0 -+#define CONFIG_PCIE_PORT1 -+#define CONFIG_PCIE_PORT2 -+#define RALINK_PCIE0_CLK_EN (1<<24) -+#define RALINK_PCIE1_CLK_EN (1<<25) -+#define RALINK_PCIE2_CLK_EN (1<<26) -+ -+#define RALINK_PCI_CONFIG_ADDR 0x20 -+#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24 -+#define RALINK_INT_PCIE0 pcie_irq[0] -+#define RALINK_INT_PCIE1 pcie_irq[1] -+#define RALINK_INT_PCIE2 pcie_irq[2] -+#define RALINK_PCI_MEMBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x0028) -+#define RALINK_PCI_IOBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x002C) -+#define RALINK_PCIE0_RST (1<<24) -+#define RALINK_PCIE1_RST (1<<25) -+#define RALINK_PCIE2_RST (1<<26) -+#define RALINK_SYSCTL_BASE 0xBE000000 -+ -+#define RALINK_PCI_PCICFG_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x0000) -+#define RALINK_PCI_PCIMSK_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x000C) -+#define RALINK_PCI_BASE 0xBE140000 -+ -+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000) -+#define RT6855_PCIE0_OFFSET 0x2000 -+#define RT6855_PCIE1_OFFSET 0x3000 -+#define RT6855_PCIE2_OFFSET 0x4000 -+ -+#define RALINK_PCI0_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010) -+#define RALINK_PCI0_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018) -+#define RALINK_PCI0_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030) -+#define RALINK_PCI0_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034) -+#define RALINK_PCI0_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038) -+#define RALINK_PCI0_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050) -+#define RALINK_PCI0_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060) -+#define RALINK_PCI0_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064) -+ -+#define RALINK_PCI1_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010) -+#define RALINK_PCI1_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018) -+#define RALINK_PCI1_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030) -+#define RALINK_PCI1_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034) -+#define RALINK_PCI1_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038) -+#define RALINK_PCI1_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050) -+#define RALINK_PCI1_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060) -+#define RALINK_PCI1_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064) -+ -+#define RALINK_PCI2_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010) -+#define RALINK_PCI2_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018) -+#define RALINK_PCI2_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030) -+#define RALINK_PCI2_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034) -+#define RALINK_PCI2_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038) -+#define RALINK_PCI2_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050) -+#define RALINK_PCI2_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060) -+#define RALINK_PCI2_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064) -+ -+#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000) -+#define RALINK_PCIEPHY_P2_CTL_OFFSET (RALINK_PCI_BASE + 0xA000) -+ -+ -+#define MV_WRITE(ofs, data) \ -+ *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data) -+#define MV_READ(ofs, data) \ -+ *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) -+#define MV_READ_DATA(ofs) \ -+ le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) -+ -+#define MV_WRITE_16(ofs, data) \ -+ *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data) -+#define MV_READ_16(ofs, data) \ -+ *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs))) -+ -+#define MV_WRITE_8(ofs, data) \ -+ *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data -+#define MV_READ_8(ofs, data) \ -+ *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) -+ -+ -+ -+#define RALINK_PCI_MM_MAP_BASE 0x60000000 -+#define RALINK_PCI_IO_MAP_BASE 0x1e160000 -+ -+#define RALINK_SYSTEM_CONTROL_BASE 0xbe000000 -+#define GPIO_PERST -+#define ASSERT_SYSRST_PCIE(val) do { \ -+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \ -+ RALINK_RSTCTRL |= val; \ -+ else \ -+ RALINK_RSTCTRL &= ~val; \ -+ } while(0) -+#define DEASSERT_SYSRST_PCIE(val) do { \ -+ if (*(unsigned int *)(0xbe00000c) == 0x00030101) \ -+ RALINK_RSTCTRL &= ~val; \ -+ else \ -+ RALINK_RSTCTRL |= val; \ -+ } while(0) -+#define RALINK_SYSCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14) -+#define RALINK_CLKCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30) -+#define RALINK_RSTCTRL *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34) -+#define RALINK_GPIOMODE *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60) -+#define RALINK_PCIE_CLK_GEN *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c) -+#define RALINK_PCIE_CLK_GEN1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80) -+#define PPLL_CFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c) -+#define PPLL_DRV *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0) -+//RALINK_SYSCFG1 bit -+#define RALINK_PCI_HOST_MODE_EN (1<<7) -+#define RALINK_PCIE_RC_MODE_EN (1<<8) -+//RALINK_RSTCTRL bit -+#define RALINK_PCIE_RST (1<<23) -+#define RALINK_PCI_RST (1<<24) -+//RALINK_CLKCFG1 bit -+#define RALINK_PCI_CLK_EN (1<<19) -+#define RALINK_PCIE_CLK_EN (1<<21) -+//RALINK_GPIOMODE bit -+#define PCI_SLOTx2 (1<<11) -+#define PCI_SLOTx1 (2<<11) -+//MTK PCIE PLL bit -+#define PDRV_SW_SET (1<<31) -+#define LC_CKDRVPD_ (1<<19) -+ -+#define MEMORY_BASE 0x0 -+static int pcie_link_status = 0; -+ -+#define PCI_ACCESS_READ_1 0 -+#define PCI_ACCESS_READ_2 1 -+#define PCI_ACCESS_READ_4 2 -+#define PCI_ACCESS_WRITE_1 3 -+#define PCI_ACCESS_WRITE_2 4 -+#define PCI_ACCESS_WRITE_4 5 -+ -+static int pcie_irq[3]; -+ -+static int config_access(unsigned char access_type, struct pci_bus *bus, -+ unsigned int devfn, unsigned int where, u32 * data) -+{ -+ unsigned int slot = PCI_SLOT(devfn); -+ u8 func = PCI_FUNC(devfn); -+ uint32_t address_reg, data_reg; -+ unsigned int address; -+ -+ address_reg = RALINK_PCI_CONFIG_ADDR; -+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; -+ -+ address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000; -+ MV_WRITE(address_reg, address); -+ -+ switch(access_type) { -+ case PCI_ACCESS_WRITE_1: -+ MV_WRITE_8(data_reg+(where&0x3), *data); -+ break; -+ case PCI_ACCESS_WRITE_2: -+ MV_WRITE_16(data_reg+(where&0x3), *data); -+ break; -+ case PCI_ACCESS_WRITE_4: -+ MV_WRITE(data_reg, *data); -+ break; -+ case PCI_ACCESS_READ_1: -+ MV_READ_8( data_reg+(where&0x3), data); -+ break; -+ case PCI_ACCESS_READ_2: -+ MV_READ_16(data_reg+(where&0x3), data); -+ break; -+ case PCI_ACCESS_READ_4: -+ MV_READ(data_reg, data); -+ break; -+ default: -+ printk("no specify access type\n"); -+ break; -+ } -+ return 0; -+} -+ -+static int -+read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val) -+{ -+ return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val); -+} -+ -+static int -+read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val) -+{ -+ return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val); -+} -+ -+static int -+read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val) -+{ -+ return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val); -+} -+ -+static int -+write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) -+{ -+ if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val)) -+ return -1; -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int -+write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val) -+{ -+ if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val)) -+ return -1; -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int -+write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) -+{ -+ if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val)) -+ return -1; -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+ -+static int -+pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) -+{ -+ switch (size) { -+ case 1: -+ return read_config_byte(bus, devfn, where, (u8 *) val); -+ case 2: -+ return read_config_word(bus, devfn, where, (u16 *) val); -+ default: -+ return read_config_dword(bus, devfn, where, val); -+ } -+} -+ -+static int -+pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) -+{ -+ switch (size) { -+ case 1: -+ return write_config_byte(bus, devfn, where, (u8) val); -+ case 2: -+ return write_config_word(bus, devfn, where, (u16) val); -+ default: -+ return write_config_dword(bus, devfn, where, val); -+ } -+} -+ -+struct pci_ops mt7621_pci_ops= { -+ .read = pci_config_read, -+ .write = pci_config_write, -+}; -+ -+static struct resource mt7621_res_pci_mem1 = { -+ .name = "PCI MEM1", -+ .start = RALINK_PCI_MM_MAP_BASE, -+ .end = (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)), -+ .flags = IORESOURCE_MEM, -+}; -+static struct resource mt7621_res_pci_io1 = { -+ .name = "PCI I/O1", -+ .start = RALINK_PCI_IO_MAP_BASE, -+ .end = (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)), -+ .flags = IORESOURCE_IO, -+}; -+ -+static struct pci_controller mt7621_controller = { -+ .pci_ops = &mt7621_pci_ops, -+ .mem_resource = &mt7621_res_pci_mem1, -+ .io_resource = &mt7621_res_pci_io1, -+ .mem_offset = 0x00000000UL, -+ .io_offset = 0x00000000UL, -+ .io_map_base = 0xa0000000, -+}; -+ -+static void -+read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val) -+{ -+ unsigned int address_reg, data_reg, address; -+ -+ address_reg = RALINK_PCI_CONFIG_ADDR; -+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; -+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; -+ MV_WRITE(address_reg, address); -+ MV_READ(data_reg, val); -+ return; -+} -+ -+static void -+write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val) -+{ -+ unsigned int address_reg, data_reg, address; -+ -+ address_reg = RALINK_PCI_CONFIG_ADDR; -+ data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; -+ address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; -+ MV_WRITE(address_reg, address); -+ MV_WRITE(data_reg, val); -+ return; -+} -+ -+ -+int -+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ u16 cmd; -+ u32 val; -+ int irq = 0; -+ -+ if ((dev->bus->number == 0) && (slot == 0)) { -+ write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); -+ read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); -+ printk("BAR0 at slot 0 = %x\n", val); -+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); -+ } else if((dev->bus->number == 0) && (slot == 0x1)) { -+ write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); -+ read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); -+ printk("BAR0 at slot 1 = %x\n", val); -+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); -+ } else if((dev->bus->number == 0) && (slot == 0x2)) { -+ write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); -+ read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); -+ printk("BAR0 at slot 2 = %x\n", val); -+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); -+ } else if ((dev->bus->number == 1) && (slot == 0x0)) { -+ switch (pcie_link_status) { -+ case 2: -+ case 6: -+ irq = RALINK_INT_PCIE1; -+ break; -+ case 4: -+ irq = RALINK_INT_PCIE2; -+ break; -+ default: -+ irq = RALINK_INT_PCIE0; -+ } -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else if ((dev->bus->number == 2) && (slot == 0x0)) { -+ switch (pcie_link_status) { -+ case 5: -+ case 6: -+ irq = RALINK_INT_PCIE2; -+ break; -+ default: -+ irq = RALINK_INT_PCIE1; -+ } -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else if ((dev->bus->number == 2) && (slot == 0x1)) { -+ switch (pcie_link_status) { -+ case 5: -+ case 6: -+ irq = RALINK_INT_PCIE2; -+ break; -+ default: -+ irq = RALINK_INT_PCIE1; -+ } -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else if ((dev->bus->number ==3) && (slot == 0x0)) { -+ irq = RALINK_INT_PCIE2; -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else if ((dev->bus->number ==3) && (slot == 0x1)) { -+ irq = RALINK_INT_PCIE2; -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else if ((dev->bus->number ==3) && (slot == 0x2)) { -+ irq = RALINK_INT_PCIE2; -+ printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); -+ } else { -+ printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); -+ return 0; -+ } -+ -+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14 -+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10 -+ pci_read_config_word(dev, PCI_COMMAND, &cmd); -+ cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; -+ pci_write_config_word(dev, PCI_COMMAND, cmd); -+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); -+ return irq; -+} -+ -+void -+set_pcie_phy(u32 *addr, int start_b, int bits, int val) -+{ -+// printk("0x%p:", addr); -+// printk(" %x", *addr); -+ *(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b); -+ *(unsigned int *)(addr) |= val << start_b; -+// printk(" -> %x\n", *addr); -+} -+ -+void -+bypass_pipe_rst(void) -+{ -+#if defined (CONFIG_PCIE_PORT0) -+ /* PCIe Port 0 */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ /* PCIe Port 1 */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01); // rg_pe1_pipe_rst_b -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ /* PCIe Port 2 */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] -+#endif -+} -+ -+void -+set_phy_for_ssc(void) -+{ -+ unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10)); -+ -+ reg = (reg >> 6) & 0x7; -+#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1) -+ /* Set PCIe Port0 & Port1 PHY to disable SSC */ -+ /* Debug Xtal Type */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 1 enable control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x00); // rg_pe1_phy_en //Port 1 disable -+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) -+ printk("***** Xtal 40MHz *****\n"); -+ } else { // 25MHz | 20MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) -+ if (reg >= 6) { -+ printk("***** Xtal 25MHz *****\n"); -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode) -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial -+ } else { -+ printk("***** Xtal 20MHz *****\n"); -+ } -+ } -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN -+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv -+ } -+ /* Enable PHY and disable force mode */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x01); // rg_pe1_phy_en //Port 1 enable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 1 disable control -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ /* Set PCIe Port2 PHY to disable SSC */ -+ /* Debug Xtal Type */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable -+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) -+ } else { // 25MHz | 20MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) -+ if (reg >= 6) { // 25MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode) -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial -+ } -+ } -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN -+ if(reg <= 5 && reg >= 3) { // 40MHz Xtal -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv -+ } -+ /* Enable PHY and disable force mode */ -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable -+ set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control -+#endif -+} -+ -+void setup_cm_memory_region(struct resource *mem_resource) -+{ -+ resource_size_t mask; -+ if (mips_cps_numiocu(0)) { -+ /* FIXME: hardware doesn't accept mask values with 1s after -+ 0s (e.g. 0xffef), so it would be great to warn if that's -+ about to happen */ -+ mask = ~(mem_resource->end - mem_resource->start); -+ -+ write_gcr_reg1_base(mem_resource->start); -+ write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); -+ printk("PCI coherence region base: 0x%08lx, mask/settings: 0x%08lx\n", -+ read_gcr_reg1_base(), -+ read_gcr_reg1_mask()); -+ } -+} -+ -+static int mt7621_pci_probe(struct platform_device *pdev) -+{ -+ unsigned long val = 0; -+ int i; -+ -+ for (i = 0; i < 3; i++) -+ pcie_irq[i] = irq_of_parse_and_map(pdev->dev.of_node, i); -+ -+ iomem_resource.start = 0; -+ iomem_resource.end= ~0; -+ ioport_resource.start= 0; -+ ioport_resource.end = ~0; -+ -+#if defined (CONFIG_PCIE_PORT0) -+ val = RALINK_PCIE0_RST; -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ val |= RALINK_PCIE1_RST; -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ val |= RALINK_PCIE2_RST; -+#endif -+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST); -+ printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); -+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/ -+ *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3); -+ *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3; -+ mdelay(100); -+ *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3) -+ mdelay(100); -+ *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7); // clear DATA -+ -+ mdelay(100); -+#else -+ *(unsigned int *)(0xbe000060) &= ~0x00000c00; -+#endif -+#if defined (CONFIG_PCIE_PORT0) -+ val = RALINK_PCIE0_RST; -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ val |= RALINK_PCIE1_RST; -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ val |= RALINK_PCIE2_RST; -+#endif -+ DEASSERT_SYSRST_PCIE(val); -+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); -+ -+ if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2 -+ bypass_pipe_rst(); -+ set_phy_for_ssc(); -+ printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); -+ -+#if defined (CONFIG_PCIE_PORT0) -+ read_config(0, 0, 0, 0x70c, &val); -+ printk("Port 0 N_FTS = %x\n", (unsigned int)val); -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ read_config(0, 1, 0, 0x70c, &val); -+ printk("Port 1 N_FTS = %x\n", (unsigned int)val); -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ read_config(0, 2, 0, 0x70c, &val); -+ printk("Port 2 N_FTS = %x\n", (unsigned int)val); -+#endif -+ -+ RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST); -+ RALINK_SYSCFG1 &= ~(0x30); -+ RALINK_SYSCFG1 |= (2<<4); -+ RALINK_PCIE_CLK_GEN &= 0x7fffffff; -+ RALINK_PCIE_CLK_GEN1 &= 0x80ffffff; -+ RALINK_PCIE_CLK_GEN1 |= 0xa << 24; -+ RALINK_PCIE_CLK_GEN |= 0x80000000; -+ mdelay(50); -+ RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST); -+ -+ -+#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/ -+ *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // set DATA -+ mdelay(100); -+#else -+ RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST -+#endif -+ mdelay(500); -+ -+ -+ mdelay(500); -+#if defined (CONFIG_PCIE_PORT0) -+ if(( RALINK_PCI0_STATUS & 0x1) == 0) -+ { -+ printk("PCIE0 no card, disable it(RST&CLK)\n"); -+ ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST); -+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN); -+ pcie_link_status &= ~(1<<0); -+ } else { -+ pcie_link_status |= 1<<0; -+ RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt -+ } -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ if(( RALINK_PCI1_STATUS & 0x1) == 0) -+ { -+ printk("PCIE1 no card, disable it(RST&CLK)\n"); -+ ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST); -+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN); -+ pcie_link_status &= ~(1<<1); -+ } else { -+ pcie_link_status |= 1<<1; -+ RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt -+ } -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ if (( RALINK_PCI2_STATUS & 0x1) == 0) { -+ printk("PCIE2 no card, disable it(RST&CLK)\n"); -+ ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST); -+ RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN); -+ pcie_link_status &= ~(1<<2); -+ } else { -+ pcie_link_status |= 1<<2; -+ RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt -+ } -+#endif -+ if (pcie_link_status == 0) -+ return 0; -+ -+/* -+pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num -+3'b000 x x x -+3'b001 x x 0 -+3'b010 x 0 x -+3'b011 x 1 0 -+3'b100 0 x x -+3'b101 1 x 0 -+3'b110 1 0 x -+3'b111 2 1 0 -+*/ -+ switch(pcie_link_status) { -+ case 2: -+ RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000; -+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0 -+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1 -+ break; -+ case 4: -+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; -+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0 -+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1 -+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 24; //port2 -+ break; -+ case 5: -+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; -+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 16; //port0 -+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1 -+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2 -+ break; -+ case 6: -+ RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; -+ RALINK_PCI_PCICFG_ADDR |= 0x2 << 16; //port0 -+ RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1 -+ RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2 -+ break; -+ } -+ printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR); -+ //printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL); -+ -+/* -+ ioport_resource.start = mt7621_res_pci_io1.start; -+ ioport_resource.end = mt7621_res_pci_io1.end; -+*/ -+ -+ RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE; -+ RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE; -+ -+#if defined (CONFIG_PCIE_PORT0) -+ //PCIe0 -+ if((pcie_link_status & 0x1) != 0) { -+ RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE -+ RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE; -+ RALINK_PCI0_CLASS = 0x06040001; -+ printk("PCIE0 enabled\n"); -+ } -+#endif -+#if defined (CONFIG_PCIE_PORT1) -+ //PCIe1 -+ if ((pcie_link_status & 0x2) != 0) { -+ RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE -+ RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE; -+ RALINK_PCI1_CLASS = 0x06040001; -+ printk("PCIE1 enabled\n"); -+ } -+#endif -+#if defined (CONFIG_PCIE_PORT2) -+ //PCIe2 -+ if ((pcie_link_status & 0x4) != 0) { -+ RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE -+ RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE; -+ RALINK_PCI2_CLASS = 0x06040001; -+ printk("PCIE2 enabled\n"); -+ } -+#endif -+ -+ -+ switch(pcie_link_status) { -+ case 7: -+ read_config(0, 2, 0, 0x4, &val); -+ write_config(0, 2, 0, 0x4, val|0x4); -+ // write_config(0, 1, 0, 0x4, val|0x7); -+ read_config(0, 2, 0, 0x70c, &val); -+ val &= ~(0xff)<<8; -+ val |= 0x50<<8; -+ write_config(0, 2, 0, 0x70c, val); -+ case 3: -+ case 5: -+ case 6: -+ read_config(0, 1, 0, 0x4, &val); -+ write_config(0, 1, 0, 0x4, val|0x4); -+ // write_config(0, 1, 0, 0x4, val|0x7); -+ read_config(0, 1, 0, 0x70c, &val); -+ val &= ~(0xff)<<8; -+ val |= 0x50<<8; -+ write_config(0, 1, 0, 0x70c, val); -+ default: -+ read_config(0, 0, 0, 0x4, &val); -+ write_config(0, 0, 0, 0x4, val|0x4); //bus master enable -+ // write_config(0, 0, 0, 0x4, val|0x7); //bus master enable -+ read_config(0, 0, 0, 0x70c, &val); -+ val &= ~(0xff)<<8; -+ val |= 0x50<<8; -+ write_config(0, 0, 0, 0x70c, val); -+ } -+ -+ pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node); -+ setup_cm_memory_region(mt7621_controller.mem_resource); -+ register_pci_controller(&mt7621_controller); -+ return 0; -+ -+} -+ -+int pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ return 0; -+} -+ -+static const struct of_device_id mt7621_pci_ids[] = { -+ { .compatible = "mediatek,mt7621-pci" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mt7621_pci_ids); -+ -+static struct platform_driver mt7621_pci_driver = { -+ .probe = mt7621_pci_probe, -+ .driver = { -+ .name = "mt7621-pci", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(mt7621_pci_ids), -+ }, -+}; -+ -+static int __init mt7621_pci_init(void) -+{ -+ return platform_driver_register(&mt7621_pci_driver); -+} -+ -+arch_initcall(mt7621_pci_init); diff --git a/target/linux/ramips/patches-5.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch b/target/linux/ramips/patches-5.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch index 90215fbf86..a3b8e4d250 100644 --- a/target/linux/ramips/patches-5.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch +++ b/target/linux/ramips/patches-5.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch @@ -179,7 +179,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + /* register clock event */ systick.dev.irq = irq_of_parse_and_map(np, 0); if (!systick.dev.irq) { - pr_err("%s: request_irq failed", np->name); + pr_err("%pOFn: request_irq failed", np); return -EINVAL; } @@ -196,5 +196,5 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + systick.dev.cpumask = cpumask_of(0); + clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff); - pr_info("%s: running - mult: %d, shift: %d\n", - np->name, systick.dev.mult, systick.dev.shift); + pr_info("%pOFn: running - mult: %d, shift: %d\n", + np, systick.dev.mult, systick.dev.shift); diff --git a/target/linux/ramips/patches-5.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-5.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch index c05ee8018d..54af571d85 100644 --- a/target/linux/ramips/patches-5.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch +++ b/target/linux/ramips/patches-5.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -82,6 +82,8 @@ void __init plat_mem_setup(void) +@@ -80,6 +80,8 @@ void __init plat_mem_setup(void) __dt_setup_arch(dtb); diff --git a/target/linux/ramips/patches-5.4/0009-PCI-MIPS-enable-PCIe-on-MT7688.patch b/target/linux/ramips/patches-5.4/0009-PCI-MIPS-enable-PCIe-on-MT7688.patch deleted file mode 100644 index 6ca15fe32e..0000000000 --- a/target/linux/ramips/patches-5.4/0009-PCI-MIPS-enable-PCIe-on-MT7688.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7768798964eb0e4f95eaecffb93b5d0ca28a38af Mon Sep 17 00:00:00 2001 -From: Daniel Golle <daniel@makrotopia.org> -Date: Sat, 3 Jun 2017 20:00:03 +0200 -Subject: [PATCH] MIPS: pci-mt7620: enabled PCIe on MT7688 -To: linux-mips@linux-mips.org, - John Crispin <john@phrozen.org> -Cc: Wei Yongjun <yongjun_wei@trendmicro.com.cn>, - Ralf Baechle <ralf@linux-mips.org>, - linux-mediatek@lists.infradead.org - -Use PCIe support for MT7628AN also on MT7688. -Tested on WRTNODE2R. - -Signed-off-by: Daniel Golle <daniel@makrotopia.org> ---- - arch/mips/pci/pci-mt7620.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/arch/mips/pci/pci-mt7620.c -+++ b/arch/mips/pci/pci-mt7620.c -@@ -316,6 +316,7 @@ static int mt7620_pci_probe(struct platf - break; - - case MT762X_SOC_MT7628AN: -+ case MT762X_SOC_MT7688: - if (mt7628_pci_hw_init(pdev)) - return -1; - break; diff --git a/target/linux/ramips/patches-5.4/0013-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-5.4/0013-owrt-hack-fix-mt7688-cache-issue.patch index 442f3180a3..75c93c7e50 100644 --- a/target/linux/ramips/patches-5.4/0013-owrt-hack-fix-mt7688-cache-issue.patch +++ b/target/linux/ramips/patches-5.4/0013-owrt-hack-fix-mt7688-cache-issue.patch @@ -10,15 +10,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c -@@ -910,7 +910,6 @@ static void __init arch_mem_init(char ** - crashk_res.end - crashk_res.start + 1, - BOOTMEM_DEFAULT); +@@ -652,7 +652,6 @@ static void __init arch_mem_init(char ** + memblock_reserve(crashk_res.start, + crashk_res.end - crashk_res.start + 1); #endif - device_tree_init(); sparse_init(); plat_swiotlb_setup(); -@@ -1026,6 +1025,7 @@ void __init setup_arch(char **cmdline_p) +@@ -760,6 +759,7 @@ void __init setup_arch(char **cmdline_p) cpu_cache_init(); paging_init(); diff --git a/target/linux/ramips/patches-5.4/0024-GPIO-add-named-gpio-exports.patch b/target/linux/ramips/patches-5.4/0024-GPIO-add-named-gpio-exports.patch index 61ed9ea784..d4ea379159 100644 --- a/target/linux/ramips/patches-5.4/0024-GPIO-add-named-gpio-exports.patch +++ b/target/linux/ramips/patches-5.4/0024-GPIO-add-named-gpio-exports.patch @@ -13,7 +13,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c -@@ -23,6 +23,8 @@ +@@ -19,6 +19,8 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> #include <linux/gpio/machine.h> @@ -21,9 +21,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +#include <linux/platform_device.h> #include "gpiolib.h" - -@@ -513,3 +515,68 @@ void of_gpiochip_remove(struct gpio_chip - gpiochip_remove_pin_ranges(chip); + #include "gpiolib-of.h" +@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip + { of_node_put(chip->of_node); } + @@ -93,7 +93,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +module_platform_driver(gpio_export_driver); --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c -@@ -553,7 +553,7 @@ static struct class gpio_class = { +@@ -563,7 +563,7 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ @@ -102,7 +102,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> { struct gpio_chip *chip; struct gpio_device *gdev; -@@ -615,6 +615,8 @@ int gpiod_export(struct gpio_desc *desc, +@@ -625,6 +625,8 @@ int gpiod_export(struct gpio_desc *desc, offset = gpio_chip_hwgpio(desc); if (chip->names && chip->names[offset]) ioname = chip->names[offset]; @@ -111,7 +111,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, -@@ -636,6 +638,12 @@ err_unlock: +@@ -646,6 +648,12 @@ err_unlock: gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -141,7 +141,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> { --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h -@@ -451,6 +451,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_ +@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) @@ -149,7 +149,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> int gpiod_export(struct gpio_desc *desc, bool direction_may_change); int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); -@@ -458,6 +459,13 @@ void gpiod_unexport(struct gpio_desc *de +@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ diff --git a/target/linux/ramips/patches-5.4/0025-pinctrl-ralink-add-pinctrl-driver.patch b/target/linux/ramips/patches-5.4/0025-pinctrl-ralink-add-pinctrl-driver.patch deleted file mode 100644 index a374e01b59..0000000000 --- a/target/linux/ramips/patches-5.4/0025-pinctrl-ralink-add-pinctrl-driver.patch +++ /dev/null @@ -1,524 +0,0 @@ -From 7adbe9a88c33c6e362a10b109d963b5500a21f00 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 27 Jul 2014 09:34:05 +0100 -Subject: [PATCH 25/53] pinctrl: ralink: add pinctrl driver - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/Kconfig | 2 + - drivers/pinctrl/Kconfig | 5 + - drivers/pinctrl/Makefile | 1 + - drivers/pinctrl/pinctrl-rt2880.c | 474 ++++++++++++++++++++++++++++++++++++++ - 4 files changed, 482 insertions(+) - create mode 100644 drivers/pinctrl/pinctrl-rt2880.c - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -629,6 +629,8 @@ config RALINK - select CLKDEV_LOOKUP - select ARCH_HAS_RESET_CONTROLLER - select RESET_CONTROLLER -+ select PINCTRL -+ select PINCTRL_RT2880 - - config SGI_IP22 - bool "SGI IP22 (Indy/Indigo2)" ---- a/drivers/pinctrl/Kconfig -+++ b/drivers/pinctrl/Kconfig -@@ -143,6 +143,11 @@ config PINCTRL_LPC18XX - help - Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU). - -+config PINCTRL_RT2880 -+ bool -+ depends on RALINK -+ select PINMUX -+ - config PINCTRL_FALCON - bool - depends on SOC_FALCON ---- a/drivers/pinctrl/Makefile -+++ b/drivers/pinctrl/Makefile -@@ -28,6 +28,7 @@ obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl- - obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-pic32.o - obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o - obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o -+obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o - obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o - obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o - obj-$(CONFIG_PINCTRL_SIRF) += sirf/ ---- /dev/null -+++ b/drivers/pinctrl/pinctrl-rt2880.c -@@ -0,0 +1,472 @@ -+/* -+ * linux/drivers/pinctrl/pinctrl-rt2880.c -+ * -+ * 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 -+ * publishhed by the Free Software Foundation. -+ * -+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/io.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/of.h> -+#include <linux/pinctrl/pinctrl.h> -+#include <linux/pinctrl/pinconf.h> -+#include <linux/pinctrl/pinmux.h> -+#include <linux/pinctrl/consumer.h> -+#include <linux/pinctrl/machine.h> -+ -+#include <asm/mach-ralink/ralink_regs.h> -+#include <asm/mach-ralink/pinmux.h> -+#include <asm/mach-ralink/mt7620.h> -+ -+#include "core.h" -+ -+#define SYSC_REG_GPIO_MODE 0x60 -+#define SYSC_REG_GPIO_MODE2 0x64 -+ -+struct rt2880_priv { -+ struct device *dev; -+ -+ struct pinctrl_pin_desc *pads; -+ struct pinctrl_desc *desc; -+ -+ struct rt2880_pmx_func **func; -+ int func_count; -+ -+ struct rt2880_pmx_group *groups; -+ const char **group_names; -+ int group_count; -+ -+ uint8_t *gpio; -+ int max_pins; -+}; -+ -+static int rt2880_get_group_count(struct pinctrl_dev *pctrldev) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ return p->group_count; -+} -+ -+static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev, -+ unsigned group) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ if (group >= p->group_count) -+ return NULL; -+ -+ return p->group_names[group]; -+} -+ -+static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev, -+ unsigned group, -+ const unsigned **pins, -+ unsigned *num_pins) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ if (group >= p->group_count) -+ return -EINVAL; -+ -+ *pins = p->groups[group].func[0].pins; -+ *num_pins = p->groups[group].func[0].pin_count; -+ -+ return 0; -+} -+ -+static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev, -+ struct pinctrl_map *map, unsigned num_maps) -+{ -+ int i; -+ -+ for (i = 0; i < num_maps; i++) -+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN || -+ map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) -+ kfree(map[i].data.configs.configs); -+ kfree(map); -+} -+ -+static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev, -+ struct seq_file *s, -+ unsigned offset) -+{ -+ seq_printf(s, "ralink pio"); -+} -+ -+static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev, -+ struct device_node *np, -+ struct pinctrl_map **map) -+{ -+ const char *function; -+ int func = of_property_read_string(np, "ralink,function", &function); -+ int grps = of_property_count_strings(np, "ralink,group"); -+ int i; -+ -+ if (func || !grps) -+ return; -+ -+ for (i = 0; i < grps; i++) { -+ const char *group; -+ -+ of_property_read_string_index(np, "ralink,group", i, &group); -+ -+ (*map)->type = PIN_MAP_TYPE_MUX_GROUP; -+ (*map)->name = function; -+ (*map)->data.mux.group = group; -+ (*map)->data.mux.function = function; -+ (*map)++; -+ } -+} -+ -+static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev, -+ struct device_node *np_config, -+ struct pinctrl_map **map, -+ unsigned *num_maps) -+{ -+ int max_maps = 0; -+ struct pinctrl_map *tmp; -+ struct device_node *np; -+ -+ for_each_child_of_node(np_config, np) { -+ int ret = of_property_count_strings(np, "ralink,group"); -+ -+ if (ret >= 0) -+ max_maps += ret; -+ } -+ -+ if (!max_maps) -+ return -EINVAL; -+ -+ *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL); -+ if (!*map) -+ return -ENOMEM; -+ -+ tmp = *map; -+ -+ for_each_child_of_node(np_config, np) -+ rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp); -+ *num_maps = max_maps; -+ -+ return 0; -+} -+ -+static const struct pinctrl_ops rt2880_pctrl_ops = { -+ .get_groups_count = rt2880_get_group_count, -+ .get_group_name = rt2880_get_group_name, -+ .get_group_pins = rt2880_get_group_pins, -+ .pin_dbg_show = rt2880_pinctrl_pin_dbg_show, -+ .dt_node_to_map = rt2880_pinctrl_dt_node_to_map, -+ .dt_free_map = rt2880_pinctrl_dt_free_map, -+}; -+ -+static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ return p->func_count; -+} -+ -+static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev, -+ unsigned func) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ return p->func[func]->name; -+} -+ -+static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev, -+ unsigned func, -+ const char * const **groups, -+ unsigned * const num_groups) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ if (p->func[func]->group_count == 1) -+ *groups = &p->group_names[p->func[func]->groups[0]]; -+ else -+ *groups = p->group_names; -+ -+ *num_groups = p->func[func]->group_count; -+ -+ return 0; -+} -+ -+static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev, -+ unsigned func, -+ unsigned group) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ u32 mode = 0; -+ u32 reg = SYSC_REG_GPIO_MODE; -+ int i; -+ int shift; -+ -+ /* dont allow double use */ -+ if (p->groups[group].enabled) { -+ dev_err(p->dev, "%s is already enabled\n", p->groups[group].name); -+ return -EBUSY; -+ } -+ -+ p->groups[group].enabled = 1; -+ p->func[func]->enabled = 1; -+ -+ shift = p->groups[group].shift; -+ if (shift >= 32) { -+ shift -= 32; -+ reg = SYSC_REG_GPIO_MODE2; -+ } -+ mode = rt_sysc_r32(reg); -+ mode &= ~(p->groups[group].mask << shift); -+ -+ /* mark the pins as gpio */ -+ for (i = 0; i < p->groups[group].func[0].pin_count; i++) -+ p->gpio[p->groups[group].func[0].pins[i]] = 1; -+ -+ /* function 0 is gpio and needs special handling */ -+ if (func == 0) { -+ mode |= p->groups[group].gpio << shift; -+ } else { -+ for (i = 0; i < p->func[func]->pin_count; i++) -+ p->gpio[p->func[func]->pins[i]] = 0; -+ mode |= p->func[func]->value << shift; -+ } -+ rt_sysc_w32(mode, reg); -+ -+ return 0; -+} -+ -+static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, -+ struct pinctrl_gpio_range *range, -+ unsigned pin) -+{ -+ struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); -+ -+ if (!p->gpio[pin]) { -+ dev_err(p->dev, "pin %d is not set to gpio mux\n", pin); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct pinmux_ops rt2880_pmx_group_ops = { -+ .get_functions_count = rt2880_pmx_func_count, -+ .get_function_name = rt2880_pmx_func_name, -+ .get_function_groups = rt2880_pmx_group_get_groups, -+ .set_mux = rt2880_pmx_group_enable, -+ .gpio_request_enable = rt2880_pmx_group_gpio_request_enable, -+}; -+ -+static struct pinctrl_desc rt2880_pctrl_desc = { -+ .owner = THIS_MODULE, -+ .name = "rt2880-pinmux", -+ .pctlops = &rt2880_pctrl_ops, -+ .pmxops = &rt2880_pmx_group_ops, -+}; -+ -+static struct rt2880_pmx_func gpio_func = { -+ .name = "gpio", -+}; -+ -+static int rt2880_pinmux_index(struct rt2880_priv *p) -+{ -+ struct rt2880_pmx_func **f; -+ struct rt2880_pmx_group *mux = p->groups; -+ int i, j, c = 0; -+ -+ /* count the mux functions */ -+ while (mux->name) { -+ p->group_count++; -+ mux++; -+ } -+ -+ /* allocate the group names array needed by the gpio function */ -+ p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL); -+ if (!p->group_names) -+ return -1; -+ -+ for (i = 0; i < p->group_count; i++) { -+ p->group_names[i] = p->groups[i].name; -+ p->func_count += p->groups[i].func_count; -+ } -+ -+ /* we have a dummy function[0] for gpio */ -+ p->func_count++; -+ -+ /* allocate our function and group mapping index buffers */ -+ f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL); -+ gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL); -+ if (!f || !gpio_func.groups) -+ return -1; -+ -+ /* add a backpointer to the function so it knows its group */ -+ gpio_func.group_count = p->group_count; -+ for (i = 0; i < gpio_func.group_count; i++) -+ gpio_func.groups[i] = i; -+ -+ f[c] = &gpio_func; -+ c++; -+ -+ /* add remaining functions */ -+ for (i = 0; i < p->group_count; i++) { -+ for (j = 0; j < p->groups[i].func_count; j++) { -+ f[c] = &p->groups[i].func[j]; -+ f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL); -+ f[c]->groups[0] = i; -+ f[c]->group_count = 1; -+ c++; -+ } -+ } -+ return 0; -+} -+ -+static int rt2880_pinmux_pins(struct rt2880_priv *p) -+{ -+ int i, j; -+ -+ /* loop over the functions and initialize the pins array. also work out the highest pin used */ -+ for (i = 0; i < p->func_count; i++) { -+ int pin; -+ -+ if (!p->func[i]->pin_count) -+ continue; -+ -+ p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL); -+ for (j = 0; j < p->func[i]->pin_count; j++) -+ p->func[i]->pins[j] = p->func[i]->pin_first + j; -+ -+ pin = p->func[i]->pin_first + p->func[i]->pin_count; -+ if (pin > p->max_pins) -+ p->max_pins = pin; -+ } -+ -+ /* the buffer that tells us which pins are gpio */ -+ p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins, -+ GFP_KERNEL); -+ /* the pads needed to tell pinctrl about our pins */ -+ p->pads = devm_kzalloc(p->dev, -+ sizeof(struct pinctrl_pin_desc) * p->max_pins, -+ GFP_KERNEL); -+ if (!p->pads || !p->gpio ) { -+ dev_err(p->dev, "Failed to allocate gpio data\n"); -+ return -ENOMEM; -+ } -+ -+ memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins); -+ for (i = 0; i < p->func_count; i++) { -+ if (!p->func[i]->pin_count) -+ continue; -+ -+ for (j = 0; j < p->func[i]->pin_count; j++) -+ p->gpio[p->func[i]->pins[j]] = 0; -+ } -+ -+ /* pin 0 is always a gpio */ -+ p->gpio[0] = 1; -+ -+ /* set the pads */ -+ for (i = 0; i < p->max_pins; i++) { -+ /* strlen("ioXY") + 1 = 5 */ -+ char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL); -+ -+ if (!name) { -+ dev_err(p->dev, "Failed to allocate pad name\n"); -+ return -ENOMEM; -+ } -+ snprintf(name, 5, "io%d", i); -+ p->pads[i].number = i; -+ p->pads[i].name = name; -+ } -+ p->desc->pins = p->pads; -+ p->desc->npins = p->max_pins; -+ -+ return 0; -+} -+ -+static int rt2880_pinmux_probe(struct platform_device *pdev) -+{ -+ struct rt2880_priv *p; -+ struct pinctrl_dev *dev; -+ struct device_node *np; -+ -+ if (!rt2880_pinmux_data) -+ return -ENOSYS; -+ -+ /* setup the private data */ -+ p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL); -+ if (!p) -+ return -ENOMEM; -+ -+ p->dev = &pdev->dev; -+ p->desc = &rt2880_pctrl_desc; -+ p->groups = rt2880_pinmux_data; -+ platform_set_drvdata(pdev, p); -+ -+ /* init the device */ -+ if (rt2880_pinmux_index(p)) { -+ dev_err(&pdev->dev, "failed to load index\n"); -+ return -EINVAL; -+ } -+ if (rt2880_pinmux_pins(p)) { -+ dev_err(&pdev->dev, "failed to load pins\n"); -+ return -EINVAL; -+ } -+ dev = pinctrl_register(p->desc, &pdev->dev, p); -+ if (IS_ERR(dev)) -+ return PTR_ERR(dev); -+ -+ /* finalize by adding gpio ranges for enables gpio controllers */ -+ for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") { -+ const __be32 *ngpio, *gpiobase; -+ struct pinctrl_gpio_range *range; -+ char *name; -+ -+ if (!of_device_is_available(np)) -+ continue; -+ -+ ngpio = of_get_property(np, "ralink,nr-gpio", NULL); -+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL); -+ if (!ngpio || !gpiobase) { -+ dev_err(&pdev->dev, "failed to load chip info\n"); -+ return -EINVAL; -+ } -+ -+ range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL); -+ range->name = name = (char *) &range[1]; -+ sprintf(name, "pio"); -+ range->npins = __be32_to_cpu(*ngpio); -+ range->base = __be32_to_cpu(*gpiobase); -+ range->pin_base = range->base; -+ pinctrl_add_gpio_range(dev, range); -+ } -+ -+ return 0; -+} -+ -+static const struct of_device_id rt2880_pinmux_match[] = { -+ { .compatible = "ralink,rt2880-pinmux" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, rt2880_pinmux_match); -+ -+static struct platform_driver rt2880_pinmux_driver = { -+ .probe = rt2880_pinmux_probe, -+ .driver = { -+ .name = "rt2880-pinmux", -+ .owner = THIS_MODULE, -+ .of_match_table = rt2880_pinmux_match, -+ }, -+}; -+ -+int __init rt2880_pinmux_init(void) -+{ -+ return platform_driver_register(&rt2880_pinmux_driver); -+} -+ -+core_initcall_sync(rt2880_pinmux_init); diff --git a/target/linux/ramips/patches-5.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch b/target/linux/ramips/patches-5.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch index eaae0d3d02..3d78ef40c6 100644 --- a/target/linux/ramips/patches-5.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch +++ b/target/linux/ramips/patches-5.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch @@ -47,9 +47,9 @@ Cc: linux-gpio@vger.kernel.org +#endif /* __ASM_MACH_RALINK_GPIO_H */ --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig -@@ -398,6 +398,12 @@ config GPIO_REG - A 32-bit single register GPIO fixed in/out implementation. This - can be used to represent any register as a set of GPIO signals. +@@ -471,6 +471,12 @@ config GPIO_SNPS_CREG + where only several fields in register belong to GPIO lines and + each GPIO line owns a field with different length and on/off value. +config GPIO_RALINK + bool "Ralink GPIO Support" @@ -62,17 +62,17 @@ Cc: linux-gpio@vger.kernel.org depends on PLAT_SPEAR --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile -@@ -98,6 +98,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-p - obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o - obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o - obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o -+obj-$(CONFIG_GPIO_RALINK) += gpio-ralink.o - obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o - obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o - obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o +@@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_PISOSR) += gpio-pisos + obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o + obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o + obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o ++obj-$(CONFIG_GPIO_RALINK) += gpio-ralink.o + obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o + obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o + obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o --- /dev/null +++ b/drivers/gpio/gpio-ralink.c -@@ -0,0 +1,355 @@ +@@ -0,0 +1,341 @@ +/* + * 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 @@ -328,20 +328,6 @@ Cc: linux-gpio@vger.kernel.org + dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio); +} + -+static int ralink_gpio_request(struct gpio_chip *chip, unsigned offset) -+{ -+ int gpio = chip->base + offset; -+ -+ return pinctrl_request_gpio(gpio); -+} -+ -+static void ralink_gpio_free(struct gpio_chip *chip, unsigned offset) -+{ -+ int gpio = chip->base + offset; -+ -+ pinctrl_free_gpio(gpio); -+} -+ +static int ralink_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; @@ -393,9 +379,9 @@ Cc: linux-gpio@vger.kernel.org + rg->chip.direction_output = ralink_gpio_direction_output; + rg->chip.get = ralink_gpio_get; + rg->chip.set = ralink_gpio_set; -+ rg->chip.request = ralink_gpio_request; ++ rg->chip.request = gpiochip_generic_request; + rg->chip.to_irq = ralink_gpio_to_irq; -+ rg->chip.free = ralink_gpio_free; ++ rg->chip.free = gpiochip_generic_free; + + /* set polarity to low for all lines */ + rt_gpio_w32(rg, GPIO_REG_POL, 0); diff --git a/target/linux/ramips/patches-5.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch b/target/linux/ramips/patches-5.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch deleted file mode 100644 index debeae2806..0000000000 --- a/target/linux/ramips/patches-5.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch +++ /dev/null @@ -1,405 +0,0 @@ -From 61ac7d9b4228de8c332900902c2b93189b042eab Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 27 Jul 2014 11:00:32 +0100 -Subject: [PATCH 28/53] GPIO: ralink: add mt7621 gpio controller - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - arch/mips/Kconfig | 3 + - drivers/gpio/Kconfig | 6 + - drivers/gpio/Makefile | 1 + - drivers/gpio/gpio-mt7621.c | 354 ++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 364 insertions(+) - create mode 100644 drivers/gpio/gpio-mt7621.c - ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -631,6 +631,9 @@ config RALINK - select RESET_CONTROLLER - select PINCTRL - select PINCTRL_RT2880 -+ select ARCH_HAS_RESET_CONTROLLER -+ select RESET_CONTROLLER -+ select ARCH_REQUIRE_GPIOLIB - - config SGI_IP22 - bool "SGI IP22 (Indy/Indigo2)" ---- a/drivers/gpio/Kconfig -+++ b/drivers/gpio/Kconfig -@@ -298,6 +298,12 @@ config GPIO_MENZ127 - help - Say yes here to support the MEN 16Z127 GPIO Controller - -+config GPIO_MT7621 -+ bool "Mediatek GPIO Support" -+ depends on SOC_MT7620 || SOC_MT7621 -+ help -+ Say yes here to support the Mediatek SoC GPIO device -+ - config GPIO_MM_LANTIQ - bool "Lantiq Memory mapped GPIOs" - depends on LANTIQ && SOC_XWAY ---- a/drivers/gpio/Makefile -+++ b/drivers/gpio/Makefile -@@ -152,3 +152,4 @@ obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o - obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o - obj-$(CONFIG_GPIO_ZX) += gpio-zx.o - obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o -+obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o ---- /dev/null -+++ b/drivers/gpio/gpio-mt7621.c -@@ -0,0 +1,354 @@ -+/* -+ * 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. -+ * -+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> -+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/io.h> -+#include <linux/err.h> -+#include <linux/gpio.h> -+#include <linux/module.h> -+#include <linux/of_irq.h> -+#include <linux/spinlock.h> -+#include <linux/irqdomain.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+ -+#define MTK_MAX_BANK 3 -+#define MTK_BANK_WIDTH 32 -+ -+enum mediatek_gpio_reg { -+ GPIO_REG_CTRL = 0, -+ GPIO_REG_POL, -+ GPIO_REG_DATA, -+ GPIO_REG_DSET, -+ GPIO_REG_DCLR, -+ GPIO_REG_REDGE, -+ GPIO_REG_FEDGE, -+ GPIO_REG_HLVL, -+ GPIO_REG_LLVL, -+ GPIO_REG_STAT, -+ GPIO_REG_EDGE, -+}; -+ -+static void __iomem *mediatek_gpio_membase; -+static int mediatek_gpio_irq; -+static struct irq_domain *mediatek_gpio_irq_domain; -+static atomic_t irq_refcount = ATOMIC_INIT(0); -+ -+struct mtk_gc { -+ struct gpio_chip chip; -+ spinlock_t lock; -+ int bank; -+ u32 rising; -+ u32 falling; -+} *gc_map[MTK_MAX_BANK]; -+ -+static inline struct mtk_gc -+*to_mediatek_gpio(struct gpio_chip *chip) -+{ -+ struct mtk_gc *mgc; -+ -+ mgc = container_of(chip, struct mtk_gc, chip); -+ -+ return mgc; -+} -+ -+static inline void -+mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val) -+{ -+ iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); -+} -+ -+static inline u32 -+mtk_gpio_r32(struct mtk_gc *rg, u8 reg) -+{ -+ return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); -+} -+ -+static void -+mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ -+ mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset)); -+} -+ -+static int -+mediatek_gpio_get(struct gpio_chip *chip, unsigned offset) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ -+ return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset)); -+} -+ -+static int -+mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ unsigned long flags; -+ u32 t; -+ -+ spin_lock_irqsave(&rg->lock, flags); -+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL); -+ t &= ~BIT(offset); -+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t); -+ spin_unlock_irqrestore(&rg->lock, flags); -+ -+ return 0; -+} -+ -+static int -+mediatek_gpio_direction_output(struct gpio_chip *chip, -+ unsigned offset, int value) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ unsigned long flags; -+ u32 t; -+ -+ spin_lock_irqsave(&rg->lock, flags); -+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL); -+ t |= BIT(offset); -+ mtk_gpio_w32(rg, GPIO_REG_CTRL, t); -+ mediatek_gpio_set(chip, offset, value); -+ spin_unlock_irqrestore(&rg->lock, flags); -+ -+ return 0; -+} -+ -+static int -+mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ unsigned long flags; -+ u32 t; -+ -+ spin_lock_irqsave(&rg->lock, flags); -+ t = mtk_gpio_r32(rg, GPIO_REG_CTRL); -+ spin_unlock_irqrestore(&rg->lock, flags); -+ -+ if (t & BIT(offset)) -+ return 0; -+ -+ return 1; -+} -+ -+static int -+mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin) -+{ -+ struct mtk_gc *rg = to_mediatek_gpio(chip); -+ -+ return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH)); -+} -+ -+static int -+mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank) -+{ -+ const __be32 *id = of_get_property(bank, "reg", NULL); -+ struct mtk_gc *rg = devm_kzalloc(&pdev->dev, -+ sizeof(struct mtk_gc), GFP_KERNEL); -+ -+ if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK) -+ return -ENOMEM; -+ -+ gc_map[be32_to_cpu(*id)] = rg; -+ -+ memset(rg, 0, sizeof(struct mtk_gc)); -+ -+ spin_lock_init(&rg->lock); -+ -+ rg->chip.parent = &pdev->dev; -+ rg->chip.label = dev_name(&pdev->dev); -+ rg->chip.of_node = bank; -+ rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id); -+ rg->chip.ngpio = MTK_BANK_WIDTH; -+ rg->chip.direction_input = mediatek_gpio_direction_input; -+ rg->chip.direction_output = mediatek_gpio_direction_output; -+ rg->chip.get_direction = mediatek_gpio_get_direction; -+ rg->chip.get = mediatek_gpio_get; -+ rg->chip.set = mediatek_gpio_set; -+ if (mediatek_gpio_irq_domain) -+ rg->chip.to_irq = mediatek_gpio_to_irq; -+ rg->bank = be32_to_cpu(*id); -+ -+ /* set polarity to low for all gpios */ -+ mtk_gpio_w32(rg, GPIO_REG_POL, 0); -+ -+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); -+ -+ return gpiochip_add(&rg->chip); -+} -+ -+static void -+mediatek_gpio_irq_handler(struct irq_desc *desc) -+{ -+ int i; -+ -+ for (i = 0; i < MTK_MAX_BANK; i++) { -+ struct mtk_gc *rg = gc_map[i]; -+ unsigned long pending; -+ int bit; -+ -+ if (!rg) -+ continue; -+ -+ pending = mtk_gpio_r32(rg, GPIO_REG_STAT); -+ -+ for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { -+ u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit); -+ -+ generic_handle_irq(map); -+ mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); -+ } -+ } -+} -+ -+static void -+mediatek_gpio_irq_unmask(struct irq_data *d) -+{ -+ int pin = d->hwirq; -+ int bank = pin / 32; -+ struct mtk_gc *rg = gc_map[bank]; -+ unsigned long flags; -+ u32 rise, fall; -+ -+ if (!rg) -+ return; -+ -+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); -+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); -+ -+ spin_lock_irqsave(&rg->lock, flags); -+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising)); -+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling)); -+ spin_unlock_irqrestore(&rg->lock, flags); -+} -+ -+static void -+mediatek_gpio_irq_mask(struct irq_data *d) -+{ -+ int pin = d->hwirq; -+ int bank = pin / 32; -+ struct mtk_gc *rg = gc_map[bank]; -+ unsigned long flags; -+ u32 rise, fall; -+ -+ if (!rg) -+ return; -+ -+ rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); -+ fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); -+ -+ spin_lock_irqsave(&rg->lock, flags); -+ mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq)); -+ mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq)); -+ spin_unlock_irqrestore(&rg->lock, flags); -+} -+ -+static int -+mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) -+{ -+ int pin = d->hwirq; -+ int bank = pin / 32; -+ struct mtk_gc *rg = gc_map[bank]; -+ u32 mask = BIT(d->hwirq); -+ -+ if (!rg) -+ return -1; -+ -+ if (type == IRQ_TYPE_PROBE) { -+ if ((rg->rising | rg->falling) & mask) -+ return 0; -+ -+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; -+ } -+ -+ if (type & IRQ_TYPE_EDGE_RISING) -+ rg->rising |= mask; -+ else -+ rg->rising &= ~mask; -+ -+ if (type & IRQ_TYPE_EDGE_FALLING) -+ rg->falling |= mask; -+ else -+ rg->falling &= ~mask; -+ -+ return 0; -+} -+ -+static struct irq_chip mediatek_gpio_irq_chip = { -+ .name = "GPIO", -+ .irq_unmask = mediatek_gpio_irq_unmask, -+ .irq_mask = mediatek_gpio_irq_mask, -+ .irq_mask_ack = mediatek_gpio_irq_mask, -+ .irq_set_type = mediatek_gpio_irq_type, -+}; -+ -+static int -+mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) -+{ -+ irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq); -+ irq_set_handler_data(irq, d); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops irq_domain_ops = { -+ .xlate = irq_domain_xlate_onecell, -+ .map = mediatek_gpio_gpio_map, -+}; -+ -+static int -+mediatek_gpio_probe(struct platform_device *pdev) -+{ -+ struct device_node *bank, *np = pdev->dev.of_node; -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ -+ mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(mediatek_gpio_membase)) -+ return PTR_ERR(mediatek_gpio_membase); -+ -+ mediatek_gpio_irq = irq_of_parse_and_map(np, 0); -+ if (mediatek_gpio_irq) { -+ mediatek_gpio_irq_domain = irq_domain_add_linear(np, -+ MTK_MAX_BANK * MTK_BANK_WIDTH, -+ &irq_domain_ops, NULL); -+ if (!mediatek_gpio_irq_domain) -+ dev_err(&pdev->dev, "irq_domain_add_linear failed\n"); -+ } -+ -+ for_each_child_of_node(np, bank) -+ if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank")) -+ mediatek_gpio_bank_probe(pdev, bank); -+ -+ if (mediatek_gpio_irq_domain) -+ irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler); -+ -+ return 0; -+} -+ -+static const struct of_device_id mediatek_gpio_match[] = { -+ { .compatible = "mtk,mt7621-gpio" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mediatek_gpio_match); -+ -+static struct platform_driver mediatek_gpio_driver = { -+ .probe = mediatek_gpio_probe, -+ .driver = { -+ .name = "mt7621_gpio", -+ .owner = THIS_MODULE, -+ .of_match_table = mediatek_gpio_match, -+ }, -+}; -+ -+static int __init -+mediatek_gpio_init(void) -+{ -+ return platform_driver_register(&mediatek_gpio_driver); -+} -+ -+subsys_initcall(mediatek_gpio_init); diff --git a/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch index 7ed1a616f6..084b655483 100644 --- a/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch +++ b/target/linux/ramips/patches-5.4/0031-uvc-add-iPassion-iP2970-support.patch @@ -13,10 +13,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c -@@ -2749,6 +2749,18 @@ static const struct usb_device_id uvc_id +@@ -2908,6 +2908,18 @@ static const struct usb_device_id uvc_id .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_FORCE_Y8 }, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* iPassion iP2970 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, @@ -34,15 +34,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org> { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c -@@ -139,6 +139,7 @@ static void uvc_status_complete(struct u - switch (dev->status[0] & 0x0f) { - case UVC_STATUS_TYPE_CONTROL: - uvc_event_control(dev, dev->status, len); +@@ -223,6 +223,7 @@ static void uvc_status_complete(struct u + if (uvc_event_control(urb, status, len)) + /* The URB will be resubmitted in work context. */ + return; + dev->motion = 1; break; + } - case UVC_STATUS_TYPE_STREAMING: -@@ -182,6 +183,7 @@ int uvc_status_init(struct uvc_device *d +@@ -271,6 +272,7 @@ int uvc_status_init(struct uvc_device *d } pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); @@ -52,7 +52,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> * an exponent of two. Some developers forgot about it. --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c -@@ -21,6 +21,11 @@ +@@ -16,6 +16,11 @@ #include <linux/wait.h> #include <linux/atomic.h> #include <asm/unaligned.h> @@ -64,8 +64,8 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #include <media/v4l2-common.h> -@@ -1101,9 +1106,149 @@ static void uvc_video_decode_data(struct - } +@@ -1156,9 +1161,149 @@ static void uvc_video_decode_data(struct + uvc_urb->async_operations++; } +struct bh_priv { @@ -196,7 +196,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + +#define MOTION_FLAG_OFFSET 4 static void uvc_video_decode_end(struct uvc_streaming *stream, - struct uvc_buffer *buf, const __u8 *data, int len) + struct uvc_buffer *buf, const u8 *data, int len) { + if ((stream->dev->quirks & UVC_QUIRK_MOTION) && + (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) { @@ -214,7 +214,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* Mark the buffer as done if the EOF marker is set. */ if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); -@@ -1518,6 +1663,8 @@ static int uvc_init_video_isoc(struct uv +@@ -1715,6 +1860,8 @@ static int uvc_init_video_isoc(struct uv if (npackets == 0) return -ENOMEM; @@ -222,13 +222,13 @@ Signed-off-by: John Crispin <blogic@openwrt.org> + npackets = 1; size = npackets * psize; - for (i = 0; i < UVC_URBS; ++i) { + for_each_uvc_urb(uvc_urb, stream) { --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h -@@ -186,7 +186,9 @@ - #define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200 +@@ -199,7 +199,9 @@ #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400 #define UVC_QUIRK_FORCE_Y8 0x00000800 + #define UVC_QUIRK_FORCE_BPP 0x00001000 - +#define UVC_QUIRK_MOTION 0x00001000 +#define UVC_QUIRK_SINGLE_ISO 0x00002000 @@ -236,11 +236,11 @@ Signed-off-by: John Crispin <blogic@openwrt.org> /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 #define UVC_FMT_FLAG_STREAM 0x00000002 -@@ -584,6 +586,7 @@ struct uvc_device { - __u8 *status; +@@ -666,6 +668,7 @@ struct uvc_device { + u8 *status; struct input_dev *input; char input_phys[64]; + int motion; - }; - enum uvc_handle_state { + struct uvc_ctrl_work { + struct work_struct work; diff --git a/target/linux/ramips/patches-5.4/0032-USB-dwc2-add-device_reset.patch b/target/linux/ramips/patches-5.4/0032-USB-dwc2-add-device_reset.patch index c04e2db661..ec837cda93 100644 --- a/target/linux/ramips/patches-5.4/0032-USB-dwc2-add-device_reset.patch +++ b/target/linux/ramips/patches-5.4/0032-USB-dwc2-add-device_reset.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c -@@ -48,6 +48,7 @@ +@@ -49,6 +49,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/usb.h> @@ -18,12 +18,12 @@ Signed-off-by: John Crispin <blogic@openwrt.org> #include <linux/usb/hcd.h> #include <linux/usb/ch11.h> -@@ -5215,6 +5216,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso +@@ -5023,6 +5024,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso retval = -ENOMEM; + device_reset(hsotg->dev); + - hcfg = dwc2_readl(hsotg->regs + HCFG); + hcfg = dwc2_readl(hsotg, HCFG); dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg); diff --git a/target/linux/ramips/patches-5.4/0034-NET-multi-phy-support.patch b/target/linux/ramips/patches-5.4/0034-NET-multi-phy-support.patch deleted file mode 100644 index 5536e3f61c..0000000000 --- a/target/linux/ramips/patches-5.4/0034-NET-multi-phy-support.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 27 Jul 2014 09:38:50 +0100 -Subject: [PATCH 34/53] NET: multi phy support - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/net/phy/phy.c | 9 ++++++--- - include/linux/phy.h | 1 + - 2 files changed, 7 insertions(+), 3 deletions(-) - ---- a/drivers/net/phy/phy.c -+++ b/drivers/net/phy/phy.c -@@ -913,7 +913,10 @@ void phy_state_machine(struct work_struc - /* If the link is down, give up on negotiation for now */ - if (!phydev->link) { - phydev->state = PHY_NOLINK; -- phy_link_down(phydev, true); -+ if (!phydev->no_auto_carrier_off) -+ phy_link_down(phydev, true); -+ else -+ phy_link_down(phydev, false); - break; - } - -@@ -1000,7 +1003,10 @@ void phy_state_machine(struct work_struc - phy_link_up(phydev); - } else { - phydev->state = PHY_NOLINK; -- phy_link_down(phydev, true); -+ if (!phydev->no_auto_carrier_off) -+ phy_link_down(phydev, true); -+ else -+ phy_link_down(phydev, false); - } - - if (phy_interrupt_is_valid(phydev)) -@@ -1010,7 +1016,10 @@ void phy_state_machine(struct work_struc - case PHY_HALTED: - if (phydev->link) { - phydev->link = 0; -- phy_link_down(phydev, true); -+ if (!phydev->no_auto_carrier_off) -+ phy_link_down(phydev, true); -+ else -+ phy_link_down(phydev, false); - do_suspend = true; - } - break; ---- a/include/linux/phy.h -+++ b/include/linux/phy.h -@@ -412,6 +412,7 @@ struct phy_device { - bool suspended; - bool sysfs_links; - bool loopback_enabled; -+ bool no_auto_carrier_off; - - enum phy_state state; - diff --git a/target/linux/ramips/patches-5.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch b/target/linux/ramips/patches-5.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch index 478af4cbc9..7011bbe50b 100644 --- a/target/linux/ramips/patches-5.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch +++ b/target/linux/ramips/patches-5.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch @@ -18,53 +18,3 @@ Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write #define MAX_RETRIES 3 -@@ -51,7 +51,9 @@ - - static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); - static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+#if !FORCE_WORD_WRITE - static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+#endif - static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); - static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); - static void cfi_amdstd_sync (struct mtd_info *); -@@ -202,6 +204,7 @@ static void fixup_amd_bootblock(struct m - } - #endif - -+#if !FORCE_WORD_WRITE - static void fixup_use_write_buffers(struct mtd_info *mtd) - { - struct map_info *map = mtd->priv; -@@ -211,6 +214,7 @@ static void fixup_use_write_buffers(stru - mtd->_write = cfi_amdstd_write_buffers; - } - } -+#endif /* !FORCE_WORD_WRITE */ - - /* Atmel chips don't use the same PRI format as AMD chips */ - static void fixup_convert_atmel_pri(struct mtd_info *mtd) -@@ -1798,6 +1802,7 @@ static int cfi_amdstd_write_words(struct - /* - * FIXME: interleaved mode not tested, and probably not supported! - */ -+#if !FORCE_WORD_WRITE - static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, - unsigned long adr, const u_char *buf, - int len) -@@ -1926,7 +1931,6 @@ static int __xipram do_write_buffer(stru - return ret; - } - -- - static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) - { -@@ -2001,6 +2005,7 @@ static int cfi_amdstd_write_buffers(stru - - return 0; - } -+#endif /* !FORCE_WORD_WRITE */ - - /* - * Wait for the flash chip to become ready to write data diff --git a/target/linux/ramips/patches-5.4/0038-Revert-mtd-nand-Remove-unused-chip-write_page-hook.patch b/target/linux/ramips/patches-5.4/0038-Revert-mtd-nand-Remove-unused-chip-write_page-hook.patch deleted file mode 100644 index 4758f18558..0000000000 --- a/target/linux/ramips/patches-5.4/0038-Revert-mtd-nand-Remove-unused-chip-write_page-hook.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> -Subject: [PATCH] Revert "mtd: nand: Remove unused chip->write_page() hook" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit f107d7a43923a83d837b3ea3c7b7de58cd014bbd. - -OpenWrt's downstream driver mtk_nand2 still uses that callback. - -Signed-off-by: Rafał Miłecki <rafal@milecki.pl> ---- - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -2577,7 +2577,7 @@ static int nand_write_page_syndrome(stru - } - - /** -- * nand_write_page - write one page -+ * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @offset: address offset within the page -@@ -2761,9 +2761,9 @@ static int nand_do_write_ops(struct mtd_ - memset(chip->oob_poi, 0xff, mtd->oobsize); - } - -- ret = nand_write_page(mtd, chip, column, bytes, wbuf, -- oob_required, page, -- (ops->mode == MTD_OPS_RAW)); -+ ret = chip->write_page(mtd, chip, column, bytes, wbuf, -+ oob_required, page, -+ (ops->mode == MTD_OPS_RAW)); - if (ret) - break; - -@@ -4719,6 +4719,9 @@ int nand_scan_tail(struct mtd_info *mtd) - } - } - -+ if (!chip->write_page) -+ chip->write_page = nand_write_page; -+ - /* - * Check ECC mode, default to software if 3byte/512byte hardware ECC is - * selected and we have 256 byte pagesize fallback to software ECC ---- a/include/linux/mtd/rawnand.h -+++ b/include/linux/mtd/rawnand.h -@@ -862,6 +862,7 @@ struct nand_manufacturer_ops { - * structure which is shared among multiple independent - * devices. - * @priv: [OPTIONAL] pointer to private chip data -+ * @write_page: [REPLACEABLE] High-level page write function - * @manufacturer: [INTERN] Contains manufacturer information - */ - -@@ -885,6 +886,9 @@ struct nand_chip { - int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); - int (*erase)(struct mtd_info *mtd, int page); - int (*scan_bbt)(struct mtd_info *mtd); -+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, -+ uint32_t offset, int data_len, const uint8_t *buf, -+ int oob_required, int page, int raw); - int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, - int feature_addr, uint8_t *subfeature_para); - int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, diff --git a/target/linux/ramips/patches-5.4/0039-mtd-add-mt7621-nand-support.patch b/target/linux/ramips/patches-5.4/0039-mtd-add-mt7621-nand-support.patch deleted file mode 100644 index 3c6a59b863..0000000000 --- a/target/linux/ramips/patches-5.4/0039-mtd-add-mt7621-nand-support.patch +++ /dev/null @@ -1,4437 +0,0 @@ -From 0e1c4e3c97b83b4e7da65b1c56f0a7d40736ac53 Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 27 Jul 2014 11:05:17 +0100 -Subject: [PATCH 39/53] mtd: add mt7621 nand support - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/mtd/nand/Kconfig | 6 + - drivers/mtd/nand/Makefile | 1 + - drivers/mtd/nand/bmt.c | 750 ++++++++++++ - drivers/mtd/nand/bmt.h | 80 ++ - drivers/mtd/nand/dev-nand.c | 63 + - drivers/mtd/nand/mt6575_typedefs.h | 340 ++++++ - drivers/mtd/nand/mtk_nand2.c | 2304 +++++++++++++++++++++++++++++++++++ - drivers/mtd/nand/mtk_nand2.h | 452 +++++++ - drivers/mtd/nand/nand_base.c | 6 +- - drivers/mtd/nand/nand_def.h | 123 ++ - drivers/mtd/nand/nand_device_list.h | 55 + - drivers/mtd/nand/partition.h | 115 ++ - 13 files changed, 4311 insertions(+), 3 deletions(-) - create mode 100644 drivers/mtd/nand/bmt.c - create mode 100644 drivers/mtd/nand/bmt.h - create mode 100644 drivers/mtd/nand/dev-nand.c - create mode 100644 drivers/mtd/nand/mt6575_typedefs.h - create mode 100644 drivers/mtd/nand/mtk_nand2.c - create mode 100644 drivers/mtd/nand/mtk_nand2.h - create mode 100644 drivers/mtd/nand/nand_def.h - create mode 100644 drivers/mtd/nand/nand_device_list.h - create mode 100644 drivers/mtd/nand/partition.h - ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -563,4 +563,10 @@ config MTD_NAND_MTK - Enables support for NAND controller on MTK SoCs. - This controller is found on mt27xx, mt81xx, mt65xx SoCs. - -+config MTK_MTD_NAND -+ tristate "Support for MTK SoC NAND controller" -+ depends on SOC_MT7621 -+ select MTD_NAND_IDS -+ select MTD_NAND_ECC -+ - endif # MTD_NAND ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -60,6 +60,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) + - obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ - obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o - obj-$(CONFIG_MTD_NAND_MTK) += mtk_nand.o mtk_ecc.o -+obj-$(CONFIG_MTK_MTD_NAND) += mtk_nand2.o bmt.o - - nand-objs := nand_base.o nand_bbt.o nand_timings.o nand_ids.o - nand-objs += nand_amd.o ---- /dev/null -+++ b/drivers/mtd/nand/bmt.c -@@ -0,0 +1,750 @@ -+#include "bmt.h" -+ -+typedef struct -+{ -+ char signature[3]; -+ u8 version; -+ u8 bad_count; // bad block count in pool -+ u8 mapped_count; // mapped block count in pool -+ u8 checksum; -+ u8 reseverd[13]; -+} phys_bmt_header; -+ -+typedef struct -+{ -+ phys_bmt_header header; -+ bmt_entry table[MAX_BMT_SIZE]; -+} phys_bmt_struct; -+ -+typedef struct -+{ -+ char signature[3]; -+} bmt_oob_data; -+ -+static char MAIN_SIGNATURE[] = "BMT"; -+static char OOB_SIGNATURE[] = "bmt"; -+#define SIGNATURE_SIZE (3) -+ -+#define MAX_DAT_SIZE 0x1000 -+#define MAX_OOB_SIZE 0x80 -+ -+static struct mtd_info *mtd_bmt; -+static struct nand_chip *nand_chip_bmt; -+#define BLOCK_SIZE_BMT (1 << nand_chip_bmt->phys_erase_shift) -+#define PAGE_SIZE_BMT (1 << nand_chip_bmt->page_shift) -+ -+#define OFFSET(block) ((block) * BLOCK_SIZE_BMT) -+#define PAGE_ADDR(block) ((block) * BLOCK_SIZE_BMT / PAGE_SIZE_BMT) -+ -+/********************************************************************* -+* Flash is splited into 2 parts, system part is for normal system * -+* system usage, size is system_block_count, another is replace pool * -+* +-------------------------------------------------+ * -+* | system_block_count | bmt_block_count | * -+* +-------------------------------------------------+ * -+*********************************************************************/ -+static u32 total_block_count; // block number in flash -+static u32 system_block_count; -+static int bmt_block_count; // bmt table size -+// static int bmt_count; // block used in bmt -+static int page_per_block; // page per count -+ -+static u32 bmt_block_index; // bmt block index -+static bmt_struct bmt; // dynamic created global bmt table -+ -+static u8 dat_buf[MAX_DAT_SIZE]; -+static u8 oob_buf[MAX_OOB_SIZE]; -+static bool pool_erased; -+ -+/*************************************************************** -+* -+* Interface adaptor for preloader/uboot/kernel -+* These interfaces operate on physical address, read/write -+* physical data. -+* -+***************************************************************/ -+int nand_read_page_bmt(u32 page, u8 * dat, u8 * oob) -+{ -+ return mtk_nand_exec_read_page(mtd_bmt, page, PAGE_SIZE_BMT, dat, oob); -+} -+ -+bool nand_block_bad_bmt(u32 offset) -+{ -+ return mtk_nand_block_bad_hw(mtd_bmt, offset); -+} -+ -+bool nand_erase_bmt(u32 offset) -+{ -+ int status; -+ if (offset < 0x20000) -+ { -+ MSG(INIT, "erase offset: 0x%x\n", offset); -+ } -+ -+ status = mtk_nand_erase_hw(mtd_bmt, offset / PAGE_SIZE_BMT); // as nand_chip structure doesn't have a erase function defined -+ if (status & NAND_STATUS_FAIL) -+ return false; -+ else -+ return true; -+} -+ -+int mark_block_bad_bmt(u32 offset) -+{ -+ return mtk_nand_block_markbad_hw(mtd_bmt, offset); //mark_block_bad_hw(offset); -+} -+ -+bool nand_write_page_bmt(u32 page, u8 * dat, u8 * oob) -+{ -+ if (mtk_nand_exec_write_page(mtd_bmt, page, PAGE_SIZE_BMT, dat, oob)) -+ return false; -+ else -+ return true; -+} -+ -+/*************************************************************** -+* * -+* static internal function * -+* * -+***************************************************************/ -+static void dump_bmt_info(bmt_struct * bmt) -+{ -+ int i; -+ -+ MSG(INIT, "BMT v%d. total %d mapping:\n", bmt->version, bmt->mapped_count); -+ for (i = 0; i < bmt->mapped_count; i++) -+ { -+ MSG(INIT, "\t0x%x -> 0x%x\n", bmt->table[i].bad_index, bmt->table[i].mapped_index); -+ } -+} -+ -+static bool match_bmt_signature(u8 * dat, u8 * oob) -+{ -+ -+ if (memcmp(dat + MAIN_SIGNATURE_OFFSET, MAIN_SIGNATURE, SIGNATURE_SIZE)) -+ { -+ return false; -+ } -+ -+ if (memcmp(oob + OOB_SIGNATURE_OFFSET, OOB_SIGNATURE, SIGNATURE_SIZE)) -+ { -+ MSG(INIT, "main signature match, oob signature doesn't match, but ignore\n"); -+ } -+ return true; -+} -+ -+static u8 cal_bmt_checksum(phys_bmt_struct * phys_table, int bmt_size) -+{ -+ int i; -+ u8 checksum = 0; -+ u8 *dat = (u8 *) phys_table; -+ -+ checksum += phys_table->header.version; -+ checksum += phys_table->header.mapped_count; -+ -+ dat += sizeof(phys_bmt_header); -+ for (i = 0; i < bmt_size * sizeof(bmt_entry); i++) -+ { -+ checksum += dat[i]; -+ } -+ -+ return checksum; -+} -+ -+ -+static int is_block_mapped(int index) -+{ -+ int i; -+ for (i = 0; i < bmt.mapped_count; i++) -+ { -+ if (index == bmt.table[i].mapped_index) -+ return i; -+ } -+ return -1; -+} -+ -+static bool is_page_used(u8 * dat, u8 * oob) -+{ -+ return ((oob[OOB_INDEX_OFFSET] != 0xFF) || (oob[OOB_INDEX_OFFSET + 1] != 0xFF)); -+} -+ -+static bool valid_bmt_data(phys_bmt_struct * phys_table) -+{ -+ int i; -+ u8 checksum = cal_bmt_checksum(phys_table, bmt_block_count); -+ -+ // checksum correct? -+ if (phys_table->header.checksum != checksum) -+ { -+ MSG(INIT, "BMT Data checksum error: %x %x\n", phys_table->header.checksum, checksum); -+ return false; -+ } -+ -+ MSG(INIT, "BMT Checksum is: 0x%x\n", phys_table->header.checksum); -+ -+ // block index correct? -+ for (i = 0; i < phys_table->header.mapped_count; i++) -+ { -+ if (phys_table->table[i].bad_index >= total_block_count || phys_table->table[i].mapped_index >= total_block_count || phys_table->table[i].mapped_index < system_block_count) -+ { -+ MSG(INIT, "index error: bad_index: %d, mapped_index: %d\n", phys_table->table[i].bad_index, phys_table->table[i].mapped_index); -+ return false; -+ } -+ } -+ -+ // pass check, valid bmt. -+ MSG(INIT, "Valid BMT, version v%d\n", phys_table->header.version); -+ return true; -+} -+ -+static void fill_nand_bmt_buffer(bmt_struct * bmt, u8 * dat, u8 * oob) -+{ -+ phys_bmt_struct phys_bmt; -+ -+ dump_bmt_info(bmt); -+ -+ // fill phys_bmt_struct structure with bmt_struct -+ memset(&phys_bmt, 0xFF, sizeof(phys_bmt)); -+ -+ memcpy(phys_bmt.header.signature, MAIN_SIGNATURE, SIGNATURE_SIZE); -+ phys_bmt.header.version = BMT_VERSION; -+ // phys_bmt.header.bad_count = bmt->bad_count; -+ phys_bmt.header.mapped_count = bmt->mapped_count; -+ memcpy(phys_bmt.table, bmt->table, sizeof(bmt_entry) * bmt_block_count); -+ -+ phys_bmt.header.checksum = cal_bmt_checksum(&phys_bmt, bmt_block_count); -+ -+ memcpy(dat + MAIN_SIGNATURE_OFFSET, &phys_bmt, sizeof(phys_bmt)); -+ memcpy(oob + OOB_SIGNATURE_OFFSET, OOB_SIGNATURE, SIGNATURE_SIZE); -+} -+ -+// return valid index if found BMT, else return 0 -+static int load_bmt_data(int start, int pool_size) -+{ -+ int bmt_index = start + pool_size - 1; // find from the end -+ phys_bmt_struct phys_table; -+ int i; -+ -+ MSG(INIT, "[%s]: begin to search BMT from block 0x%x\n", __FUNCTION__, bmt_index); -+ -+ for (bmt_index = start + pool_size - 1; bmt_index >= start; bmt_index--) -+ { -+ if (nand_block_bad_bmt(OFFSET(bmt_index))) -+ { -+ MSG(INIT, "Skip bad block: %d\n", bmt_index); -+ continue; -+ } -+ -+ if (!nand_read_page_bmt(PAGE_ADDR(bmt_index), dat_buf, oob_buf)) -+ { -+ MSG(INIT, "Error found when read block %d\n", bmt_index); -+ continue; -+ } -+ -+ if (!match_bmt_signature(dat_buf, oob_buf)) -+ { -+ continue; -+ } -+ -+ MSG(INIT, "Match bmt signature @ block: 0x%x\n", bmt_index); -+ -+ memcpy(&phys_table, dat_buf + MAIN_SIGNATURE_OFFSET, sizeof(phys_table)); -+ -+ if (!valid_bmt_data(&phys_table)) -+ { -+ MSG(INIT, "BMT data is not correct %d\n", bmt_index); -+ continue; -+ } else -+ { -+ bmt.mapped_count = phys_table.header.mapped_count; -+ bmt.version = phys_table.header.version; -+ // bmt.bad_count = phys_table.header.bad_count; -+ memcpy(bmt.table, phys_table.table, bmt.mapped_count * sizeof(bmt_entry)); -+ -+ MSG(INIT, "bmt found at block: %d, mapped block: %d\n", bmt_index, bmt.mapped_count); -+ -+ for (i = 0; i < bmt.mapped_count; i++) -+ { -+ if (!nand_block_bad_bmt(OFFSET(bmt.table[i].bad_index))) -+ { -+ MSG(INIT, "block 0x%x is not mark bad, should be power lost last time\n", bmt.table[i].bad_index); -+ mark_block_bad_bmt(OFFSET(bmt.table[i].bad_index)); -+ } -+ } -+ -+ return bmt_index; -+ } -+ } -+ -+ MSG(INIT, "bmt block not found!\n"); -+ return 0; -+} -+ -+/************************************************************************* -+* Find an available block and erase. * -+* start_from_end: if true, find available block from end of flash. * -+* else, find from the beginning of the pool * -+* need_erase: if true, all unmapped blocks in the pool will be erased * -+*************************************************************************/ -+static int find_available_block(bool start_from_end) -+{ -+ int i; // , j; -+ int block = system_block_count; -+ int direction; -+ // int avail_index = 0; -+ MSG(INIT, "Try to find_available_block, pool_erase: %d\n", pool_erased); -+ -+ // erase all un-mapped blocks in pool when finding avaliable block -+ if (!pool_erased) -+ { -+ MSG(INIT, "Erase all un-mapped blocks in pool\n"); -+ for (i = 0; i < bmt_block_count; i++) -+ { -+ if (block == bmt_block_index) -+ { -+ MSG(INIT, "Skip bmt block 0x%x\n", block); -+ continue; -+ } -+ -+ if (nand_block_bad_bmt(OFFSET(block + i))) -+ { -+ MSG(INIT, "Skip bad block 0x%x\n", block + i); -+ continue; -+ } -+//if(block==4095) -+//{ -+// continue; -+//} -+ -+ if (is_block_mapped(block + i) >= 0) -+ { -+ MSG(INIT, "Skip mapped block 0x%x\n", block + i); -+ continue; -+ } -+ -+ if (!nand_erase_bmt(OFFSET(block + i))) -+ { -+ MSG(INIT, "Erase block 0x%x failed\n", block + i); -+ mark_block_bad_bmt(OFFSET(block + i)); -+ } -+ } -+ -+ pool_erased = 1; -+ } -+ -+ if (start_from_end) -+ { -+ block = total_block_count - 1; -+ direction = -1; -+ } else -+ { -+ block = system_block_count; -+ direction = 1; -+ } -+ -+ for (i = 0; i < bmt_block_count; i++, block += direction) -+ { -+ if (block == bmt_block_index) -+ { -+ MSG(INIT, "Skip bmt block 0x%x\n", block); -+ continue; -+ } -+ -+ if (nand_block_bad_bmt(OFFSET(block))) -+ { -+ MSG(INIT, "Skip bad block 0x%x\n", block); -+ continue; -+ } -+ -+ if (is_block_mapped(block) >= 0) -+ { -+ MSG(INIT, "Skip mapped block 0x%x\n", block); -+ continue; -+ } -+ -+ MSG(INIT, "Find block 0x%x available\n", block); -+ return block; -+ } -+ -+ return 0; -+} -+ -+static unsigned short get_bad_index_from_oob(u8 * oob_buf) -+{ -+ unsigned short index; -+ memcpy(&index, oob_buf + OOB_INDEX_OFFSET, OOB_INDEX_SIZE); -+ -+ return index; -+} -+ -+void set_bad_index_to_oob(u8 * oob, u16 index) -+{ -+ memcpy(oob + OOB_INDEX_OFFSET, &index, sizeof(index)); -+} -+ -+static int migrate_from_bad(int offset, u8 * write_dat, u8 * write_oob) -+{ -+ int page; -+ int error_block = offset / BLOCK_SIZE_BMT; -+ int error_page = (offset / PAGE_SIZE_BMT) % page_per_block; -+ int to_index; -+ -+ memcpy(oob_buf, write_oob, MAX_OOB_SIZE); -+ -+ to_index = find_available_block(false); -+ -+ if (!to_index) -+ { -+ MSG(INIT, "Cannot find an available block for BMT\n"); -+ return 0; -+ } -+ -+ { // migrate error page first -+ MSG(INIT, "Write error page: 0x%x\n", error_page); -+ if (!write_dat) -+ { -+ nand_read_page_bmt(PAGE_ADDR(error_block) + error_page, dat_buf, NULL); -+ write_dat = dat_buf; -+ } -+ // memcpy(oob_buf, write_oob, MAX_OOB_SIZE); -+ -+ if (error_block < system_block_count) -+ set_bad_index_to_oob(oob_buf, error_block); // if error_block is already a mapped block, original mapping index is in OOB. -+ -+ if (!nand_write_page_bmt(PAGE_ADDR(to_index) + error_page, write_dat, oob_buf)) -+ { -+ MSG(INIT, "Write to page 0x%x fail\n", PAGE_ADDR(to_index) + error_page); -+ mark_block_bad_bmt(to_index); -+ return migrate_from_bad(offset, write_dat, write_oob); -+ } -+ } -+ -+ for (page = 0; page < page_per_block; page++) -+ { -+ if (page != error_page) -+ { -+ nand_read_page_bmt(PAGE_ADDR(error_block) + page, dat_buf, oob_buf); -+ if (is_page_used(dat_buf, oob_buf)) -+ { -+ if (error_block < system_block_count) -+ { -+ set_bad_index_to_oob(oob_buf, error_block); -+ } -+ MSG(INIT, "\tmigrate page 0x%x to page 0x%x\n", PAGE_ADDR(error_block) + page, PAGE_ADDR(to_index) + page); -+ if (!nand_write_page_bmt(PAGE_ADDR(to_index) + page, dat_buf, oob_buf)) -+ { -+ MSG(INIT, "Write to page 0x%x fail\n", PAGE_ADDR(to_index) + page); -+ mark_block_bad_bmt(to_index); -+ return migrate_from_bad(offset, write_dat, write_oob); -+ } -+ } -+ } -+ } -+ -+ MSG(INIT, "Migrate from 0x%x to 0x%x done!\n", error_block, to_index); -+ -+ return to_index; -+} -+ -+static bool write_bmt_to_flash(u8 * dat, u8 * oob) -+{ -+ bool need_erase = true; -+ MSG(INIT, "Try to write BMT\n"); -+ -+ if (bmt_block_index == 0) -+ { -+ // if we don't have index, we don't need to erase found block as it has been erased in find_available_block() -+ need_erase = false; -+ if (!(bmt_block_index = find_available_block(true))) -+ { -+ MSG(INIT, "Cannot find an available block for BMT\n"); -+ return false; -+ } -+ } -+ -+ MSG(INIT, "Find BMT block: 0x%x\n", bmt_block_index); -+ -+ // write bmt to flash -+ if (need_erase) -+ { -+ if (!nand_erase_bmt(OFFSET(bmt_block_index))) -+ { -+ MSG(INIT, "BMT block erase fail, mark bad: 0x%x\n", bmt_block_index); -+ mark_block_bad_bmt(OFFSET(bmt_block_index)); -+ // bmt.bad_count++; -+ -+ bmt_block_index = 0; -+ return write_bmt_to_flash(dat, oob); // recursive call -+ } -+ } -+ -+ if (!nand_write_page_bmt(PAGE_ADDR(bmt_block_index), dat, oob)) -+ { -+ MSG(INIT, "Write BMT data fail, need to write again\n"); -+ mark_block_bad_bmt(OFFSET(bmt_block_index)); -+ // bmt.bad_count++; -+ -+ bmt_block_index = 0; -+ return write_bmt_to_flash(dat, oob); // recursive call -+ } -+ -+ MSG(INIT, "Write BMT data to block 0x%x success\n", bmt_block_index); -+ return true; -+} -+ -+/******************************************************************* -+* Reconstruct bmt, called when found bmt info doesn't match bad -+* block info in flash. -+* -+* Return NULL for failure -+*******************************************************************/ -+bmt_struct *reconstruct_bmt(bmt_struct * bmt) -+{ -+ int i; -+ int index = system_block_count; -+ unsigned short bad_index; -+ int mapped; -+ -+ // init everything in BMT struct -+ bmt->version = BMT_VERSION; -+ bmt->bad_count = 0; -+ bmt->mapped_count = 0; -+ -+ memset(bmt->table, 0, bmt_block_count * sizeof(bmt_entry)); -+ -+ for (i = 0; i < bmt_block_count; i++, index++) -+ { -+ if (nand_block_bad_bmt(OFFSET(index))) -+ { -+ MSG(INIT, "Skip bad block: 0x%x\n", index); -+ // bmt->bad_count++; -+ continue; -+ } -+ -+ MSG(INIT, "read page: 0x%x\n", PAGE_ADDR(index)); -+ nand_read_page_bmt(PAGE_ADDR(index), dat_buf, oob_buf); -+ /* if (mtk_nand_read_page_hw(PAGE_ADDR(index), dat_buf)) -+ { -+ MSG(INIT, "Error when read block %d\n", bmt_block_index); -+ continue; -+ } */ -+ -+ if ((bad_index = get_bad_index_from_oob(oob_buf)) >= system_block_count) -+ { -+ MSG(INIT, "get bad index: 0x%x\n", bad_index); -+ if (bad_index != 0xFFFF) -+ MSG(INIT, "Invalid bad index found in block 0x%x, bad index 0x%x\n", index, bad_index); -+ continue; -+ } -+ -+ MSG(INIT, "Block 0x%x is mapped to bad block: 0x%x\n", index, bad_index); -+ -+ if (!nand_block_bad_bmt(OFFSET(bad_index))) -+ { -+ MSG(INIT, "\tbut block 0x%x is not marked as bad, invalid mapping\n", bad_index); -+ continue; // no need to erase here, it will be erased later when trying to write BMT -+ } -+ -+ if ((mapped = is_block_mapped(bad_index)) >= 0) -+ { -+ MSG(INIT, "bad block 0x%x is mapped to 0x%x, should be caused by power lost, replace with one\n", bmt->table[mapped].bad_index, bmt->table[mapped].mapped_index); -+ bmt->table[mapped].mapped_index = index; // use new one instead. -+ } else -+ { -+ // add mapping to BMT -+ bmt->table[bmt->mapped_count].bad_index = bad_index; -+ bmt->table[bmt->mapped_count].mapped_index = index; -+ bmt->mapped_count++; -+ } -+ -+ MSG(INIT, "Add mapping: 0x%x -> 0x%x to BMT\n", bad_index, index); -+ -+ } -+ -+ MSG(INIT, "Scan replace pool done, mapped block: %d\n", bmt->mapped_count); -+ // dump_bmt_info(bmt); -+ -+ // fill NAND BMT buffer -+ memset(oob_buf, 0xFF, sizeof(oob_buf)); -+ fill_nand_bmt_buffer(bmt, dat_buf, oob_buf); -+ -+ // write BMT back -+ if (!write_bmt_to_flash(dat_buf, oob_buf)) -+ { -+ MSG(INIT, "TRAGEDY: cannot find a place to write BMT!!!!\n"); -+ } -+ -+ return bmt; -+} -+ -+/******************************************************************* -+* [BMT Interface] -+* -+* Description: -+* Init bmt from nand. Reconstruct if not found or data error -+* -+* Parameter: -+* size: size of bmt and replace pool -+* -+* Return: -+* NULL for failure, and a bmt struct for success -+*******************************************************************/ -+bmt_struct *init_bmt(struct nand_chip * chip, int size) -+{ -+ struct mtk_nand_host *host; -+ -+ if (size > 0 && size < MAX_BMT_SIZE) -+ { -+ MSG(INIT, "Init bmt table, size: %d\n", size); -+ bmt_block_count = size; -+ } else -+ { -+ MSG(INIT, "Invalid bmt table size: %d\n", size); -+ return NULL; -+ } -+ nand_chip_bmt = chip; -+ system_block_count = chip->chipsize >> chip->phys_erase_shift; -+ total_block_count = bmt_block_count + system_block_count; -+ page_per_block = BLOCK_SIZE_BMT / PAGE_SIZE_BMT; -+ host = (struct mtk_nand_host *)chip->priv; -+ mtd_bmt = host->mtd; -+ -+ MSG(INIT, "mtd_bmt: %p, nand_chip_bmt: %p\n", mtd_bmt, nand_chip_bmt); -+ MSG(INIT, "bmt count: %d, system count: %d\n", bmt_block_count, system_block_count); -+ -+ // set this flag, and unmapped block in pool will be erased. -+ pool_erased = 0; -+ memset(bmt.table, 0, size * sizeof(bmt_entry)); -+ if ((bmt_block_index = load_bmt_data(system_block_count, size))) -+ { -+ MSG(INIT, "Load bmt data success @ block 0x%x\n", bmt_block_index); -+ dump_bmt_info(&bmt); -+ return &bmt; -+ } else -+ { -+ MSG(INIT, "Load bmt data fail, need re-construct!\n"); -+#ifndef __UBOOT_NAND__ // BMT is not re-constructed in UBOOT. -+ if (reconstruct_bmt(&bmt)) -+ return &bmt; -+ else -+#endif -+ return NULL; -+ } -+} -+ -+/******************************************************************* -+* [BMT Interface] -+* -+* Description: -+* Update BMT. -+* -+* Parameter: -+* offset: update block/page offset. -+* reason: update reason, see update_reason_t for reason. -+* dat/oob: data and oob buffer for write fail. -+* -+* Return: -+* Return true for success, and false for failure. -+*******************************************************************/ -+bool update_bmt(u32 offset, update_reason_t reason, u8 * dat, u8 * oob) -+{ -+ int map_index; -+ int orig_bad_block = -1; -+ // int bmt_update_index; -+ int i; -+ int bad_index = offset / BLOCK_SIZE_BMT; -+ -+#ifndef MTK_NAND_BMT -+ return false; -+#endif -+ if (reason == UPDATE_WRITE_FAIL) -+ { -+ MSG(INIT, "Write fail, need to migrate\n"); -+ if (!(map_index = migrate_from_bad(offset, dat, oob))) -+ { -+ MSG(INIT, "migrate fail\n"); -+ return false; -+ } -+ } else -+ { -+ if (!(map_index = find_available_block(false))) -+ { -+ MSG(INIT, "Cannot find block in pool\n"); -+ return false; -+ } -+ } -+ -+ // now let's update BMT -+ if (bad_index >= system_block_count) // mapped block become bad, find original bad block -+ { -+ for (i = 0; i < bmt_block_count; i++) -+ { -+ if (bmt.table[i].mapped_index == bad_index) -+ { -+ orig_bad_block = bmt.table[i].bad_index; -+ break; -+ } -+ } -+ // bmt.bad_count++; -+ MSG(INIT, "Mapped block becomes bad, orig bad block is 0x%x\n", orig_bad_block); -+ -+ bmt.table[i].mapped_index = map_index; -+ } else -+ { -+ bmt.table[bmt.mapped_count].mapped_index = map_index; -+ bmt.table[bmt.mapped_count].bad_index = bad_index; -+ bmt.mapped_count++; -+ } -+ -+ memset(oob_buf, 0xFF, sizeof(oob_buf)); -+ fill_nand_bmt_buffer(&bmt, dat_buf, oob_buf); -+ if (!write_bmt_to_flash(dat_buf, oob_buf)) -+ return false; -+ -+ mark_block_bad_bmt(offset); -+ -+ return true; -+} -+ -+/******************************************************************* -+* [BMT Interface] -+* -+* Description: -+* Given an block index, return mapped index if it's mapped, else -+* return given index. -+* -+* Parameter: -+* index: given an block index. This value cannot exceed -+* system_block_count. -+* -+* Return NULL for failure -+*******************************************************************/ -+u16 get_mapping_block_index(int index) -+{ -+ int i; -+#ifndef MTK_NAND_BMT -+ return index; -+#endif -+ if (index > system_block_count) -+ { -+ return index; -+ } -+ -+ for (i = 0; i < bmt.mapped_count; i++) -+ { -+ if (bmt.table[i].bad_index == index) -+ { -+ return bmt.table[i].mapped_index; -+ } -+ } -+ -+ return index; -+} -+#ifdef __KERNEL_NAND__ -+EXPORT_SYMBOL_GPL(init_bmt); -+EXPORT_SYMBOL_GPL(update_bmt); -+EXPORT_SYMBOL_GPL(get_mapping_block_index); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("MediaTek"); -+MODULE_DESCRIPTION("Bad Block mapping management for MediaTek NAND Flash Driver"); -+#endif ---- /dev/null -+++ b/drivers/mtd/nand/bmt.h -@@ -0,0 +1,80 @@ -+#ifndef __BMT_H__ -+#define __BMT_H__ -+ -+#include "nand_def.h" -+ -+#if defined(__PRELOADER_NAND__) -+ -+#include "nand.h" -+ -+#elif defined(__UBOOT_NAND__) -+ -+#include <linux/mtd/nand.h> -+#include "mtk_nand2.h" -+ -+#elif defined(__KERNEL_NAND__) -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/rawnand.h> -+#include <linux/module.h> -+#include "mtk_nand2.h" -+ -+#endif -+ -+ -+#define MAX_BMT_SIZE (0x80) -+#define BMT_VERSION (1) // initial version -+ -+#define MAIN_SIGNATURE_OFFSET (0) -+#define OOB_SIGNATURE_OFFSET (1) -+#define OOB_INDEX_OFFSET (29) -+#define OOB_INDEX_SIZE (2) -+#define FAKE_INDEX (0xAAAA) -+ -+typedef struct _bmt_entry_ -+{ -+ u16 bad_index; // bad block index -+ u16 mapped_index; // mapping block index in the replace pool -+} bmt_entry; -+ -+typedef enum -+{ -+ UPDATE_ERASE_FAIL, -+ UPDATE_WRITE_FAIL, -+ UPDATE_UNMAPPED_BLOCK, -+ UPDATE_REASON_COUNT, -+} update_reason_t; -+ -+typedef struct -+{ -+ bmt_entry table[MAX_BMT_SIZE]; -+ u8 version; -+ u8 mapped_count; // mapped block count in pool -+ u8 bad_count; // bad block count in pool. Not used in V1 -+} bmt_struct; -+ -+/*************************************************************** -+* * -+* Interface BMT need to use * -+* * -+***************************************************************/ -+extern bool mtk_nand_exec_read_page(struct mtd_info *mtd, u32 row, u32 page_size, u8 * dat, u8 * oob); -+extern int mtk_nand_block_bad_hw(struct mtd_info *mtd, loff_t ofs); -+extern int mtk_nand_erase_hw(struct mtd_info *mtd, int page); -+extern int mtk_nand_block_markbad_hw(struct mtd_info *mtd, loff_t ofs); -+extern int mtk_nand_exec_write_page(struct mtd_info *mtd, u32 row, u32 page_size, u8 * dat, u8 * oob); -+ -+ -+/*************************************************************** -+* * -+* Different function interface for preloader/uboot/kernel * -+* * -+***************************************************************/ -+void set_bad_index_to_oob(u8 * oob, u16 index); -+ -+ -+bmt_struct *init_bmt(struct nand_chip *nand, int size); -+bool update_bmt(u32 offset, update_reason_t reason, u8 * dat, u8 * oob); -+unsigned short get_mapping_block_index(int index); -+ -+#endif // #ifndef __BMT_H__ ---- /dev/null -+++ b/drivers/mtd/nand/dev-nand.c -@@ -0,0 +1,63 @@ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/platform_device.h> -+ -+#include "mt6575_typedefs.h" -+ -+#define RALINK_NAND_CTRL_BASE 0xBE003000 -+#define NFI_base RALINK_NAND_CTRL_BASE -+#define RALINK_NANDECC_CTRL_BASE 0xBE003800 -+#define NFIECC_base RALINK_NANDECC_CTRL_BASE -+#define MT7621_NFI_IRQ_ID SURFBOARDINT_NAND -+#define MT7621_NFIECC_IRQ_ID SURFBOARDINT_NAND_ECC -+ -+#define SURFBOARDINT_NAND 22 -+#define SURFBOARDINT_NAND_ECC 23 -+ -+static struct resource MT7621_resource_nand[] = { -+ { -+ .start = NFI_base, -+ .end = NFI_base + 0x1A0, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = NFIECC_base, -+ .end = NFIECC_base + 0x150, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = MT7621_NFI_IRQ_ID, -+ .flags = IORESOURCE_IRQ, -+ }, -+ { -+ .start = MT7621_NFIECC_IRQ_ID, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static struct platform_device MT7621_nand_dev = { -+ .name = "MT7621-NAND", -+ .id = 0, -+ .num_resources = ARRAY_SIZE(MT7621_resource_nand), -+ .resource = MT7621_resource_nand, -+ .dev = { -+ .platform_data = &mt7621_nand_hw, -+ }, -+}; -+ -+ -+int __init mtk_nand_register(void) -+{ -+ -+ int retval = 0; -+ -+ retval = platform_device_register(&MT7621_nand_dev); -+ if (retval != 0) { -+ printk(KERN_ERR "register nand device fail\n"); -+ return retval; -+ } -+ -+ -+ return retval; -+} -+arch_initcall(mtk_nand_register); ---- /dev/null -+++ b/drivers/mtd/nand/mt6575_typedefs.h -@@ -0,0 +1,340 @@ -+/* Copyright Statement: -+ * -+ * This software/firmware and related documentation ("MediaTek Software") are -+ * protected under relevant copyright laws. The information contained herein -+ * is confidential and proprietary to MediaTek Inc. and/or its licensors. -+ * Without the prior written permission of MediaTek inc. and/or its licensors, -+ * any reproduction, modification, use or disclosure of MediaTek Software, -+ * and information contained herein, in whole or in part, shall be strictly prohibited. -+ */ -+/* MediaTek Inc. (C) 2010. All rights reserved. -+ * -+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON -+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH -+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES -+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES -+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK -+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR -+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND -+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO -+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -+ * -+ * The following software/firmware and/or related documentation ("MediaTek Software") -+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's -+ * applicable license agreements with MediaTek Inc. -+ */ -+ -+/***************************************************************************** -+* Copyright Statement: -+* -------------------- -+* This software is protected by Copyright and the information contained -+* herein is confidential. The software may not be copied and the information -+* contained herein may not be used or disclosed except with the written -+* permission of MediaTek Inc. (C) 2008 -+* -+* BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON -+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH -+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO -+* NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S -+* SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM. -+* -+* BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE -+* LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO -+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -+* -+* THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE -+* WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF -+* LAWS PRINCIPLES. ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND -+* RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER -+* THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC). -+* -+*****************************************************************************/ -+ -+#ifndef _MT6575_TYPEDEFS_H -+#define _MT6575_TYPEDEFS_H -+ -+#if defined (__KERNEL_NAND__) -+#include <linux/bug.h> -+#else -+#define true 1 -+#define false 0 -+#define bool u8 -+#endif -+ -+// --------------------------------------------------------------------------- -+// Basic Type Definitions -+// --------------------------------------------------------------------------- -+ -+typedef volatile unsigned char *P_kal_uint8; -+typedef volatile unsigned short *P_kal_uint16; -+typedef volatile unsigned int *P_kal_uint32; -+ -+typedef long LONG; -+typedef unsigned char UBYTE; -+typedef short SHORT; -+ -+typedef signed char kal_int8; -+typedef signed short kal_int16; -+typedef signed int kal_int32; -+typedef long long kal_int64; -+typedef unsigned char kal_uint8; -+typedef unsigned short kal_uint16; -+typedef unsigned int kal_uint32; -+typedef unsigned long long kal_uint64; -+typedef char kal_char; -+ -+typedef unsigned int *UINT32P; -+typedef volatile unsigned short *UINT16P; -+typedef volatile unsigned char *UINT8P; -+typedef unsigned char *U8P; -+ -+typedef volatile unsigned char *P_U8; -+typedef volatile signed char *P_S8; -+typedef volatile unsigned short *P_U16; -+typedef volatile signed short *P_S16; -+typedef volatile unsigned int *P_U32; -+typedef volatile signed int *P_S32; -+typedef unsigned long long *P_U64; -+typedef signed long long *P_S64; -+ -+typedef unsigned char U8; -+typedef signed char S8; -+typedef unsigned short U16; -+typedef signed short S16; -+typedef unsigned int U32; -+typedef signed int S32; -+typedef unsigned long long U64; -+typedef signed long long S64; -+//typedef unsigned char bool; -+ -+typedef unsigned char UINT8; -+typedef unsigned short UINT16; -+typedef unsigned int UINT32; -+typedef unsigned short USHORT; -+typedef signed char INT8; -+typedef signed short INT16; -+typedef signed int INT32; -+typedef unsigned int DWORD; -+typedef void VOID; -+typedef unsigned char BYTE; -+typedef float FLOAT; -+ -+typedef char *LPCSTR; -+typedef short *LPWSTR; -+ -+ -+// --------------------------------------------------------------------------- -+// Constants -+// --------------------------------------------------------------------------- -+ -+#define IMPORT EXTERN -+#ifndef __cplusplus -+ #define EXTERN extern -+#else -+ #define EXTERN extern "C" -+#endif -+#define LOCAL static -+#define GLOBAL -+#define EXPORT GLOBAL -+ -+#define EQ == -+#define NEQ != -+#define AND && -+#define OR || -+#define XOR(A,B) ((!(A) AND (B)) OR ((A) AND !(B))) -+ -+#ifndef FALSE -+ #define FALSE (0) -+#endif -+ -+#ifndef TRUE -+ #define TRUE (1) -+#endif -+ -+#ifndef NULL -+ #define NULL (0) -+#endif -+ -+//enum boolean {false, true}; -+enum {RX, TX, NONE}; -+ -+#ifndef BOOL -+typedef unsigned char BOOL; -+#endif -+ -+typedef enum { -+ KAL_FALSE = 0, -+ KAL_TRUE = 1, -+} kal_bool; -+ -+ -+// --------------------------------------------------------------------------- -+// Type Casting -+// --------------------------------------------------------------------------- -+ -+#define AS_INT32(x) (*(INT32 *)((void*)x)) -+#define AS_INT16(x) (*(INT16 *)((void*)x)) -+#define AS_INT8(x) (*(INT8 *)((void*)x)) -+ -+#define AS_UINT32(x) (*(UINT32 *)((void*)x)) -+#define AS_UINT16(x) (*(UINT16 *)((void*)x)) -+#define AS_UINT8(x) (*(UINT8 *)((void*)x)) -+ -+ -+// --------------------------------------------------------------------------- -+// Register Manipulations -+// --------------------------------------------------------------------------- -+ -+#define READ_REGISTER_UINT32(reg) \ -+ (*(volatile UINT32 * const)(reg)) -+ -+#define WRITE_REGISTER_UINT32(reg, val) \ -+ (*(volatile UINT32 * const)(reg)) = (val) -+ -+#define READ_REGISTER_UINT16(reg) \ -+ (*(volatile UINT16 * const)(reg)) -+ -+#define WRITE_REGISTER_UINT16(reg, val) \ -+ (*(volatile UINT16 * const)(reg)) = (val) -+ -+#define READ_REGISTER_UINT8(reg) \ -+ (*(volatile UINT8 * const)(reg)) -+ -+#define WRITE_REGISTER_UINT8(reg, val) \ -+ (*(volatile UINT8 * const)(reg)) = (val) -+ -+#define INREG8(x) READ_REGISTER_UINT8((UINT8*)((void*)(x))) -+#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8*)((void*)(x)), (UINT8)(y)) -+#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) -+#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) -+#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) -+ -+#define INREG16(x) READ_REGISTER_UINT16((UINT16*)((void*)(x))) -+#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16*)((void*)(x)),(UINT16)(y)) -+#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) -+#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) -+#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) -+ -+#define INREG32(x) READ_REGISTER_UINT32((UINT32*)((void*)(x))) -+#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32*)((void*)(x)), (UINT32)(y)) -+#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) -+#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) -+#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) -+ -+ -+#define DRV_Reg8(addr) INREG8(addr) -+#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) -+#define DRV_SetReg8(addr, data) SETREG8(addr, data) -+#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) -+ -+#define DRV_Reg16(addr) INREG16(addr) -+#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) -+#define DRV_SetReg16(addr, data) SETREG16(addr, data) -+#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) -+ -+#define DRV_Reg32(addr) INREG32(addr) -+#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) -+#define DRV_SetReg32(addr, data) SETREG32(addr, data) -+#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) -+ -+// !!! DEPRECATED, WILL BE REMOVED LATER !!! -+#define DRV_Reg(addr) DRV_Reg16(addr) -+#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) -+#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) -+#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) -+ -+ -+// --------------------------------------------------------------------------- -+// Compiler Time Deduction Macros -+// --------------------------------------------------------------------------- -+ -+#define _MASK_OFFSET_1(x, n) ((x) & 0x1) ? (n) : -+#define _MASK_OFFSET_2(x, n) _MASK_OFFSET_1((x), (n)) _MASK_OFFSET_1((x) >> 1, (n) + 1) -+#define _MASK_OFFSET_4(x, n) _MASK_OFFSET_2((x), (n)) _MASK_OFFSET_2((x) >> 2, (n) + 2) -+#define _MASK_OFFSET_8(x, n) _MASK_OFFSET_4((x), (n)) _MASK_OFFSET_4((x) >> 4, (n) + 4) -+#define _MASK_OFFSET_16(x, n) _MASK_OFFSET_8((x), (n)) _MASK_OFFSET_8((x) >> 8, (n) + 8) -+#define _MASK_OFFSET_32(x, n) _MASK_OFFSET_16((x), (n)) _MASK_OFFSET_16((x) >> 16, (n) + 16) -+ -+#define MASK_OFFSET_ERROR (0xFFFFFFFF) -+ -+#define MASK_OFFSET(x) (_MASK_OFFSET_32(x, 0) MASK_OFFSET_ERROR) -+ -+ -+// --------------------------------------------------------------------------- -+// Assertions -+// --------------------------------------------------------------------------- -+ -+#ifndef ASSERT -+ #define ASSERT(expr) BUG_ON(!(expr)) -+#endif -+ -+#ifndef NOT_IMPLEMENTED -+ #define NOT_IMPLEMENTED() BUG_ON(1) -+#endif -+ -+#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) -+#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) -+#define STATIC_ASSERT_XX(pred, line) \ -+ extern char assertion_failed_at_##line[(pred) ? 1 : -1] -+ -+// --------------------------------------------------------------------------- -+// Resolve Compiler Warnings -+// --------------------------------------------------------------------------- -+ -+#define NOT_REFERENCED(x) { (x) = (x); } -+ -+ -+// --------------------------------------------------------------------------- -+// Utilities -+// --------------------------------------------------------------------------- -+ -+#define MAXIMUM(A,B) (((A)>(B))?(A):(B)) -+#define MINIMUM(A,B) (((A)<(B))?(A):(B)) -+ -+#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) -+#define DVT_DELAYMACRO(u4Num) \ -+{ \ -+ UINT32 u4Count = 0 ; \ -+ for (u4Count = 0; u4Count < u4Num; u4Count++ ); \ -+} \ -+ -+#define A68351B 0 -+#define B68351B 1 -+#define B68351D 2 -+#define B68351E 3 -+#define UNKNOWN_IC_VERSION 0xFF -+ -+/* NAND driver */ -+struct mtk_nand_host_hw { -+ unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */ -+ unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */ -+ unsigned int nfi_cs_num; /* NFI_CS_NUM */ -+ unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */ -+ unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */ -+ unsigned int nand_ecc_size; -+ unsigned int nand_ecc_bytes; -+ unsigned int nand_ecc_mode; -+}; -+extern struct mtk_nand_host_hw mt7621_nand_hw; -+extern unsigned int CFG_BLOCKSIZE; -+ -+#endif // _MT6575_TYPEDEFS_H -+ ---- /dev/null -+++ b/drivers/mtd/nand/mtk_nand2.c -@@ -0,0 +1,2345 @@ -+/****************************************************************************** -+* mtk_nand2.c - MTK NAND Flash Device Driver -+ * -+* Copyright 2009-2012 MediaTek Co.,Ltd. -+ * -+* DESCRIPTION: -+* This file provid the other drivers nand relative functions -+ * -+* modification history -+* ---------------------------------------- -+* v3.0, 11 Feb 2010, mtk -+* ---------------------------------------- -+******************************************************************************/ -+#include "nand_def.h" -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/errno.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+#include <linux/wait.h> -+#include <linux/spinlock.h> -+#include <linux/interrupt.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/rawnand.h> -+#include <linux/mtd/partitions.h> -+#include <linux/mtd/nand_ecc.h> -+#include <linux/dma-mapping.h> -+#include <linux/jiffies.h> -+#include <linux/platform_device.h> -+#include <linux/proc_fs.h> -+#include <linux/time.h> -+#include <linux/mm.h> -+#include <asm/io.h> -+#include <asm/cacheflush.h> -+#include <asm/uaccess.h> -+#include <linux/miscdevice.h> -+#include "mtk_nand2.h" -+#include "nand_device_list.h" -+ -+#include "bmt.h" -+#include "partition.h" -+ -+unsigned int CFG_BLOCKSIZE; -+ -+static int shift_on_bbt = 0; -+int mtk_nand_read_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page); -+ -+static const char * const probe_types[] = { "cmdlinepart", "ofpart", NULL }; -+ -+#define NAND_CMD_STATUS_MULTI 0x71 -+ -+void show_stack(struct task_struct *tsk, unsigned long *sp); -+extern void mt_irq_set_sens(unsigned int irq, unsigned int sens); -+extern void mt_irq_set_polarity(unsigned int irq,unsigned int polarity); -+ -+struct mtk_nand_host mtk_nand_host; /* include mtd_info and nand_chip structs */ -+struct mtk_nand_host_hw mt7621_nand_hw = { -+ .nfi_bus_width = 8, -+ .nfi_access_timing = NFI_DEFAULT_ACCESS_TIMING, -+ .nfi_cs_num = NFI_CS_NUM, -+ .nand_sec_size = 512, -+ .nand_sec_shift = 9, -+ .nand_ecc_size = 2048, -+ .nand_ecc_bytes = 32, -+ .nand_ecc_mode = NAND_ECC_HW, -+}; -+ -+ -+/******************************************************************************* -+ * Gloable Varible Definition -+ *******************************************************************************/ -+ -+#define NFI_ISSUE_COMMAND(cmd, col_addr, row_addr, col_num, row_num) \ -+ do { \ -+ DRV_WriteReg(NFI_CMD_REG16,cmd);\ -+ while (DRV_Reg32(NFI_STA_REG32) & STA_CMD_STATE);\ -+ DRV_WriteReg32(NFI_COLADDR_REG32, col_addr);\ -+ DRV_WriteReg32(NFI_ROWADDR_REG32, row_addr);\ -+ DRV_WriteReg(NFI_ADDRNOB_REG16, col_num | (row_num<<ADDR_ROW_NOB_SHIFT));\ -+ while (DRV_Reg32(NFI_STA_REG32) & STA_ADDR_STATE);\ -+ }while(0); -+ -+//------------------------------------------------------------------------------- -+static struct NAND_CMD g_kCMD; -+static u32 g_u4ChipVer; -+bool g_bInitDone; -+static bool g_bcmdstatus; -+static u32 g_value = 0; -+static int g_page_size; -+ -+BOOL g_bHwEcc = true; -+ -+ -+extern void nand_release_device(struct mtd_info *mtd); -+extern int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state); -+ -+#if defined(MTK_NAND_BMT) -+static bmt_struct *g_bmt; -+#endif -+struct mtk_nand_host *host; -+extern struct mtd_partition g_pasStatic_Partition[]; -+int part_num = NUM_PARTITIONS; -+int manu_id; -+int dev_id; -+ -+/* this constant was taken from linux/nand/nand.h v 3.14 -+ * in later versions it seems it was removed in order to save a bit of space -+ */ -+#define NAND_MAX_OOBSIZE 774 -+static u8 local_oob_buf[NAND_MAX_OOBSIZE]; -+ -+static u8 nand_badblock_offset = 0; -+ -+static void nand_bbt_set(struct mtd_info *mtd, int page, int flag) -+{ -+ struct nand_chip *this = mtd->priv; -+ int block; -+ -+ block = (int)(page >> (this->bbt_erase_shift - this->page_shift - 1)); -+ this->bbt[block >> 3] &= ~(0x03 << (block & 0x6)); -+ this->bbt[block >> 3] |= (flag & 0x3) << (block & 0x6); -+} -+ -+static int nand_bbt_get(struct mtd_info *mtd, int page) -+{ -+ struct nand_chip *this = mtd->priv; -+ int block; -+ -+ block = (int)(page >> (this->bbt_erase_shift - this->page_shift - 1)); -+ return (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; -+} -+ -+void nand_enable_clock(void) -+{ -+ //enable_clock(MT65XX_PDN_PERI_NFI, "NAND"); -+} -+ -+void nand_disable_clock(void) -+{ -+ //disable_clock(MT65XX_PDN_PERI_NFI, "NAND"); -+} -+ -+struct nand_ecclayout { -+ __u32 eccbytes; -+ __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE]; -+ __u32 oobavail; -+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; -+}; -+ -+static struct nand_ecclayout *layout; -+ -+static struct nand_ecclayout nand_oob_16 = { -+ .eccbytes = 8, -+ .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, -+ .oobfree = {{1, 6}, {0, 0}} -+}; -+ -+struct nand_ecclayout nand_oob_64 = { -+ .eccbytes = 32, -+ .eccpos = {32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63}, -+ .oobfree = {{1, 7}, {9, 7}, {17, 7}, {25, 6}, {0, 0}} -+}; -+ -+struct nand_ecclayout nand_oob_128 = { -+ .eccbytes = 64, -+ .eccpos = { -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 86, -+ 88, 89, 90, 91, 92, 93, 94, 95, -+ 96, 97, 98, 99, 100, 101, 102, 103, -+ 104, 105, 106, 107, 108, 109, 110, 111, -+ 112, 113, 114, 115, 116, 117, 118, 119, -+ 120, 121, 122, 123, 124, 125, 126, 127}, -+ .oobfree = {{1, 7}, {9, 7}, {17, 7}, {25, 7}, {33, 7}, {41, 7}, {49, 7}, {57, 6}} -+}; -+ -+flashdev_info devinfo; -+ -+void dump_nfi(void) -+{ -+} -+ -+void dump_ecc(void) -+{ -+} -+ -+u32 -+nand_virt_to_phys_add(u32 va) -+{ -+ u32 pageOffset = (va & (PAGE_SIZE - 1)); -+ pgd_t *pgd; -+ pmd_t *pmd; -+ pte_t *pte; -+ u32 pa; -+ -+ if (virt_addr_valid(va)) -+ return __virt_to_phys(va); -+ -+ if (NULL == current) { -+ printk(KERN_ERR "[nand_virt_to_phys_add] ERROR ,current is NULL! \n"); -+ return 0; -+ } -+ -+ if (NULL == current->mm) { -+ printk(KERN_ERR "[nand_virt_to_phys_add] ERROR current->mm is NULL! tgid=0x%x, name=%s \n", current->tgid, current->comm); -+ return 0; -+ } -+ -+ pgd = pgd_offset(current->mm, va); /* what is tsk->mm */ -+ if (pgd_none(*pgd) || pgd_bad(*pgd)) { -+ printk(KERN_ERR "[nand_virt_to_phys_add] ERROR, va=0x%x, pgd invalid! \n", va); -+ return 0; -+ } -+ -+ pmd = pmd_offset((pud_t *)pgd, va); -+ if (pmd_none(*pmd) || pmd_bad(*pmd)) { -+ printk(KERN_ERR "[nand_virt_to_phys_add] ERROR, va=0x%x, pmd invalid! \n", va); -+ return 0; -+ } -+ -+ pte = pte_offset_map(pmd, va); -+ if (pte_present(*pte)) { -+ pa = (pte_val(*pte) & (PAGE_MASK)) | pageOffset; -+ return pa; -+ } -+ -+ printk(KERN_ERR "[nand_virt_to_phys_add] ERROR va=0x%x, pte invalid! \n", va); -+ return 0; -+} -+EXPORT_SYMBOL(nand_virt_to_phys_add); -+ -+bool -+get_device_info(u16 id, u32 ext_id, flashdev_info * pdevinfo) -+{ -+ u32 index; -+ for (index = 0; gen_FlashTable[index].id != 0; index++) { -+ if (id == gen_FlashTable[index].id && ext_id == gen_FlashTable[index].ext_id) { -+ pdevinfo->id = gen_FlashTable[index].id; -+ pdevinfo->ext_id = gen_FlashTable[index].ext_id; -+ pdevinfo->blocksize = gen_FlashTable[index].blocksize; -+ pdevinfo->addr_cycle = gen_FlashTable[index].addr_cycle; -+ pdevinfo->iowidth = gen_FlashTable[index].iowidth; -+ pdevinfo->timmingsetting = gen_FlashTable[index].timmingsetting; -+ pdevinfo->advancedmode = gen_FlashTable[index].advancedmode; -+ pdevinfo->pagesize = gen_FlashTable[index].pagesize; -+ pdevinfo->sparesize = gen_FlashTable[index].sparesize; -+ pdevinfo->totalsize = gen_FlashTable[index].totalsize; -+ memcpy(pdevinfo->devciename, gen_FlashTable[index].devciename, sizeof(pdevinfo->devciename)); -+ printk(KERN_INFO "Device found in MTK table, ID: %x, EXT_ID: %x\n", id, ext_id); -+ -+ goto find; -+ } -+ } -+ -+find: -+ if (0 == pdevinfo->id) { -+ printk(KERN_INFO "Device not found, ID: %x\n", id); -+ return false; -+ } else { -+ return true; -+ } -+} -+ -+static void -+ECC_Config(struct mtk_nand_host_hw *hw,u32 ecc_bit) -+{ -+ u32 u4ENCODESize; -+ u32 u4DECODESize; -+ u32 ecc_bit_cfg = ECC_CNFG_ECC4; -+ -+ switch(ecc_bit){ -+ case 4: -+ ecc_bit_cfg = ECC_CNFG_ECC4; -+ break; -+ case 8: -+ ecc_bit_cfg = ECC_CNFG_ECC8; -+ break; -+ case 10: -+ ecc_bit_cfg = ECC_CNFG_ECC10; -+ break; -+ case 12: -+ ecc_bit_cfg = ECC_CNFG_ECC12; -+ break; -+ default: -+ break; -+ } -+ DRV_WriteReg16(ECC_DECCON_REG16, DEC_DE); -+ do { -+ } while (!DRV_Reg16(ECC_DECIDLE_REG16)); -+ -+ DRV_WriteReg16(ECC_ENCCON_REG16, ENC_DE); -+ do { -+ } while (!DRV_Reg32(ECC_ENCIDLE_REG32)); -+ -+ /* setup FDM register base */ -+ DRV_WriteReg32(ECC_FDMADDR_REG32, NFI_FDM0L_REG32); -+ -+ /* Sector + FDM */ -+ u4ENCODESize = (hw->nand_sec_size + 8) << 3; -+ /* Sector + FDM + YAFFS2 meta data bits */ -+ u4DECODESize = ((hw->nand_sec_size + 8) << 3) + ecc_bit * 13; -+ -+ /* configure ECC decoder && encoder */ -+ DRV_WriteReg32(ECC_DECCNFG_REG32, ecc_bit_cfg | DEC_CNFG_NFI | DEC_CNFG_EMPTY_EN | (u4DECODESize << DEC_CNFG_CODE_SHIFT)); -+ -+ DRV_WriteReg32(ECC_ENCCNFG_REG32, ecc_bit_cfg | ENC_CNFG_NFI | (u4ENCODESize << ENC_CNFG_MSG_SHIFT)); -+ NFI_SET_REG32(ECC_DECCNFG_REG32, DEC_CNFG_EL); -+} -+ -+static void -+ECC_Decode_Start(void) -+{ -+ while (!(DRV_Reg16(ECC_DECIDLE_REG16) & DEC_IDLE)) -+ ; -+ DRV_WriteReg16(ECC_DECCON_REG16, DEC_EN); -+} -+ -+static void -+ECC_Decode_End(void) -+{ -+ while (!(DRV_Reg16(ECC_DECIDLE_REG16) & DEC_IDLE)) -+ ; -+ DRV_WriteReg16(ECC_DECCON_REG16, DEC_DE); -+} -+ -+static void -+ECC_Encode_Start(void) -+{ -+ while (!(DRV_Reg32(ECC_ENCIDLE_REG32) & ENC_IDLE)) -+ ; -+ mb(); -+ DRV_WriteReg16(ECC_ENCCON_REG16, ENC_EN); -+} -+ -+static void -+ECC_Encode_End(void) -+{ -+ /* wait for device returning idle */ -+ while (!(DRV_Reg32(ECC_ENCIDLE_REG32) & ENC_IDLE)) ; -+ mb(); -+ DRV_WriteReg16(ECC_ENCCON_REG16, ENC_DE); -+} -+ -+static bool -+mtk_nand_check_bch_error(struct mtd_info *mtd, u8 * pDataBuf, u32 u4SecIndex, u32 u4PageAddr) -+{ -+ bool bRet = true; -+ u16 u2SectorDoneMask = 1 << u4SecIndex; -+ u32 u4ErrorNumDebug, i, u4ErrNum; -+ u32 timeout = 0xFFFF; -+ // int el; -+ u32 au4ErrBitLoc[6]; -+ u32 u4ErrByteLoc, u4BitOffset; -+ u32 u4ErrBitLoc1th, u4ErrBitLoc2nd; -+ -+ //4 // Wait for Decode Done -+ while (0 == (u2SectorDoneMask & DRV_Reg16(ECC_DECDONE_REG16))) { -+ timeout--; -+ if (0 == timeout) -+ return false; -+ } -+ /* We will manually correct the error bits in the last sector, not all the sectors of the page! */ -+ memset(au4ErrBitLoc, 0x0, sizeof(au4ErrBitLoc)); -+ u4ErrorNumDebug = DRV_Reg32(ECC_DECENUM_REG32); -+ u4ErrNum = DRV_Reg32(ECC_DECENUM_REG32) >> (u4SecIndex << 2); -+ u4ErrNum &= 0xF; -+ -+ if (u4ErrNum) { -+ if (0xF == u4ErrNum) { -+ mtd->ecc_stats.failed++; -+ bRet = false; -+ printk(KERN_ERR"mtk_nand: UnCorrectable at PageAddr=%d\n", u4PageAddr); -+ } else { -+ for (i = 0; i < ((u4ErrNum + 1) >> 1); ++i) { -+ au4ErrBitLoc[i] = DRV_Reg32(ECC_DECEL0_REG32 + i); -+ u4ErrBitLoc1th = au4ErrBitLoc[i] & 0x1FFF; -+ if (u4ErrBitLoc1th < 0x1000) { -+ u4ErrByteLoc = u4ErrBitLoc1th / 8; -+ u4BitOffset = u4ErrBitLoc1th % 8; -+ pDataBuf[u4ErrByteLoc] = pDataBuf[u4ErrByteLoc] ^ (1 << u4BitOffset); -+ mtd->ecc_stats.corrected++; -+ } else { -+ mtd->ecc_stats.failed++; -+ } -+ u4ErrBitLoc2nd = (au4ErrBitLoc[i] >> 16) & 0x1FFF; -+ if (0 != u4ErrBitLoc2nd) { -+ if (u4ErrBitLoc2nd < 0x1000) { -+ u4ErrByteLoc = u4ErrBitLoc2nd / 8; -+ u4BitOffset = u4ErrBitLoc2nd % 8; -+ pDataBuf[u4ErrByteLoc] = pDataBuf[u4ErrByteLoc] ^ (1 << u4BitOffset); -+ mtd->ecc_stats.corrected++; -+ } else { -+ mtd->ecc_stats.failed++; -+ //printk(KERN_ERR"UnCorrectable High ErrLoc=%d\n", au4ErrBitLoc[i]); -+ } -+ } -+ } -+ } -+ if (0 == (DRV_Reg16(ECC_DECFER_REG16) & (1 << u4SecIndex))) -+ bRet = false; -+ } -+ return bRet; -+} -+ -+static bool -+mtk_nand_RFIFOValidSize(u16 u2Size) -+{ -+ u32 timeout = 0xFFFF; -+ while (FIFO_RD_REMAIN(DRV_Reg16(NFI_FIFOSTA_REG16)) < u2Size) { -+ timeout--; -+ if (0 == timeout) -+ return false; -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_WFIFOValidSize(u16 u2Size) -+{ -+ u32 timeout = 0xFFFF; -+ -+ while (FIFO_WR_REMAIN(DRV_Reg16(NFI_FIFOSTA_REG16)) > u2Size) { -+ timeout--; -+ if (0 == timeout) -+ return false; -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_status_ready(u32 u4Status) -+{ -+ u32 timeout = 0xFFFF; -+ -+ while ((DRV_Reg32(NFI_STA_REG32) & u4Status) != 0) { -+ timeout--; -+ if (0 == timeout) -+ return false; -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_reset(void) -+{ -+ int timeout = 0xFFFF; -+ if (DRV_Reg16(NFI_MASTERSTA_REG16)) { -+ mb(); -+ DRV_WriteReg16(NFI_CON_REG16, CON_FIFO_FLUSH | CON_NFI_RST); -+ while (DRV_Reg16(NFI_MASTERSTA_REG16)) { -+ timeout--; -+ if (!timeout) -+ MSG(INIT, "Wait for NFI_MASTERSTA timeout\n"); -+ } -+ } -+ /* issue reset operation */ -+ mb(); -+ DRV_WriteReg16(NFI_CON_REG16, CON_FIFO_FLUSH | CON_NFI_RST); -+ -+ return mtk_nand_status_ready(STA_NFI_FSM_MASK | STA_NAND_BUSY) && mtk_nand_RFIFOValidSize(0) && mtk_nand_WFIFOValidSize(0); -+} -+ -+static void -+mtk_nand_set_mode(u16 u2OpMode) -+{ -+ u16 u2Mode = DRV_Reg16(NFI_CNFG_REG16); -+ u2Mode &= ~CNFG_OP_MODE_MASK; -+ u2Mode |= u2OpMode; -+ DRV_WriteReg16(NFI_CNFG_REG16, u2Mode); -+} -+ -+static void -+mtk_nand_set_autoformat(bool bEnable) -+{ -+ if (bEnable) -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_AUTO_FMT_EN); -+ else -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AUTO_FMT_EN); -+} -+ -+static void -+mtk_nand_configure_fdm(u16 u2FDMSize) -+{ -+ NFI_CLN_REG16(NFI_PAGEFMT_REG16, PAGEFMT_FDM_MASK | PAGEFMT_FDM_ECC_MASK); -+ NFI_SET_REG16(NFI_PAGEFMT_REG16, u2FDMSize << PAGEFMT_FDM_SHIFT); -+ NFI_SET_REG16(NFI_PAGEFMT_REG16, u2FDMSize << PAGEFMT_FDM_ECC_SHIFT); -+} -+ -+static void -+mtk_nand_configure_lock(void) -+{ -+ u32 u4WriteColNOB = 2; -+ u32 u4WriteRowNOB = 3; -+ u32 u4EraseColNOB = 0; -+ u32 u4EraseRowNOB = 3; -+ DRV_WriteReg16(NFI_LOCKANOB_REG16, -+ (u4WriteColNOB << PROG_CADD_NOB_SHIFT) | (u4WriteRowNOB << PROG_RADD_NOB_SHIFT) | (u4EraseColNOB << ERASE_CADD_NOB_SHIFT) | (u4EraseRowNOB << ERASE_RADD_NOB_SHIFT)); -+ -+ if (CHIPVER_ECO_1 == g_u4ChipVer) { -+ int i; -+ for (i = 0; i < 16; ++i) { -+ DRV_WriteReg32(NFI_LOCK00ADD_REG32 + (i << 1), 0xFFFFFFFF); -+ DRV_WriteReg32(NFI_LOCK00FMT_REG32 + (i << 1), 0xFFFFFFFF); -+ } -+ //DRV_WriteReg16(NFI_LOCKANOB_REG16, 0x0); -+ DRV_WriteReg32(NFI_LOCKCON_REG32, 0xFFFFFFFF); -+ DRV_WriteReg16(NFI_LOCK_REG16, NFI_LOCK_ON); -+ } -+} -+ -+static bool -+mtk_nand_pio_ready(void) -+{ -+ int count = 0; -+ while (!(DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1)) { -+ count++; -+ if (count > 0xffff) { -+ printk("PIO_DIRDY timeout\n"); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static bool -+mtk_nand_set_command(u16 command) -+{ -+ mb(); -+ DRV_WriteReg16(NFI_CMD_REG16, command); -+ return mtk_nand_status_ready(STA_CMD_STATE); -+} -+ -+static bool -+mtk_nand_set_address(u32 u4ColAddr, u32 u4RowAddr, u16 u2ColNOB, u16 u2RowNOB) -+{ -+ mb(); -+ DRV_WriteReg32(NFI_COLADDR_REG32, u4ColAddr); -+ DRV_WriteReg32(NFI_ROWADDR_REG32, u4RowAddr); -+ DRV_WriteReg16(NFI_ADDRNOB_REG16, u2ColNOB | (u2RowNOB << ADDR_ROW_NOB_SHIFT)); -+ return mtk_nand_status_ready(STA_ADDR_STATE); -+} -+ -+static void mtk_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) -+{ -+ if (ctrl & NAND_ALE) { -+ mtk_nand_set_address(dat, 0, 1, 0); -+ } else if (ctrl & NAND_CLE) { -+ mtk_nand_reset(); -+ mtk_nand_set_mode(0x6000); -+ mtk_nand_set_command(dat); -+ } -+} -+ -+static bool -+mtk_nand_check_RW_count(u16 u2WriteSize) -+{ -+ u32 timeout = 0xFFFF; -+ u16 u2SecNum = u2WriteSize >> 9; -+ -+ while (ADDRCNTR_CNTR(DRV_Reg16(NFI_ADDRCNTR_REG16)) < u2SecNum) { -+ timeout--; -+ if (0 == timeout) { -+ printk(KERN_INFO "[%s] timeout\n", __FUNCTION__); -+ return false; -+ } -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_ready_for_read(struct nand_chip *nand, u32 u4RowAddr, u32 u4ColAddr, bool full, u8 * buf) -+{ -+ /* Reset NFI HW internal state machine and flush NFI in/out FIFO */ -+ bool bRet = false; -+ u16 sec_num = 1 << (nand->page_shift - 9); -+ u32 col_addr = u4ColAddr; -+ u32 colnob = 2, rownob = devinfo.addr_cycle - 2; -+ if (nand->options & NAND_BUSWIDTH_16) -+ col_addr /= 2; -+ -+ if (!mtk_nand_reset()) -+ goto cleanup; -+ if (g_bHwEcc) { -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } else { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } -+ -+ mtk_nand_set_mode(CNFG_OP_READ); -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN); -+ DRV_WriteReg16(NFI_CON_REG16, sec_num << CON_NFI_SEC_SHIFT); -+ -+ if (full) { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ -+ if (g_bHwEcc) -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ else -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } else { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ } -+ -+ mtk_nand_set_autoformat(full); -+ if (full) -+ if (g_bHwEcc) -+ ECC_Decode_Start(); -+ if (!mtk_nand_set_command(NAND_CMD_READ0)) -+ goto cleanup; -+ if (!mtk_nand_set_address(col_addr, u4RowAddr, colnob, rownob)) -+ goto cleanup; -+ if (!mtk_nand_set_command(NAND_CMD_READSTART)) -+ goto cleanup; -+ if (!mtk_nand_status_ready(STA_NAND_BUSY)) -+ goto cleanup; -+ -+ bRet = true; -+ -+cleanup: -+ return bRet; -+} -+ -+static bool -+mtk_nand_ready_for_write(struct nand_chip *nand, u32 u4RowAddr, u32 col_addr, bool full, u8 * buf) -+{ -+ bool bRet = false; -+ u32 sec_num = 1 << (nand->page_shift - 9); -+ u32 colnob = 2, rownob = devinfo.addr_cycle - 2; -+ if (nand->options & NAND_BUSWIDTH_16) -+ col_addr /= 2; -+ -+ /* Reset NFI HW internal state machine and flush NFI in/out FIFO */ -+ if (!mtk_nand_reset()) -+ return false; -+ -+ mtk_nand_set_mode(CNFG_OP_PRGM); -+ -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_READ_EN); -+ -+ DRV_WriteReg16(NFI_CON_REG16, sec_num << CON_NFI_SEC_SHIFT); -+ -+ if (full) { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ if (g_bHwEcc) -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ else -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } else { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ } -+ -+ mtk_nand_set_autoformat(full); -+ -+ if (full) -+ if (g_bHwEcc) -+ ECC_Encode_Start(); -+ -+ if (!mtk_nand_set_command(NAND_CMD_SEQIN)) -+ goto cleanup; -+ //1 FIXED ME: For Any Kind of AddrCycle -+ if (!mtk_nand_set_address(col_addr, u4RowAddr, colnob, rownob)) -+ goto cleanup; -+ -+ if (!mtk_nand_status_ready(STA_NAND_BUSY)) -+ goto cleanup; -+ -+ bRet = true; -+ -+cleanup: -+ return bRet; -+} -+ -+static bool -+mtk_nand_check_dececc_done(u32 u4SecNum) -+{ -+ u32 timeout, dec_mask; -+ -+ timeout = 0xffff; -+ dec_mask = (1 << u4SecNum) - 1; -+ while ((dec_mask != DRV_Reg(ECC_DECDONE_REG16)) && timeout > 0) -+ timeout--; -+ if (timeout == 0) { -+ MSG(VERIFY, "ECC_DECDONE: timeout\n"); -+ return false; -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_mcu_read_data(u8 * buf, u32 length) -+{ -+ int timeout = 0xffff; -+ u32 i; -+ u32 *buf32 = (u32 *) buf; -+ if ((u32) buf % 4 || length % 4) -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ else -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ -+ //DRV_WriteReg32(NFI_STRADDR_REG32, 0); -+ mb(); -+ NFI_SET_REG16(NFI_CON_REG16, CON_NFI_BRD); -+ -+ if ((u32) buf % 4 || length % 4) { -+ for (i = 0; (i < (length)) && (timeout > 0);) { -+ if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { -+ *buf++ = (u8) DRV_Reg32(NFI_DATAR_REG32); -+ i++; -+ } else { -+ timeout--; -+ } -+ if (0 == timeout) { -+ printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); -+ dump_nfi(); -+ return false; -+ } -+ } -+ } else { -+ for (i = 0; (i < (length >> 2)) && (timeout > 0);) { -+ if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { -+ *buf32++ = DRV_Reg32(NFI_DATAR_REG32); -+ i++; -+ } else { -+ timeout--; -+ } -+ if (0 == timeout) { -+ printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); -+ dump_nfi(); -+ return false; -+ } -+ } -+ } -+ return true; -+} -+ -+static bool -+mtk_nand_read_page_data(struct mtd_info *mtd, u8 * pDataBuf, u32 u4Size) -+{ -+ return mtk_nand_mcu_read_data(pDataBuf, u4Size); -+} -+ -+static bool -+mtk_nand_mcu_write_data(struct mtd_info *mtd, const u8 * buf, u32 length) -+{ -+ u32 timeout = 0xFFFF; -+ u32 i; -+ u32 *pBuf32; -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ mb(); -+ NFI_SET_REG16(NFI_CON_REG16, CON_NFI_BWR); -+ pBuf32 = (u32 *) buf; -+ -+ if ((u32) buf % 4 || length % 4) -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ else -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ -+ if ((u32) buf % 4 || length % 4) { -+ for (i = 0; (i < (length)) && (timeout > 0);) { -+ if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { -+ DRV_WriteReg32(NFI_DATAW_REG32, *buf++); -+ i++; -+ } else { -+ timeout--; -+ } -+ if (0 == timeout) { -+ printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); -+ dump_nfi(); -+ return false; -+ } -+ } -+ } else { -+ for (i = 0; (i < (length >> 2)) && (timeout > 0);) { -+ if (DRV_Reg16(NFI_PIO_DIRDY_REG16) & 1) { -+ DRV_WriteReg32(NFI_DATAW_REG32, *pBuf32++); -+ i++; -+ } else { -+ timeout--; -+ } -+ if (0 == timeout) { -+ printk(KERN_ERR "[%s] timeout\n", __FUNCTION__); -+ dump_nfi(); -+ return false; -+ } -+ } -+ } -+ -+ return true; -+} -+ -+static bool -+mtk_nand_write_page_data(struct mtd_info *mtd, u8 * buf, u32 size) -+{ -+ return mtk_nand_mcu_write_data(mtd, buf, size); -+} -+ -+static void -+mtk_nand_read_fdm_data(u8 * pDataBuf, u32 u4SecNum) -+{ -+ u32 i; -+ u32 *pBuf32 = (u32 *) pDataBuf; -+ -+ if (pBuf32) { -+ for (i = 0; i < u4SecNum; ++i) { -+ *pBuf32++ = DRV_Reg32(NFI_FDM0L_REG32 + (i << 1)); -+ *pBuf32++ = DRV_Reg32(NFI_FDM0M_REG32 + (i << 1)); -+ } -+ } -+} -+ -+static u8 fdm_buf[64]; -+static void -+mtk_nand_write_fdm_data(struct nand_chip *chip, u8 * pDataBuf, u32 u4SecNum) -+{ -+ u32 i, j; -+ u8 checksum = 0; -+ bool empty = true; -+ struct nand_oobfree *free_entry; -+ u32 *pBuf32; -+ -+ memcpy(fdm_buf, pDataBuf, u4SecNum * 8); -+ -+ free_entry = layout->oobfree; -+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free_entry[i].length; i++) { -+ for (j = 0; j < free_entry[i].length; j++) { -+ if (pDataBuf[free_entry[i].offset + j] != 0xFF) -+ empty = false; -+ checksum ^= pDataBuf[free_entry[i].offset + j]; -+ } -+ } -+ -+ if (!empty) { -+ fdm_buf[free_entry[i - 1].offset + free_entry[i - 1].length] = checksum; -+ } -+ -+ pBuf32 = (u32 *) fdm_buf; -+ for (i = 0; i < u4SecNum; ++i) { -+ DRV_WriteReg32(NFI_FDM0L_REG32 + (i << 1), *pBuf32++); -+ DRV_WriteReg32(NFI_FDM0M_REG32 + (i << 1), *pBuf32++); -+ } -+} -+ -+static void -+mtk_nand_stop_read(void) -+{ -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BRD); -+ mtk_nand_reset(); -+ if (g_bHwEcc) -+ ECC_Decode_End(); -+ DRV_WriteReg16(NFI_INTR_EN_REG16, 0); -+} -+ -+static void -+mtk_nand_stop_write(void) -+{ -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BWR); -+ if (g_bHwEcc) -+ ECC_Encode_End(); -+ DRV_WriteReg16(NFI_INTR_EN_REG16, 0); -+} -+ -+bool -+mtk_nand_exec_read_page(struct mtd_info *mtd, u32 u4RowAddr, u32 u4PageSize, u8 * pPageBuf, u8 * pFDMBuf) -+{ -+ u8 *buf; -+ bool bRet = true; -+ struct nand_chip *nand = mtd->priv; -+ u32 u4SecNum = u4PageSize >> 9; -+ -+ buf = pPageBuf; -+ if (mtk_nand_ready_for_read(nand, u4RowAddr, 0, true, buf)) { -+ int j; -+ for (j = 0 ; j < u4SecNum; j++) { -+ if (!mtk_nand_read_page_data(mtd, buf+j*512, 512)) -+ bRet = false; -+ if(g_bHwEcc && !mtk_nand_check_dececc_done(j+1)) -+ bRet = false; -+ if(g_bHwEcc && !mtk_nand_check_bch_error(mtd, buf+j*512, j, u4RowAddr)) -+ bRet = false; -+ } -+ if (!mtk_nand_status_ready(STA_NAND_BUSY)) -+ bRet = false; -+ -+ mtk_nand_read_fdm_data(pFDMBuf, u4SecNum); -+ mtk_nand_stop_read(); -+ } -+ -+ return bRet; -+} -+ -+int -+mtk_nand_exec_write_page(struct mtd_info *mtd, u32 u4RowAddr, u32 u4PageSize, u8 * pPageBuf, u8 * pFDMBuf) -+{ -+ struct nand_chip *chip = mtd->priv; -+ u32 u4SecNum = u4PageSize >> 9; -+ u8 *buf; -+ u8 status; -+ -+ MSG(WRITE, "mtk_nand_exec_write_page, page: 0x%x\n", u4RowAddr); -+ -+ buf = pPageBuf; -+ -+ if (mtk_nand_ready_for_write(chip, u4RowAddr, 0, true, buf)) { -+ mtk_nand_write_fdm_data(chip, pFDMBuf, u4SecNum); -+ (void)mtk_nand_write_page_data(mtd, buf, u4PageSize); -+ (void)mtk_nand_check_RW_count(u4PageSize); -+ mtk_nand_stop_write(); -+ (void)mtk_nand_set_command(NAND_CMD_PAGEPROG); -+ while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) ; -+ } -+ -+ status = chip->waitfunc(mtd, chip); -+ if (status & NAND_STATUS_FAIL) -+ return -EIO; -+ return 0; -+} -+ -+static int -+get_start_end_block(struct mtd_info *mtd, int block, int *start_blk, int *end_blk) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int i; -+ -+ *start_blk = 0; -+ for (i = 0; i <= part_num; i++) -+ { -+ if (i == part_num) -+ { -+ // try the last reset partition -+ *end_blk = (chip->chipsize >> chip->phys_erase_shift) - 1; -+ if (*start_blk <= *end_blk) -+ { -+ if ((block >= *start_blk) && (block <= *end_blk)) -+ break; -+ } -+ } -+ // skip All partition entry -+ else if (g_pasStatic_Partition[i].size == MTDPART_SIZ_FULL) -+ { -+ continue; -+ } -+ *end_blk = *start_blk + (g_pasStatic_Partition[i].size >> chip->phys_erase_shift) - 1; -+ if ((block >= *start_blk) && (block <= *end_blk)) -+ break; -+ *start_blk = *end_blk + 1; -+ } -+ if (*start_blk > *end_blk) -+ { -+ return -1; -+ } -+ return 0; -+} -+ -+static int -+block_remap(struct mtd_info *mtd, int block) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int start_blk, end_blk; -+ int j, block_offset; -+ int bad_block = 0; -+ -+ if (chip->bbt == NULL) { -+ printk("ERROR!! no bbt table for block_remap\n"); -+ return -1; -+ } -+ -+ if (get_start_end_block(mtd, block, &start_blk, &end_blk) < 0) { -+ printk("ERROR!! can not find start_blk and end_blk\n"); -+ return -1; -+ } -+ -+ block_offset = block - start_blk; -+ for (j = start_blk; j <= end_blk;j++) { -+ if (((chip->bbt[j >> 2] >> ((j<<1) & 0x6)) & 0x3) == 0x0) { -+ if (!block_offset) -+ break; -+ block_offset--; -+ } else { -+ bad_block++; -+ } -+ } -+ if (j <= end_blk) { -+ return j; -+ } else { -+ // remap to the bad block -+ for (j = end_blk; bad_block > 0; j--) -+ { -+ if (((chip->bbt[j >> 2] >> ((j<<1) & 0x6)) & 0x3) != 0x0) -+ { -+ bad_block--; -+ if (bad_block <= block_offset) -+ return j; -+ } -+ } -+ } -+ -+ printk("Error!! block_remap error\n"); -+ return -1; -+} -+ -+int -+check_block_remap(struct mtd_info *mtd, int block) -+{ -+ if (shift_on_bbt) -+ return block_remap(mtd, block); -+ else -+ return block; -+} -+EXPORT_SYMBOL(check_block_remap); -+ -+ -+static int -+write_next_on_fail(struct mtd_info *mtd, char *write_buf, int page, int * to_blk) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int i, j, to_page = 0, first_page; -+ char *buf, *oob; -+ int start_blk = 0, end_blk; -+ int mapped_block; -+ int page_per_block_bit = chip->phys_erase_shift - chip->page_shift; -+ int block = page >> page_per_block_bit; -+ -+ // find next available block in the same MTD partition -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ -+ get_start_end_block(mtd, block, &start_blk, &end_blk); -+ -+ buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL | GFP_DMA); -+ if (buf == NULL) -+ return -1; -+ -+ oob = buf + mtd->writesize; -+ for ((*to_blk) = block + 1; (*to_blk) <= end_blk ; (*to_blk)++) { -+ if (nand_bbt_get(mtd, (*to_blk) << page_per_block_bit) == 0) { -+ int status; -+ status = mtk_nand_erase_hw(mtd, (*to_blk) << page_per_block_bit); -+ if (status & NAND_STATUS_FAIL) { -+ mtk_nand_block_markbad_hw(mtd, (*to_blk) << chip->phys_erase_shift); -+ nand_bbt_set(mtd, (*to_blk) << page_per_block_bit, 0x3); -+ } else { -+ /* good block */ -+ to_page = (*to_blk) << page_per_block_bit; -+ break; -+ } -+ } -+ } -+ -+ if (!to_page) { -+ kfree(buf); -+ return -1; -+ } -+ -+ first_page = (page >> page_per_block_bit) << page_per_block_bit; -+ for (i = 0; i < (1 << page_per_block_bit); i++) { -+ if ((first_page + i) != page) { -+ mtk_nand_read_oob_hw(mtd, chip, (first_page+i)); -+ for (j = 0; j < mtd->oobsize; j++) -+ if (chip->oob_poi[j] != (unsigned char)0xff) -+ break; -+ if (j < mtd->oobsize) { -+ mtk_nand_exec_read_page(mtd, (first_page+i), mtd->writesize, buf, oob); -+ memset(oob, 0xff, mtd->oobsize); -+ if (mtk_nand_exec_write_page(mtd, to_page + i, mtd->writesize, (u8 *)buf, oob) != 0) { -+ int ret, new_blk = 0; -+ nand_bbt_set(mtd, to_page, 0x3); -+ ret = write_next_on_fail(mtd, buf, to_page + i, &new_blk); -+ if (ret) { -+ kfree(buf); -+ mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); -+ return ret; -+ } -+ mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); -+ *to_blk = new_blk; -+ to_page = ((*to_blk) << page_per_block_bit); -+ } -+ } -+ } else { -+ memset(chip->oob_poi, 0xff, mtd->oobsize); -+ if (mtk_nand_exec_write_page(mtd, to_page + i, mtd->writesize, (u8 *)write_buf, chip->oob_poi) != 0) { -+ int ret, new_blk = 0; -+ nand_bbt_set(mtd, to_page, 0x3); -+ ret = write_next_on_fail(mtd, write_buf, to_page + i, &new_blk); -+ if (ret) { -+ kfree(buf); -+ mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); -+ return ret; -+ } -+ mtk_nand_block_markbad_hw(mtd, to_page << chip->page_shift); -+ *to_blk = new_blk; -+ to_page = ((*to_blk) << page_per_block_bit); -+ } -+ } -+ } -+ -+ kfree(buf); -+ -+ return 0; -+} -+ -+static int -+mtk_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, -+ int data_len, const u8 * buf, int oob_required, int page, int raw) -+{ -+ int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ int block = page / page_per_block; -+ u16 page_in_block = page % page_per_block; -+ int mapped_block = block; -+ -+#if defined(MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+ // write bad index into oob -+ if (mapped_block != block) -+ set_bad_index_to_oob(chip->oob_poi, block); -+ else -+ set_bad_index_to_oob(chip->oob_poi, FAKE_INDEX); -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } -+#endif -+ do { -+ if (mtk_nand_exec_write_page(mtd, page_in_block + mapped_block * page_per_block, mtd->writesize, (u8 *)buf, chip->oob_poi)) { -+ MSG(INIT, "write fail at block: 0x%x, page: 0x%x\n", mapped_block, page_in_block); -+#if defined(MTK_NAND_BMT) -+ if (update_bmt((page_in_block + mapped_block * page_per_block) << chip->page_shift, UPDATE_WRITE_FAIL, (u8 *) buf, chip->oob_poi)) { -+ MSG(INIT, "Update BMT success\n"); -+ return 0; -+ } else { -+ MSG(INIT, "Update BMT fail\n"); -+ return -EIO; -+ } -+#else -+ { -+ int new_blk; -+ nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); -+ if (write_next_on_fail(mtd, (char *)buf, page_in_block + mapped_block * page_per_block, &new_blk) != 0) -+ { -+ mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); -+ return NAND_STATUS_FAIL; -+ } -+ mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); -+ break; -+ } -+#endif -+ } else -+ break; -+ } while(1); -+ -+ return 0; -+} -+ -+static void -+mtk_nand_command_bp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) -+{ -+ struct nand_chip *nand = mtd->priv; -+ -+ switch (command) { -+ case NAND_CMD_SEQIN: -+ memset(g_kCMD.au1OOB, 0xFF, sizeof(g_kCMD.au1OOB)); -+ g_kCMD.pDataBuf = NULL; -+ g_kCMD.u4RowAddr = page_addr; -+ g_kCMD.u4ColAddr = column; -+ break; -+ -+ case NAND_CMD_PAGEPROG: -+ if (g_kCMD.pDataBuf || (0xFF != g_kCMD.au1OOB[nand_badblock_offset])) { -+ u8 *pDataBuf = g_kCMD.pDataBuf ? g_kCMD.pDataBuf : nand->buffers->databuf; -+ mtk_nand_exec_write_page(mtd, g_kCMD.u4RowAddr, mtd->writesize, pDataBuf, g_kCMD.au1OOB); -+ g_kCMD.u4RowAddr = (u32) - 1; -+ g_kCMD.u4OOBRowAddr = (u32) - 1; -+ } -+ break; -+ -+ case NAND_CMD_READOOB: -+ g_kCMD.u4RowAddr = page_addr; -+ g_kCMD.u4ColAddr = column + mtd->writesize; -+ break; -+ -+ case NAND_CMD_READ0: -+ g_kCMD.u4RowAddr = page_addr; -+ g_kCMD.u4ColAddr = column; -+ break; -+ -+ case NAND_CMD_ERASE1: -+ nand->state=FL_ERASING; -+ (void)mtk_nand_reset(); -+ mtk_nand_set_mode(CNFG_OP_ERASE); -+ (void)mtk_nand_set_command(NAND_CMD_ERASE1); -+ (void)mtk_nand_set_address(0, page_addr, 0, devinfo.addr_cycle - 2); -+ break; -+ -+ case NAND_CMD_ERASE2: -+ (void)mtk_nand_set_command(NAND_CMD_ERASE2); -+ while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) -+ ; -+ break; -+ -+ case NAND_CMD_STATUS: -+ (void)mtk_nand_reset(); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_BYTE_RW); -+ mtk_nand_set_mode(CNFG_OP_SRD); -+ mtk_nand_set_mode(CNFG_READ_EN); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ (void)mtk_nand_set_command(NAND_CMD_STATUS); -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_NOB_MASK); -+ mb(); -+ DRV_WriteReg16(NFI_CON_REG16, CON_NFI_SRD | (1 << CON_NFI_NOB_SHIFT)); -+ g_bcmdstatus = true; -+ break; -+ -+ case NAND_CMD_RESET: -+ (void)mtk_nand_reset(); -+ DRV_WriteReg16(NFI_INTR_EN_REG16, INTR_RST_DONE_EN); -+ (void)mtk_nand_set_command(NAND_CMD_RESET); -+ DRV_WriteReg16(NFI_BASE+0x44, 0xF1); -+ while(!(DRV_Reg16(NFI_INTR_REG16)&INTR_RST_DONE_EN)) -+ ; -+ break; -+ -+ case NAND_CMD_READID: -+ mtk_nand_reset(); -+ /* Disable HW ECC */ -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN | CNFG_BYTE_RW); -+ (void)mtk_nand_reset(); -+ mb(); -+ mtk_nand_set_mode(CNFG_OP_SRD); -+ (void)mtk_nand_set_command(NAND_CMD_READID); -+ (void)mtk_nand_set_address(0, 0, 1, 0); -+ DRV_WriteReg16(NFI_CON_REG16, CON_NFI_SRD); -+ while (DRV_Reg32(NFI_STA_REG32) & STA_DATAR_STATE) -+ ; -+ break; -+ -+ default: -+ BUG(); -+ break; -+ } -+} -+ -+static void -+mtk_nand_select_chip(struct mtd_info *mtd, int chip) -+{ -+ if ((chip == -1) && (false == g_bInitDone)) { -+ struct nand_chip *nand = mtd->priv; -+ struct mtk_nand_host *host = nand->priv; -+ struct mtk_nand_host_hw *hw = host->hw; -+ u32 spare_per_sector = mtd->oobsize / (mtd->writesize / 512); -+ u32 ecc_bit = 4; -+ u32 spare_bit = PAGEFMT_SPARE_16; -+ -+ if (spare_per_sector >= 28) { -+ spare_bit = PAGEFMT_SPARE_28; -+ ecc_bit = 12; -+ spare_per_sector = 28; -+ } else if (spare_per_sector >= 27) { -+ spare_bit = PAGEFMT_SPARE_27; -+ ecc_bit = 8; -+ spare_per_sector = 27; -+ } else if (spare_per_sector >= 26) { -+ spare_bit = PAGEFMT_SPARE_26; -+ ecc_bit = 8; -+ spare_per_sector = 26; -+ } else if (spare_per_sector >= 16) { -+ spare_bit = PAGEFMT_SPARE_16; -+ ecc_bit = 4; -+ spare_per_sector = 16; -+ } else { -+ MSG(INIT, "[NAND]: NFI not support oobsize: %x\n", spare_per_sector); -+ ASSERT(0); -+ } -+ mtd->oobsize = spare_per_sector*(mtd->writesize/512); -+ MSG(INIT, "[NAND]select ecc bit:%d, sparesize :%d spare_per_sector=%d\n",ecc_bit,mtd->oobsize,spare_per_sector); -+ /* Setup PageFormat */ -+ if (4096 == mtd->writesize) { -+ NFI_SET_REG16(NFI_PAGEFMT_REG16, (spare_bit << PAGEFMT_SPARE_SHIFT) | PAGEFMT_4K); -+ nand->cmdfunc = mtk_nand_command_bp; -+ } else if (2048 == mtd->writesize) { -+ NFI_SET_REG16(NFI_PAGEFMT_REG16, (spare_bit << PAGEFMT_SPARE_SHIFT) | PAGEFMT_2K); -+ nand->cmdfunc = mtk_nand_command_bp; -+ } -+ ECC_Config(hw,ecc_bit); -+ g_bInitDone = true; -+ } -+ switch (chip) { -+ case -1: -+ break; -+ case 0: -+ case 1: -+ /* Jun Shen, 2011.04.13 */ -+ /* Note: MT6577 EVB NAND is mounted on CS0, but FPGA is CS1 */ -+ DRV_WriteReg16(NFI_CSEL_REG16, chip); -+ /* Jun Shen, 2011.04.13 */ -+ break; -+ } -+} -+ -+static uint8_t -+mtk_nand_read_byte(struct mtd_info *mtd) -+{ -+ uint8_t retval = 0; -+ -+ if (!mtk_nand_pio_ready()) { -+ printk("pio ready timeout\n"); -+ retval = false; -+ } -+ -+ if (g_bcmdstatus) { -+ retval = DRV_Reg8(NFI_DATAR_REG32); -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_NOB_MASK); -+ mtk_nand_reset(); -+ if (g_bHwEcc) { -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } else { -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ } -+ g_bcmdstatus = false; -+ } else -+ retval = DRV_Reg8(NFI_DATAR_REG32); -+ -+ return retval; -+} -+ -+static void -+mtk_nand_read_buf(struct mtd_info *mtd, uint8_t * buf, int len) -+{ -+ struct nand_chip *nand = (struct nand_chip *)mtd->priv; -+ struct NAND_CMD *pkCMD = &g_kCMD; -+ u32 u4ColAddr = pkCMD->u4ColAddr; -+ u32 u4PageSize = mtd->writesize; -+ -+ if (u4ColAddr < u4PageSize) { -+ if ((u4ColAddr == 0) && (len >= u4PageSize)) { -+ mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, buf, pkCMD->au1OOB); -+ if (len > u4PageSize) { -+ u32 u4Size = min(len - u4PageSize, sizeof(pkCMD->au1OOB)); -+ memcpy(buf + u4PageSize, pkCMD->au1OOB, u4Size); -+ } -+ } else { -+ mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, nand->buffers->databuf, pkCMD->au1OOB); -+ memcpy(buf, nand->buffers->databuf + u4ColAddr, len); -+ } -+ pkCMD->u4OOBRowAddr = pkCMD->u4RowAddr; -+ } else { -+ u32 u4Offset = u4ColAddr - u4PageSize; -+ u32 u4Size = min(len - u4Offset, sizeof(pkCMD->au1OOB)); -+ if (pkCMD->u4OOBRowAddr != pkCMD->u4RowAddr) { -+ mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, nand->buffers->databuf, pkCMD->au1OOB); -+ pkCMD->u4OOBRowAddr = pkCMD->u4RowAddr; -+ } -+ memcpy(buf, pkCMD->au1OOB + u4Offset, u4Size); -+ } -+ pkCMD->u4ColAddr += len; -+} -+ -+static void -+mtk_nand_write_buf(struct mtd_info *mtd, const uint8_t * buf, int len) -+{ -+ struct NAND_CMD *pkCMD = &g_kCMD; -+ u32 u4ColAddr = pkCMD->u4ColAddr; -+ u32 u4PageSize = mtd->writesize; -+ int i4Size, i; -+ -+ if (u4ColAddr >= u4PageSize) { -+ u32 u4Offset = u4ColAddr - u4PageSize; -+ u8 *pOOB = pkCMD->au1OOB + u4Offset; -+ i4Size = min(len, (int)(sizeof(pkCMD->au1OOB) - u4Offset)); -+ for (i = 0; i < i4Size; i++) { -+ pOOB[i] &= buf[i]; -+ } -+ } else { -+ pkCMD->pDataBuf = (u8 *) buf; -+ } -+ -+ pkCMD->u4ColAddr += len; -+} -+ -+static int -+mtk_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t * buf, int oob_required, int page) -+{ -+ mtk_nand_write_buf(mtd, buf, mtd->writesize); -+ mtk_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); -+ return 0; -+} -+ -+static int -+mtk_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, int oob_required, int page) -+{ -+ struct NAND_CMD *pkCMD = &g_kCMD; -+ u32 u4ColAddr = pkCMD->u4ColAddr; -+ u32 u4PageSize = mtd->writesize; -+ -+ if (u4ColAddr == 0) { -+ mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, buf, chip->oob_poi); -+ pkCMD->u4ColAddr += u4PageSize + mtd->oobsize; -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, u8 * buf, int page) -+{ -+ int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ int block = page / page_per_block; -+ u16 page_in_block = page % page_per_block; -+ int mapped_block = block; -+ -+#if defined (MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+ if (mtk_nand_exec_read_page(mtd, page_in_block + mapped_block * page_per_block, -+ mtd->writesize, buf, chip->oob_poi)) -+ return 0; -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } -+ -+ if (mtk_nand_exec_read_page(mtd, page_in_block + mapped_block * page_per_block, mtd->writesize, buf, chip->oob_poi)) -+ return 0; -+ else -+ return -EIO; -+#endif -+} -+ -+int -+mtk_nand_erase_hw(struct mtd_info *mtd, int page) -+{ -+ struct nand_chip *chip = (struct nand_chip *)mtd->priv; -+ -+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); -+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); -+ -+ return chip->waitfunc(mtd, chip); -+} -+ -+static int -+mtk_nand_erase(struct mtd_info *mtd, int page) -+{ -+ // get mapping -+ struct nand_chip *chip = mtd->priv; -+ int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ int page_in_block = page % page_per_block; -+ int block = page / page_per_block; -+ int mapped_block = block; -+ -+#if defined(MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } -+#endif -+ -+ do { -+ int status = mtk_nand_erase_hw(mtd, page_in_block + page_per_block * mapped_block); -+ -+ if (status & NAND_STATUS_FAIL) { -+#if defined (MTK_NAND_BMT) -+ if (update_bmt( (page_in_block + mapped_block * page_per_block) << chip->page_shift, -+ UPDATE_ERASE_FAIL, NULL, NULL)) -+ { -+ MSG(INIT, "Erase fail at block: 0x%x, update BMT success\n", mapped_block); -+ return 0; -+ } else { -+ MSG(INIT, "Erase fail at block: 0x%x, update BMT fail\n", mapped_block); -+ return NAND_STATUS_FAIL; -+ } -+#else -+ mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); -+ nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } else -+ return NAND_STATUS_FAIL; -+#endif -+ } else -+ break; -+ } while(1); -+ -+ return 0; -+} -+ -+static int -+mtk_nand_read_oob_raw(struct mtd_info *mtd, uint8_t * buf, int page_addr, int len) -+{ -+ struct nand_chip *chip = (struct nand_chip *)mtd->priv; -+ u32 col_addr = 0; -+ u32 sector = 0; -+ int res = 0; -+ u32 colnob = 2, rawnob = devinfo.addr_cycle - 2; -+ int randomread = 0; -+ int read_len = 0; -+ int sec_num = 1<<(chip->page_shift-9); -+ int spare_per_sector = mtd->oobsize/sec_num; -+ -+ if (len > NAND_MAX_OOBSIZE || len % OOB_AVAI_PER_SECTOR || !buf) { -+ printk(KERN_WARNING "[%s] invalid parameter, len: %d, buf: %p\n", __FUNCTION__, len, buf); -+ return -EINVAL; -+ } -+ if (len > spare_per_sector) -+ randomread = 1; -+ if (!randomread || !(devinfo.advancedmode & RAMDOM_READ)) { -+ while (len > 0) { -+ read_len = min(len, spare_per_sector); -+ col_addr = NAND_SECTOR_SIZE + sector * (NAND_SECTOR_SIZE + spare_per_sector); // TODO: Fix this hard-code 16 -+ if (!mtk_nand_ready_for_read(chip, page_addr, col_addr, false, NULL)) { -+ printk(KERN_WARNING "mtk_nand_ready_for_read return failed\n"); -+ res = -EIO; -+ goto error; -+ } -+ if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { -+ printk(KERN_WARNING "mtk_nand_mcu_read_data return failed\n"); -+ res = -EIO; -+ goto error; -+ } -+ mtk_nand_check_RW_count(read_len); -+ mtk_nand_stop_read(); -+ sector++; -+ len -= read_len; -+ } -+ } else { -+ col_addr = NAND_SECTOR_SIZE; -+ if (chip->options & NAND_BUSWIDTH_16) -+ col_addr /= 2; -+ if (!mtk_nand_reset()) -+ goto error; -+ mtk_nand_set_mode(0x6000); -+ NFI_SET_REG16(NFI_CNFG_REG16, CNFG_READ_EN); -+ DRV_WriteReg16(NFI_CON_REG16, 4 << CON_NFI_SEC_SHIFT); -+ -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_AHB); -+ NFI_CLN_REG16(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ -+ mtk_nand_set_autoformat(false); -+ -+ if (!mtk_nand_set_command(NAND_CMD_READ0)) -+ goto error; -+ //1 FIXED ME: For Any Kind of AddrCycle -+ if (!mtk_nand_set_address(col_addr, page_addr, colnob, rawnob)) -+ goto error; -+ if (!mtk_nand_set_command(NAND_CMD_READSTART)) -+ goto error; -+ if (!mtk_nand_status_ready(STA_NAND_BUSY)) -+ goto error; -+ read_len = min(len, spare_per_sector); -+ if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { -+ printk(KERN_WARNING "mtk_nand_mcu_read_data return failed first 16\n"); -+ res = -EIO; -+ goto error; -+ } -+ sector++; -+ len -= read_len; -+ mtk_nand_stop_read(); -+ while (len > 0) { -+ read_len = min(len, spare_per_sector); -+ if (!mtk_nand_set_command(0x05)) -+ goto error; -+ col_addr = NAND_SECTOR_SIZE + sector * (NAND_SECTOR_SIZE + spare_per_sector); -+ if (chip->options & NAND_BUSWIDTH_16) -+ col_addr /= 2; -+ DRV_WriteReg32(NFI_COLADDR_REG32, col_addr); -+ DRV_WriteReg16(NFI_ADDRNOB_REG16, 2); -+ DRV_WriteReg16(NFI_CON_REG16, 4 << CON_NFI_SEC_SHIFT); -+ if (!mtk_nand_status_ready(STA_ADDR_STATE)) -+ goto error; -+ if (!mtk_nand_set_command(0xE0)) -+ goto error; -+ if (!mtk_nand_status_ready(STA_NAND_BUSY)) -+ goto error; -+ if (!mtk_nand_mcu_read_data(buf + spare_per_sector * sector, read_len)) { -+ printk(KERN_WARNING "mtk_nand_mcu_read_data return failed first 16\n"); -+ res = -EIO; -+ goto error; -+ } -+ mtk_nand_stop_read(); -+ sector++; -+ len -= read_len; -+ } -+ } -+error: -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BRD); -+ return res; -+} -+ -+static int -+mtk_nand_write_oob_raw(struct mtd_info *mtd, const uint8_t * buf, int page_addr, int len) -+{ -+ struct nand_chip *chip = mtd->priv; -+ u32 col_addr = 0; -+ u32 sector = 0; -+ int write_len = 0; -+ int status; -+ int sec_num = 1<<(chip->page_shift-9); -+ int spare_per_sector = mtd->oobsize/sec_num; -+ -+ if (len > NAND_MAX_OOBSIZE || len % OOB_AVAI_PER_SECTOR || !buf) { -+ printk(KERN_WARNING "[%s] invalid parameter, len: %d, buf: %p\n", __FUNCTION__, len, buf); -+ return -EINVAL; -+ } -+ -+ while (len > 0) { -+ write_len = min(len, spare_per_sector); -+ col_addr = sector * (NAND_SECTOR_SIZE + spare_per_sector) + NAND_SECTOR_SIZE; -+ if (!mtk_nand_ready_for_write(chip, page_addr, col_addr, false, NULL)) -+ return -EIO; -+ if (!mtk_nand_mcu_write_data(mtd, buf + sector * spare_per_sector, write_len)) -+ return -EIO; -+ (void)mtk_nand_check_RW_count(write_len); -+ NFI_CLN_REG16(NFI_CON_REG16, CON_NFI_BWR); -+ (void)mtk_nand_set_command(NAND_CMD_PAGEPROG); -+ while (DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY) -+ ; -+ status = chip->waitfunc(mtd, chip); -+ if (status & NAND_STATUS_FAIL) { -+ printk(KERN_INFO "status: %d\n", status); -+ return -EIO; -+ } -+ len -= write_len; -+ sector++; -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_nand_write_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page) -+{ -+ int i, iter; -+ int sec_num = 1<<(chip->page_shift-9); -+ int spare_per_sector = mtd->oobsize/sec_num; -+ -+ memcpy(local_oob_buf, chip->oob_poi, mtd->oobsize); -+ -+ // copy ecc data -+ for (i = 0; i < layout->eccbytes; i++) { -+ iter = (i / (spare_per_sector-OOB_AVAI_PER_SECTOR)) * spare_per_sector + OOB_AVAI_PER_SECTOR + i % (spare_per_sector-OOB_AVAI_PER_SECTOR); -+ local_oob_buf[iter] = chip->oob_poi[layout->eccpos[i]]; -+ } -+ -+ // copy FDM data -+ for (i = 0; i < sec_num; i++) -+ memcpy(&local_oob_buf[i * spare_per_sector], &chip->oob_poi[i * OOB_AVAI_PER_SECTOR], OOB_AVAI_PER_SECTOR); -+ -+ return mtk_nand_write_oob_raw(mtd, local_oob_buf, page, mtd->oobsize); -+} -+ -+static int mtk_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) -+{ -+ int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ int block = page / page_per_block; -+ u16 page_in_block = page % page_per_block; -+ int mapped_block = block; -+ -+#if defined(MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+ // write bad index into oob -+ if (mapped_block != block) -+ set_bad_index_to_oob(chip->oob_poi, block); -+ else -+ set_bad_index_to_oob(chip->oob_poi, FAKE_INDEX); -+#else -+ if (shift_on_bbt) -+ { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } -+#endif -+ do { -+ if (mtk_nand_write_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block /* page */)) { -+ MSG(INIT, "write oob fail at block: 0x%x, page: 0x%x\n", mapped_block, page_in_block); -+#if defined(MTK_NAND_BMT) -+ if (update_bmt((page_in_block + mapped_block * page_per_block) << chip->page_shift, -+ UPDATE_WRITE_FAIL, NULL, chip->oob_poi)) -+ { -+ MSG(INIT, "Update BMT success\n"); -+ return 0; -+ } else { -+ MSG(INIT, "Update BMT fail\n"); -+ return -EIO; -+ } -+#else -+ mtk_nand_block_markbad_hw(mtd, (page_in_block + mapped_block * page_per_block) << chip->page_shift); -+ nand_bbt_set(mtd, page_in_block + mapped_block * page_per_block, 0x3); -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, mapped_block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ if (nand_bbt_get(mtd, mapped_block << (chip->phys_erase_shift - chip->page_shift)) != 0x0) -+ return NAND_STATUS_FAIL; -+ } else { -+ return NAND_STATUS_FAIL; -+ } -+#endif -+ } else -+ break; -+ } while (1); -+ -+ return 0; -+} -+ -+int -+mtk_nand_block_markbad_hw(struct mtd_info *mtd, loff_t offset) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int block = (int)offset >> chip->phys_erase_shift; -+ int page = block * (1 << (chip->phys_erase_shift - chip->page_shift)); -+ u8 buf[8]; -+ -+ memset(buf, 0xFF, 8); -+ buf[0] = 0; -+ return mtk_nand_write_oob_raw(mtd, buf, page, 8); -+} -+ -+static int -+mtk_nand_block_markbad(struct mtd_info *mtd, loff_t offset) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int block = (int)offset >> chip->phys_erase_shift; -+ int ret; -+ int mapped_block = block; -+ -+ nand_get_device(chip, mtd, FL_WRITING); -+ -+#if defined(MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+ ret = mtk_nand_block_markbad_hw(mtd, mapped_block << chip->phys_erase_shift); -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) { -+ printk("NAND mark bad failed\n"); -+ nand_release_device(mtd); -+ return NAND_STATUS_FAIL; -+ } -+ } -+ ret = mtk_nand_block_markbad_hw(mtd, mapped_block << chip->phys_erase_shift); -+#endif -+ nand_release_device(mtd); -+ -+ return ret; -+} -+ -+int -+mtk_nand_read_oob_hw(struct mtd_info *mtd, struct nand_chip *chip, int page) -+{ -+ int i; -+ u8 iter = 0; -+ -+ int sec_num = 1<<(chip->page_shift-9); -+ int spare_per_sector = mtd->oobsize/sec_num; -+ -+ if (mtk_nand_read_oob_raw(mtd, chip->oob_poi, page, mtd->oobsize)) { -+ printk(KERN_ERR "[%s]mtk_nand_read_oob_raw return failed\n", __FUNCTION__); -+ return -EIO; -+ } -+ -+ // adjust to ecc physical layout to memory layout -+ /*********************************************************/ -+ /* FDM0 | ECC0 | FDM1 | ECC1 | FDM2 | ECC2 | FDM3 | ECC3 */ -+ /* 8B | 8B | 8B | 8B | 8B | 8B | 8B | 8B */ -+ /*********************************************************/ -+ -+ memcpy(local_oob_buf, chip->oob_poi, mtd->oobsize); -+ // copy ecc data -+ for (i = 0; i < layout->eccbytes; i++) { -+ iter = (i / (spare_per_sector-OOB_AVAI_PER_SECTOR)) * spare_per_sector + OOB_AVAI_PER_SECTOR + i % (spare_per_sector-OOB_AVAI_PER_SECTOR); -+ chip->oob_poi[layout->eccpos[i]] = local_oob_buf[iter]; -+ } -+ -+ // copy FDM data -+ for (i = 0; i < sec_num; i++) { -+ memcpy(&chip->oob_poi[i * OOB_AVAI_PER_SECTOR], &local_oob_buf[i * spare_per_sector], OOB_AVAI_PER_SECTOR); -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) -+{ -+ int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ int block = page / page_per_block; -+ u16 page_in_block = page % page_per_block; -+ int mapped_block = block; -+ -+#if defined (MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+ mtk_nand_read_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block); -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ if (mapped_block == -1) -+ return NAND_STATUS_FAIL; -+ // allow to read oob even if the block is bad -+ } -+ if (mtk_nand_read_oob_hw(mtd, chip, page_in_block + mapped_block * page_per_block)!=0) -+ return -1; -+#endif -+ return 0; -+} -+ -+int -+mtk_nand_block_bad_hw(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_chip *chip = (struct nand_chip *)mtd->priv; -+ int page_addr = (int)(ofs >> chip->page_shift); -+ unsigned int page_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); -+ unsigned char oob_buf[8]; -+ -+ page_addr &= ~(page_per_block - 1); -+ if (mtk_nand_read_oob_raw(mtd, oob_buf, page_addr, sizeof(oob_buf))) { -+ printk(KERN_WARNING "mtk_nand_read_oob_raw return error\n"); -+ return 1; -+ } -+ -+ if (oob_buf[0] != 0xff) { -+ printk(KERN_WARNING "Bad block detected at 0x%x, oob_buf[0] is 0x%x\n", page_addr, oob_buf[0]); -+ // dump_nfi(); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_nand_block_bad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_chip *chip = (struct nand_chip *)mtd->priv; -+ int block = (int)ofs >> chip->phys_erase_shift; -+ int mapped_block = block; -+ int ret; -+ -+#if defined(MTK_NAND_BMT) -+ mapped_block = get_mapping_block_index(block); -+#else -+ if (shift_on_bbt) { -+ mapped_block = block_remap(mtd, block); -+ } -+#endif -+ -+ ret = mtk_nand_block_bad_hw(mtd, mapped_block << chip->phys_erase_shift); -+#if defined (MTK_NAND_BMT) -+ if (ret) { -+ MSG(INIT, "Unmapped bad block: 0x%x\n", mapped_block); -+ if (update_bmt(mapped_block << chip->phys_erase_shift, UPDATE_UNMAPPED_BLOCK, NULL, NULL)) { -+ MSG(INIT, "Update BMT success\n"); -+ ret = 0; -+ } else { -+ MSG(INIT, "Update BMT fail\n"); -+ ret = 1; -+ } -+ } -+#endif -+ -+ return ret; -+} -+ -+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -+char gacBuf[4096 + 288]; -+ -+static int -+mtk_nand_verify_buf(struct mtd_info *mtd, const uint8_t * buf, int len) -+{ -+ struct nand_chip *chip = (struct nand_chip *)mtd->priv; -+ struct NAND_CMD *pkCMD = &g_kCMD; -+ u32 u4PageSize = mtd->writesize; -+ u32 *pSrc, *pDst; -+ int i; -+ -+ mtk_nand_exec_read_page(mtd, pkCMD->u4RowAddr, u4PageSize, gacBuf, gacBuf + u4PageSize); -+ -+ pSrc = (u32 *) buf; -+ pDst = (u32 *) gacBuf; -+ len = len / sizeof(u32); -+ for (i = 0; i < len; ++i) { -+ if (*pSrc != *pDst) { -+ MSG(VERIFY, "mtk_nand_verify_buf page fail at page %d\n", pkCMD->u4RowAddr); -+ return -1; -+ } -+ pSrc++; -+ pDst++; -+ } -+ -+ pSrc = (u32 *) chip->oob_poi; -+ pDst = (u32 *) (gacBuf + u4PageSize); -+ -+ if ((pSrc[0] != pDst[0]) || (pSrc[1] != pDst[1]) || (pSrc[2] != pDst[2]) || (pSrc[3] != pDst[3]) || (pSrc[4] != pDst[4]) || (pSrc[5] != pDst[5])) { -+ // TODO: Ask Designer Why? -+ //(pSrc[6] != pDst[6]) || (pSrc[7] != pDst[7])) -+ MSG(VERIFY, "mtk_nand_verify_buf oob fail at page %d\n", pkCMD->u4RowAddr); -+ MSG(VERIFY, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", pSrc[0], pSrc[1], pSrc[2], pSrc[3], pSrc[4], pSrc[5], pSrc[6], pSrc[7]); -+ MSG(VERIFY, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", pDst[0], pDst[1], pDst[2], pDst[3], pDst[4], pDst[5], pDst[6], pDst[7]); -+ return -1; -+ } -+ return 0; -+} -+#endif -+ -+static void -+mtk_nand_init_hw(struct mtk_nand_host *host) { -+ struct mtk_nand_host_hw *hw = host->hw; -+ u32 data; -+ -+ data = DRV_Reg32(RALINK_SYSCTL_BASE+0x60); -+ data &= ~((0x3<<18)|(0x3<<16)); -+ data |= ((0x2<<18) |(0x2<<16)); -+ DRV_WriteReg32(RALINK_SYSCTL_BASE+0x60, data); -+ -+ MSG(INIT, "Enable NFI Clock\n"); -+ nand_enable_clock(); -+ -+ g_bInitDone = false; -+ g_kCMD.u4OOBRowAddr = (u32) - 1; -+ -+ /* Set default NFI access timing control */ -+ DRV_WriteReg32(NFI_ACCCON_REG32, hw->nfi_access_timing); -+ DRV_WriteReg16(NFI_CNFG_REG16, 0); -+ DRV_WriteReg16(NFI_PAGEFMT_REG16, 0); -+ -+ /* Reset the state machine and data FIFO, because flushing FIFO */ -+ (void)mtk_nand_reset(); -+ -+ /* Set the ECC engine */ -+ if (hw->nand_ecc_mode == NAND_ECC_HW) { -+ MSG(INIT, "%s : Use HW ECC\n", MODULE_NAME); -+ if (g_bHwEcc) -+ NFI_SET_REG32(NFI_CNFG_REG16, CNFG_HW_ECC_EN); -+ ECC_Config(host->hw,4); -+ mtk_nand_configure_fdm(8); -+ mtk_nand_configure_lock(); -+ } -+ -+ NFI_SET_REG16(NFI_IOCON_REG16, 0x47); -+} -+ -+static int mtk_nand_dev_ready(struct mtd_info *mtd) -+{ -+ return !(DRV_Reg32(NFI_STA_REG32) & STA_NAND_BUSY); -+} -+ -+#define FACT_BBT_BLOCK_NUM 32 // use the latest 32 BLOCK for factory bbt table -+#define FACT_BBT_OOB_SIGNATURE 1 -+#define FACT_BBT_SIGNATURE_LEN 7 -+const u8 oob_signature[] = "mtknand"; -+static u8 *fact_bbt = 0; -+static u32 bbt_size = 0; -+ -+static int -+read_fact_bbt(struct mtd_info *mtd, unsigned int page) -+{ -+ struct nand_chip *chip = mtd->priv; -+ -+ // read oob -+ if (mtk_nand_read_oob_hw(mtd, chip, page)==0) -+ { -+ if (chip->oob_poi[nand_badblock_offset] != 0xFF) -+ { -+ printk("Bad Block on Page %x\n", page); -+ return -1; -+ } -+ if (memcmp(&chip->oob_poi[FACT_BBT_OOB_SIGNATURE], oob_signature, FACT_BBT_SIGNATURE_LEN) != 0) -+ { -+ printk("compare signature failed %x\n", page); -+ return -1; -+ } -+ if (mtk_nand_exec_read_page(mtd, page, mtd->writesize, chip->buffers->databuf, chip->oob_poi)) -+ { -+ printk("Signature matched and data read!\n"); -+ memcpy(fact_bbt, chip->buffers->databuf, (bbt_size <= mtd->writesize)? bbt_size:mtd->writesize); -+ return 0; -+ } -+ -+ } -+ printk("failed at page %x\n", page); -+ return -1; -+} -+ -+static int -+load_fact_bbt(struct mtd_info *mtd) -+{ -+ struct nand_chip *chip = mtd->priv; -+ int i; -+ u32 total_block; -+ -+ total_block = 1 << (chip->chip_shift - chip->phys_erase_shift); -+ bbt_size = total_block >> 2; -+ -+ if ((!fact_bbt) && (bbt_size)) -+ fact_bbt = (u8 *)kmalloc(bbt_size, GFP_KERNEL); -+ if (!fact_bbt) -+ return -1; -+ -+ for (i = total_block - 1; i >= (total_block - FACT_BBT_BLOCK_NUM); i--) -+ { -+ if (read_fact_bbt(mtd, i << (chip->phys_erase_shift - chip->page_shift)) == 0) -+ { -+ printk("load_fact_bbt success %d\n", i); -+ return 0; -+ } -+ -+ } -+ printk("load_fact_bbt failed\n"); -+ return -1; -+} -+ -+static int oob_mtk_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ oobregion->length = 8; -+ oobregion->offset = layout->eccpos[section * 8]; -+ -+ return 0; -+} -+ -+static int oob_mtk_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ if (section >= (layout->eccbytes / 8)) { -+ return -ERANGE; -+ } -+ oobregion->offset = layout->oobfree[section].offset; -+ oobregion->length = layout->oobfree[section].length; -+ -+ return 0; -+} -+ -+ -+static const struct mtd_ooblayout_ops oob_mtk_ops = { -+ .ecc = oob_mtk_ooblayout_ecc, -+ .free = oob_mtk_ooblayout_free, -+}; -+ -+static int -+mtk_nand_probe(struct platform_device *pdev) -+{ -+ struct mtd_part_parser_data ppdata; -+ struct mtk_nand_host_hw *hw; -+ struct nand_chip *nand_chip; -+ struct mtd_info *mtd; -+ u8 ext_id1, ext_id2, ext_id3; -+ int err = 0; -+ int id; -+ u32 ext_id; -+ int i; -+ u32 data; -+ -+ data = DRV_Reg32(RALINK_SYSCTL_BASE+0x60); -+ data &= ~((0x3<<18)|(0x3<<16)); -+ data |= ((0x2<<18) |(0x2<<16)); -+ DRV_WriteReg32(RALINK_SYSCTL_BASE+0x60, data); -+ -+ hw = &mt7621_nand_hw; -+ BUG_ON(!hw); -+ /* Allocate memory for the device structure (and zero it) */ -+ host = kzalloc(sizeof(struct mtk_nand_host), GFP_KERNEL); -+ if (!host) { -+ MSG(INIT, "mtk_nand: failed to allocate device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ host->hw = hw; -+ -+ /* init mtd data structure */ -+ nand_chip = &host->nand_chip; -+ nand_chip->priv = host; /* link the private data structures */ -+ -+ mtd = host->mtd = &nand_chip->mtd; -+ mtd->priv = nand_chip; -+ mtd->owner = THIS_MODULE; -+ mtd->name = "MT7621-NAND"; -+ -+ hw->nand_ecc_mode = NAND_ECC_HW; -+ -+ /* Set address of NAND IO lines */ -+ nand_chip->IO_ADDR_R = (void __iomem *)NFI_DATAR_REG32; -+ nand_chip->IO_ADDR_W = (void __iomem *)NFI_DATAW_REG32; -+ nand_chip->chip_delay = 20; /* 20us command delay time */ -+ nand_chip->ecc.mode = hw->nand_ecc_mode; /* enable ECC */ -+ nand_chip->ecc.strength = 1; -+ nand_chip->read_byte = mtk_nand_read_byte; -+ nand_chip->read_buf = mtk_nand_read_buf; -+ nand_chip->write_buf = mtk_nand_write_buf; -+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -+ nand_chip->verify_buf = mtk_nand_verify_buf; -+#endif -+ nand_chip->select_chip = mtk_nand_select_chip; -+ nand_chip->dev_ready = mtk_nand_dev_ready; -+ nand_chip->cmdfunc = mtk_nand_command_bp; -+ nand_chip->ecc.read_page = mtk_nand_read_page_hwecc; -+ nand_chip->ecc.write_page = mtk_nand_write_page_hwecc; -+ -+ mtd_set_ooblayout(mtd, &oob_mtk_ops); -+ nand_chip->ecc.size = hw->nand_ecc_size; //2048 -+ nand_chip->ecc.bytes = hw->nand_ecc_bytes; //32 -+ -+ // For BMT, we need to revise driver architecture -+ nand_chip->write_page = mtk_nand_write_page; -+ nand_chip->ecc.write_oob = mtk_nand_write_oob; -+ nand_chip->block_markbad = mtk_nand_block_markbad; // need to add nand_get_device()/nand_release_device(). -+ nand_chip->read_page = mtk_nand_read_page; -+ nand_chip->ecc.read_oob = mtk_nand_read_oob; -+ nand_chip->block_bad = mtk_nand_block_bad; -+ nand_chip->cmd_ctrl = mtk_nfc_cmd_ctrl; -+ -+ //Qwert:Add for Uboot -+ mtk_nand_init_hw(host); -+ /* Select the device */ -+ nand_chip->select_chip(mtd, NFI_DEFAULT_CS); -+ -+ /* -+ * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) -+ * after power-up -+ */ -+ nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ -+ memset(&devinfo, 0 , sizeof(flashdev_info)); -+ -+ /* Send the command for reading device ID */ -+ -+ nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); -+ -+ /* Read manufacturer and device IDs */ -+ manu_id = nand_chip->read_byte(mtd); -+ dev_id = nand_chip->read_byte(mtd); -+ id = dev_id | (manu_id << 8); -+ ext_id1 = nand_chip->read_byte(mtd); -+ ext_id2 = nand_chip->read_byte(mtd); -+ ext_id3 = nand_chip->read_byte(mtd); -+ ext_id = ext_id1 << 16 | ext_id2 << 8 | ext_id3; -+ if (!get_device_info(id, ext_id, &devinfo)) { -+ u32 chip_mode = RALINK_REG(RALINK_SYSCTL_BASE+0x010)&0x0F; -+ MSG(INIT, "Not Support this Device! \r\n"); -+ memset(&devinfo, 0 , sizeof(flashdev_info)); -+ MSG(INIT, "chip_mode=%08X\n",chip_mode); -+ -+ /* apply bootstrap first */ -+ devinfo.addr_cycle = 5; -+ devinfo.iowidth = 8; -+ -+ switch (chip_mode) { -+ case 10: -+ devinfo.pagesize = 2048; -+ devinfo.sparesize = 128; -+ devinfo.totalsize = 128; -+ devinfo.blocksize = 128; -+ break; -+ case 11: -+ devinfo.pagesize = 4096; -+ devinfo.sparesize = 128; -+ devinfo.totalsize = 1024; -+ devinfo.blocksize = 256; -+ break; -+ case 12: -+ devinfo.pagesize = 4096; -+ devinfo.sparesize = 224; -+ devinfo.totalsize = 2048; -+ devinfo.blocksize = 512; -+ break; -+ default: -+ case 1: -+ devinfo.pagesize = 2048; -+ devinfo.sparesize = 64; -+ devinfo.totalsize = 128; -+ devinfo.blocksize = 128; -+ break; -+ } -+ -+ devinfo.timmingsetting = NFI_DEFAULT_ACCESS_TIMING; -+ devinfo.devciename[0] = 'U'; -+ devinfo.advancedmode = 0; -+ } -+ mtd->writesize = devinfo.pagesize; -+ mtd->erasesize = (devinfo.blocksize<<10); -+ mtd->oobsize = devinfo.sparesize; -+ -+ nand_chip->chipsize = (devinfo.totalsize<<20); -+ nand_chip->page_shift = ffs(mtd->writesize) - 1; -+ nand_chip->pagemask = (nand_chip->chipsize >> nand_chip->page_shift) - 1; -+ nand_chip->phys_erase_shift = ffs(mtd->erasesize) - 1; -+ nand_chip->chip_shift = ffs(nand_chip->chipsize) - 1;//0x1C;//ffs(nand_chip->chipsize) - 1; -+ nand_chip->cmd_ctrl = mtk_nfc_cmd_ctrl; -+ -+ if (devinfo.pagesize == 4096) -+ layout = &nand_oob_128; -+ else if (devinfo.pagesize == 2048) -+ layout = &nand_oob_64; -+ else if (devinfo.pagesize == 512) -+ layout = &nand_oob_16; -+ -+ layout->eccbytes = devinfo.sparesize-OOB_AVAI_PER_SECTOR*(devinfo.pagesize/NAND_SECTOR_SIZE); -+ for (i = 0; i < layout->eccbytes; i++) -+ layout->eccpos[i]=OOB_AVAI_PER_SECTOR*(devinfo.pagesize/NAND_SECTOR_SIZE)+i; -+ -+ MSG(INIT, "Support this Device in MTK table! %x \r\n", id); -+ hw->nfi_bus_width = devinfo.iowidth; -+ DRV_WriteReg32(NFI_ACCCON_REG32, devinfo.timmingsetting); -+ -+ /* 16-bit bus width */ -+ if (hw->nfi_bus_width == 16) { -+ MSG(INIT, "%s : Set the 16-bit I/O settings!\n", MODULE_NAME); -+ nand_chip->options |= NAND_BUSWIDTH_16; -+ } -+ mtd->oobsize = devinfo.sparesize; -+ hw->nfi_cs_num = 1; -+ -+ nand_chip->options |= NAND_USE_BOUNCE_BUFFER; -+ nand_chip->buf_align = 16; -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan(mtd, hw->nfi_cs_num)) { -+ MSG(INIT, "%s : nand_scan fail.\n", MODULE_NAME); -+ err = -ENXIO; -+ goto out; -+ } -+ -+ nand_chip->erase = mtk_nand_erase; -+ -+ g_page_size = mtd->writesize; -+ platform_set_drvdata(pdev, host); -+ if (hw->nfi_bus_width == 16) { -+ NFI_SET_REG16(NFI_PAGEFMT_REG16, PAGEFMT_DBYTE_EN); -+ } -+ -+ nand_chip->select_chip(mtd, 0); -+#if defined(MTK_NAND_BMT) -+ nand_chip->chipsize -= (BMT_POOL_SIZE) << nand_chip->phys_erase_shift; -+#endif -+ mtd->size = nand_chip->chipsize; -+ -+ CFG_BLOCKSIZE = mtd->erasesize; -+ -+#if defined(MTK_NAND_BMT) -+ if (!g_bmt) { -+ if (!(g_bmt = init_bmt(nand_chip, BMT_POOL_SIZE))) { -+ MSG(INIT, "Error: init bmt failed\n"); -+ return 0; -+ } -+ } -+#endif -+ -+ nand_set_flash_node(nand_chip, pdev->dev.of_node); -+ err = mtd_device_parse_register(mtd, probe_types, &ppdata, -+ NULL, 0); -+ if (!err) { -+ MSG(INIT, "[mtk_nand] probe successfully!\n"); -+ nand_disable_clock(); -+ shift_on_bbt = 0; -+ if (load_fact_bbt(mtd) == 0) { -+ int i; -+ for (i = 0; i < 0x100; i++) -+ nand_chip->bbt[i] |= fact_bbt[i]; -+ } -+ -+ return err; -+ } -+ -+out: -+ MSG(INIT, "[NFI] mtk_nand_probe fail, err = %d!\n", err); -+ nand_release(mtd); -+ platform_set_drvdata(pdev, NULL); -+ kfree(host); -+ nand_disable_clock(); -+ return err; -+} -+ -+static int -+mtk_nand_remove(struct platform_device *pdev) -+{ -+ struct mtk_nand_host *host = platform_get_drvdata(pdev); -+ struct mtd_info *mtd = host->mtd; -+ struct nand_chip *nand_chip = &host->nand_chip; -+ -+ nand_release(mtd); -+ kfree(host); -+ nand_disable_clock(); -+ -+ return 0; -+} -+ -+static const struct of_device_id mt7621_nand_match[] = { -+ { .compatible = "mtk,mt7621-nand" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mt7621_nand_match); -+ -+static struct platform_driver mtk_nand_driver = { -+ .probe = mtk_nand_probe, -+ .remove = mtk_nand_remove, -+ .driver = { -+ .name = "MT7621-NAND", -+ .owner = THIS_MODULE, -+ .of_match_table = mt7621_nand_match, -+ }, -+}; -+ -+static int __init -+mtk_nand_init(void) -+{ -+ printk("MediaTek Nand driver init, version %s\n", VERSION); -+ -+ return platform_driver_register(&mtk_nand_driver); -+} -+ -+static void __exit -+mtk_nand_exit(void) -+{ -+ platform_driver_unregister(&mtk_nand_driver); -+} -+ -+module_init(mtk_nand_init); -+module_exit(mtk_nand_exit); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/mtd/nand/mtk_nand2.h -@@ -0,0 +1,452 @@ -+#ifndef __MTK_NAND_H -+#define __MTK_NAND_H -+ -+#define RALINK_NAND_CTRL_BASE 0xBE003000 -+#define RALINK_SYSCTL_BASE 0xBE000000 -+#define RALINK_NANDECC_CTRL_BASE 0xBE003800 -+/******************************************************************************* -+ * NFI Register Definition -+ *******************************************************************************/ -+ -+#define NFI_CNFG_REG16 ((volatile P_U16)(NFI_BASE+0x0000)) -+#define NFI_PAGEFMT_REG16 ((volatile P_U16)(NFI_BASE+0x0004)) -+#define NFI_CON_REG16 ((volatile P_U16)(NFI_BASE+0x0008)) -+#define NFI_ACCCON_REG32 ((volatile P_U32)(NFI_BASE+0x000C)) -+#define NFI_INTR_EN_REG16 ((volatile P_U16)(NFI_BASE+0x0010)) -+#define NFI_INTR_REG16 ((volatile P_U16)(NFI_BASE+0x0014)) -+ -+#define NFI_CMD_REG16 ((volatile P_U16)(NFI_BASE+0x0020)) -+ -+#define NFI_ADDRNOB_REG16 ((volatile P_U16)(NFI_BASE+0x0030)) -+#define NFI_COLADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0034)) -+#define NFI_ROWADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0038)) -+ -+#define NFI_STRDATA_REG16 ((volatile P_U16)(NFI_BASE+0x0040)) -+ -+#define NFI_DATAW_REG32 ((volatile P_U32)(NFI_BASE+0x0050)) -+#define NFI_DATAR_REG32 ((volatile P_U32)(NFI_BASE+0x0054)) -+#define NFI_PIO_DIRDY_REG16 ((volatile P_U16)(NFI_BASE+0x0058)) -+ -+#define NFI_STA_REG32 ((volatile P_U32)(NFI_BASE+0x0060)) -+#define NFI_FIFOSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0064)) -+#define NFI_LOCKSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0068)) -+ -+#define NFI_ADDRCNTR_REG16 ((volatile P_U16)(NFI_BASE+0x0070)) -+ -+#define NFI_STRADDR_REG32 ((volatile P_U32)(NFI_BASE+0x0080)) -+#define NFI_BYTELEN_REG16 ((volatile P_U16)(NFI_BASE+0x0084)) -+ -+#define NFI_CSEL_REG16 ((volatile P_U16)(NFI_BASE+0x0090)) -+#define NFI_IOCON_REG16 ((volatile P_U16)(NFI_BASE+0x0094)) -+ -+#define NFI_FDM0L_REG32 ((volatile P_U32)(NFI_BASE+0x00A0)) -+#define NFI_FDM0M_REG32 ((volatile P_U32)(NFI_BASE+0x00A4)) -+ -+#define NFI_LOCK_REG16 ((volatile P_U16)(NFI_BASE+0x0100)) -+#define NFI_LOCKCON_REG32 ((volatile P_U32)(NFI_BASE+0x0104)) -+#define NFI_LOCKANOB_REG16 ((volatile P_U16)(NFI_BASE+0x0108)) -+#define NFI_LOCK00ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0110)) -+#define NFI_LOCK00FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0114)) -+#define NFI_LOCK01ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0118)) -+#define NFI_LOCK01FMT_REG32 ((volatile P_U32)(NFI_BASE+0x011C)) -+#define NFI_LOCK02ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0120)) -+#define NFI_LOCK02FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0124)) -+#define NFI_LOCK03ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0128)) -+#define NFI_LOCK03FMT_REG32 ((volatile P_U32)(NFI_BASE+0x012C)) -+#define NFI_LOCK04ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0130)) -+#define NFI_LOCK04FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0134)) -+#define NFI_LOCK05ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0138)) -+#define NFI_LOCK05FMT_REG32 ((volatile P_U32)(NFI_BASE+0x013C)) -+#define NFI_LOCK06ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0140)) -+#define NFI_LOCK06FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0144)) -+#define NFI_LOCK07ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0148)) -+#define NFI_LOCK07FMT_REG32 ((volatile P_U32)(NFI_BASE+0x014C)) -+#define NFI_LOCK08ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0150)) -+#define NFI_LOCK08FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0154)) -+#define NFI_LOCK09ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0158)) -+#define NFI_LOCK09FMT_REG32 ((volatile P_U32)(NFI_BASE+0x015C)) -+#define NFI_LOCK10ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0160)) -+#define NFI_LOCK10FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0164)) -+#define NFI_LOCK11ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0168)) -+#define NFI_LOCK11FMT_REG32 ((volatile P_U32)(NFI_BASE+0x016C)) -+#define NFI_LOCK12ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0170)) -+#define NFI_LOCK12FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0174)) -+#define NFI_LOCK13ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0178)) -+#define NFI_LOCK13FMT_REG32 ((volatile P_U32)(NFI_BASE+0x017C)) -+#define NFI_LOCK14ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0180)) -+#define NFI_LOCK14FMT_REG32 ((volatile P_U32)(NFI_BASE+0x0184)) -+#define NFI_LOCK15ADD_REG32 ((volatile P_U32)(NFI_BASE+0x0188)) -+#define NFI_LOCK15FMT_REG32 ((volatile P_U32)(NFI_BASE+0x018C)) -+ -+#define NFI_FIFODATA0_REG32 ((volatile P_U32)(NFI_BASE+0x0190)) -+#define NFI_FIFODATA1_REG32 ((volatile P_U32)(NFI_BASE+0x0194)) -+#define NFI_FIFODATA2_REG32 ((volatile P_U32)(NFI_BASE+0x0198)) -+#define NFI_FIFODATA3_REG32 ((volatile P_U32)(NFI_BASE+0x019C)) -+#define NFI_MASTERSTA_REG16 ((volatile P_U16)(NFI_BASE+0x0210)) -+ -+ -+/******************************************************************************* -+ * NFI Register Field Definition -+ *******************************************************************************/ -+ -+/* NFI_CNFG */ -+#define CNFG_AHB (0x0001) -+#define CNFG_READ_EN (0x0002) -+#define CNFG_DMA_BURST_EN (0x0004) -+#define CNFG_BYTE_RW (0x0040) -+#define CNFG_HW_ECC_EN (0x0100) -+#define CNFG_AUTO_FMT_EN (0x0200) -+#define CNFG_OP_IDLE (0x0000) -+#define CNFG_OP_READ (0x1000) -+#define CNFG_OP_SRD (0x2000) -+#define CNFG_OP_PRGM (0x3000) -+#define CNFG_OP_ERASE (0x4000) -+#define CNFG_OP_RESET (0x5000) -+#define CNFG_OP_CUST (0x6000) -+#define CNFG_OP_MODE_MASK (0x7000) -+#define CNFG_OP_MODE_SHIFT (12) -+ -+/* NFI_PAGEFMT */ -+#define PAGEFMT_512 (0x0000) -+#define PAGEFMT_2K (0x0001) -+#define PAGEFMT_4K (0x0002) -+ -+#define PAGEFMT_PAGE_MASK (0x0003) -+ -+#define PAGEFMT_DBYTE_EN (0x0008) -+ -+#define PAGEFMT_SPARE_16 (0x0000) -+#define PAGEFMT_SPARE_26 (0x0001) -+#define PAGEFMT_SPARE_27 (0x0002) -+#define PAGEFMT_SPARE_28 (0x0003) -+#define PAGEFMT_SPARE_MASK (0x0030) -+#define PAGEFMT_SPARE_SHIFT (4) -+ -+#define PAGEFMT_FDM_MASK (0x0F00) -+#define PAGEFMT_FDM_SHIFT (8) -+ -+#define PAGEFMT_FDM_ECC_MASK (0xF000) -+#define PAGEFMT_FDM_ECC_SHIFT (12) -+ -+/* NFI_CON */ -+#define CON_FIFO_FLUSH (0x0001) -+#define CON_NFI_RST (0x0002) -+#define CON_NFI_SRD (0x0010) -+ -+#define CON_NFI_NOB_MASK (0x0060) -+#define CON_NFI_NOB_SHIFT (5) -+ -+#define CON_NFI_BRD (0x0100) -+#define CON_NFI_BWR (0x0200) -+ -+#define CON_NFI_SEC_MASK (0xF000) -+#define CON_NFI_SEC_SHIFT (12) -+ -+/* NFI_ACCCON */ -+#define ACCCON_SETTING () -+ -+/* NFI_INTR_EN */ -+#define INTR_RD_DONE_EN (0x0001) -+#define INTR_WR_DONE_EN (0x0002) -+#define INTR_RST_DONE_EN (0x0004) -+#define INTR_ERASE_DONE_EN (0x0008) -+#define INTR_BSY_RTN_EN (0x0010) -+#define INTR_ACC_LOCK_EN (0x0020) -+#define INTR_AHB_DONE_EN (0x0040) -+#define INTR_ALL_INTR_DE (0x0000) -+#define INTR_ALL_INTR_EN (0x007F) -+ -+/* NFI_INTR */ -+#define INTR_RD_DONE (0x0001) -+#define INTR_WR_DONE (0x0002) -+#define INTR_RST_DONE (0x0004) -+#define INTR_ERASE_DONE (0x0008) -+#define INTR_BSY_RTN (0x0010) -+#define INTR_ACC_LOCK (0x0020) -+#define INTR_AHB_DONE (0x0040) -+ -+/* NFI_ADDRNOB */ -+#define ADDR_COL_NOB_MASK (0x0003) -+#define ADDR_COL_NOB_SHIFT (0) -+#define ADDR_ROW_NOB_MASK (0x0030) -+#define ADDR_ROW_NOB_SHIFT (4) -+ -+/* NFI_STA */ -+#define STA_READ_EMPTY (0x00001000) -+#define STA_ACC_LOCK (0x00000010) -+#define STA_CMD_STATE (0x00000001) -+#define STA_ADDR_STATE (0x00000002) -+#define STA_DATAR_STATE (0x00000004) -+#define STA_DATAW_STATE (0x00000008) -+ -+#define STA_NAND_FSM_MASK (0x1F000000) -+#define STA_NAND_BUSY (0x00000100) -+#define STA_NAND_BUSY_RETURN (0x00000200) -+#define STA_NFI_FSM_MASK (0x000F0000) -+#define STA_NFI_OP_MASK (0x0000000F) -+ -+/* NFI_FIFOSTA */ -+#define FIFO_RD_EMPTY (0x0040) -+#define FIFO_RD_FULL (0x0080) -+#define FIFO_WR_FULL (0x8000) -+#define FIFO_WR_EMPTY (0x4000) -+#define FIFO_RD_REMAIN(x) (0x1F&(x)) -+#define FIFO_WR_REMAIN(x) ((0x1F00&(x))>>8) -+ -+/* NFI_ADDRCNTR */ -+#define ADDRCNTR_CNTR(x) ((0xF000&(x))>>12) -+#define ADDRCNTR_OFFSET(x) (0x03FF&(x)) -+ -+/* NFI_LOCK */ -+#define NFI_LOCK_ON (0x0001) -+ -+/* NFI_LOCKANOB */ -+#define PROG_RADD_NOB_MASK (0x7000) -+#define PROG_RADD_NOB_SHIFT (12) -+#define PROG_CADD_NOB_MASK (0x0300) -+#define PROG_CADD_NOB_SHIFT (8) -+#define ERASE_RADD_NOB_MASK (0x0070) -+#define ERASE_RADD_NOB_SHIFT (4) -+#define ERASE_CADD_NOB_MASK (0x0007) -+#define ERASE_CADD_NOB_SHIFT (0) -+ -+/******************************************************************************* -+ * ECC Register Definition -+ *******************************************************************************/ -+ -+#define ECC_ENCCON_REG16 ((volatile P_U16)(NFIECC_BASE+0x0000)) -+#define ECC_ENCCNFG_REG32 ((volatile P_U32)(NFIECC_BASE+0x0004)) -+#define ECC_ENCDIADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x0008)) -+#define ECC_ENCIDLE_REG32 ((volatile P_U32)(NFIECC_BASE+0x000C)) -+#define ECC_ENCPAR0_REG32 ((volatile P_U32)(NFIECC_BASE+0x0010)) -+#define ECC_ENCPAR1_REG32 ((volatile P_U32)(NFIECC_BASE+0x0014)) -+#define ECC_ENCPAR2_REG32 ((volatile P_U32)(NFIECC_BASE+0x0018)) -+#define ECC_ENCPAR3_REG32 ((volatile P_U32)(NFIECC_BASE+0x001C)) -+#define ECC_ENCPAR4_REG32 ((volatile P_U32)(NFIECC_BASE+0x0020)) -+#define ECC_ENCSTA_REG32 ((volatile P_U32)(NFIECC_BASE+0x0024)) -+#define ECC_ENCIRQEN_REG16 ((volatile P_U16)(NFIECC_BASE+0x0028)) -+#define ECC_ENCIRQSTA_REG16 ((volatile P_U16)(NFIECC_BASE+0x002C)) -+ -+#define ECC_DECCON_REG16 ((volatile P_U16)(NFIECC_BASE+0x0100)) -+#define ECC_DECCNFG_REG32 ((volatile P_U32)(NFIECC_BASE+0x0104)) -+#define ECC_DECDIADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x0108)) -+#define ECC_DECIDLE_REG16 ((volatile P_U16)(NFIECC_BASE+0x010C)) -+#define ECC_DECFER_REG16 ((volatile P_U16)(NFIECC_BASE+0x0110)) -+#define ECC_DECENUM_REG32 ((volatile P_U32)(NFIECC_BASE+0x0114)) -+#define ECC_DECDONE_REG16 ((volatile P_U16)(NFIECC_BASE+0x0118)) -+#define ECC_DECEL0_REG32 ((volatile P_U32)(NFIECC_BASE+0x011C)) -+#define ECC_DECEL1_REG32 ((volatile P_U32)(NFIECC_BASE+0x0120)) -+#define ECC_DECEL2_REG32 ((volatile P_U32)(NFIECC_BASE+0x0124)) -+#define ECC_DECEL3_REG32 ((volatile P_U32)(NFIECC_BASE+0x0128)) -+#define ECC_DECEL4_REG32 ((volatile P_U32)(NFIECC_BASE+0x012C)) -+#define ECC_DECEL5_REG32 ((volatile P_U32)(NFIECC_BASE+0x0130)) -+#define ECC_DECIRQEN_REG16 ((volatile P_U16)(NFIECC_BASE+0x0134)) -+#define ECC_DECIRQSTA_REG16 ((volatile P_U16)(NFIECC_BASE+0x0138)) -+#define ECC_FDMADDR_REG32 ((volatile P_U32)(NFIECC_BASE+0x013C)) -+#define ECC_DECFSM_REG32 ((volatile P_U32)(NFIECC_BASE+0x0140)) -+#define ECC_SYNSTA_REG32 ((volatile P_U32)(NFIECC_BASE+0x0144)) -+#define ECC_DECNFIDI_REG32 ((volatile P_U32)(NFIECC_BASE+0x0148)) -+#define ECC_SYN0_REG32 ((volatile P_U32)(NFIECC_BASE+0x014C)) -+ -+/******************************************************************************* -+ * ECC register definition -+ *******************************************************************************/ -+/* ECC_ENCON */ -+#define ENC_EN (0x0001) -+#define ENC_DE (0x0000) -+ -+/* ECC_ENCCNFG */ -+#define ECC_CNFG_ECC4 (0x0000) -+#define ECC_CNFG_ECC6 (0x0001) -+#define ECC_CNFG_ECC8 (0x0002) -+#define ECC_CNFG_ECC10 (0x0003) -+#define ECC_CNFG_ECC12 (0x0004) -+#define ECC_CNFG_ECC_MASK (0x00000007) -+ -+#define ENC_CNFG_NFI (0x0010) -+#define ENC_CNFG_MODE_MASK (0x0010) -+ -+#define ENC_CNFG_META6 (0x10300000) -+#define ENC_CNFG_META8 (0x10400000) -+ -+#define ENC_CNFG_MSG_MASK (0x1FFF0000) -+#define ENC_CNFG_MSG_SHIFT (0x10) -+ -+/* ECC_ENCIDLE */ -+#define ENC_IDLE (0x0001) -+ -+/* ECC_ENCSTA */ -+#define STA_FSM (0x001F) -+#define STA_COUNT_PS (0xFF10) -+#define STA_COUNT_MS (0x3FFF0000) -+ -+/* ECC_ENCIRQEN */ -+#define ENC_IRQEN (0x0001) -+ -+/* ECC_ENCIRQSTA */ -+#define ENC_IRQSTA (0x0001) -+ -+/* ECC_DECCON */ -+#define DEC_EN (0x0001) -+#define DEC_DE (0x0000) -+ -+/* ECC_ENCCNFG */ -+#define DEC_CNFG_ECC4 (0x0000) -+//#define DEC_CNFG_ECC6 (0x0001) -+//#define DEC_CNFG_ECC12 (0x0002) -+#define DEC_CNFG_NFI (0x0010) -+//#define DEC_CNFG_META6 (0x10300000) -+//#define DEC_CNFG_META8 (0x10400000) -+ -+#define DEC_CNFG_FER (0x01000) -+#define DEC_CNFG_EL (0x02000) -+#define DEC_CNFG_CORRECT (0x03000) -+#define DEC_CNFG_TYPE_MASK (0x03000) -+ -+#define DEC_CNFG_EMPTY_EN (0x80000000) -+ -+#define DEC_CNFG_CODE_MASK (0x1FFF0000) -+#define DEC_CNFG_CODE_SHIFT (0x10) -+ -+/* ECC_DECIDLE */ -+#define DEC_IDLE (0x0001) -+ -+/* ECC_DECFER */ -+#define DEC_FER0 (0x0001) -+#define DEC_FER1 (0x0002) -+#define DEC_FER2 (0x0004) -+#define DEC_FER3 (0x0008) -+#define DEC_FER4 (0x0010) -+#define DEC_FER5 (0x0020) -+#define DEC_FER6 (0x0040) -+#define DEC_FER7 (0x0080) -+ -+/* ECC_DECENUM */ -+#define ERR_NUM0 (0x0000000F) -+#define ERR_NUM1 (0x000000F0) -+#define ERR_NUM2 (0x00000F00) -+#define ERR_NUM3 (0x0000F000) -+#define ERR_NUM4 (0x000F0000) -+#define ERR_NUM5 (0x00F00000) -+#define ERR_NUM6 (0x0F000000) -+#define ERR_NUM7 (0xF0000000) -+ -+/* ECC_DECDONE */ -+#define DEC_DONE0 (0x0001) -+#define DEC_DONE1 (0x0002) -+#define DEC_DONE2 (0x0004) -+#define DEC_DONE3 (0x0008) -+#define DEC_DONE4 (0x0010) -+#define DEC_DONE5 (0x0020) -+#define DEC_DONE6 (0x0040) -+#define DEC_DONE7 (0x0080) -+ -+/* ECC_DECIRQEN */ -+#define DEC_IRQEN (0x0001) -+ -+/* ECC_DECIRQSTA */ -+#define DEC_IRQSTA (0x0001) -+ -+#define CHIPVER_ECO_1 (0x8a00) -+#define CHIPVER_ECO_2 (0x8a01) -+ -+//#define NAND_PFM -+ -+/******************************************************************************* -+ * Data Structure Definition -+ *******************************************************************************/ -+struct mtk_nand_host -+{ -+ struct nand_chip nand_chip; -+ struct mtd_info *mtd; -+ struct mtk_nand_host_hw *hw; -+}; -+ -+struct NAND_CMD -+{ -+ u32 u4ColAddr; -+ u32 u4RowAddr; -+ u32 u4OOBRowAddr; -+ u8 au1OOB[288]; -+ u8* pDataBuf; -+#ifdef NAND_PFM -+ u32 pureReadOOB; -+ u32 pureReadOOBNum; -+#endif -+}; -+ -+/* -+ * ECC layout control structure. Exported to userspace for -+ * diagnosis and to allow creation of raw images -+struct nand_ecclayout { -+ uint32_t eccbytes; -+ uint32_t eccpos[64]; -+ uint32_t oobavail; -+ struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; -+}; -+*/ -+#define __DEBUG_NAND 1 /* Debug information on/off */ -+ -+/* Debug message event */ -+#define DBG_EVT_NONE 0x00000000 /* No event */ -+#define DBG_EVT_INIT 0x00000001 /* Initial related event */ -+#define DBG_EVT_VERIFY 0x00000002 /* Verify buffer related event */ -+#define DBG_EVT_PERFORMANCE 0x00000004 /* Performance related event */ -+#define DBG_EVT_READ 0x00000008 /* Read related event */ -+#define DBG_EVT_WRITE 0x00000010 /* Write related event */ -+#define DBG_EVT_ERASE 0x00000020 /* Erase related event */ -+#define DBG_EVT_BADBLOCK 0x00000040 /* Badblock related event */ -+#define DBG_EVT_POWERCTL 0x00000080 /* Suspend/Resume related event */ -+ -+#define DBG_EVT_ALL 0xffffffff -+ -+#define DBG_EVT_MASK (DBG_EVT_INIT) -+ -+#if __DEBUG_NAND -+#define MSG(evt, fmt, args...) \ -+do { \ -+ if ((DBG_EVT_##evt) & DBG_EVT_MASK) { \ -+ printk(fmt, ##args); \ -+ } \ -+} while(0) -+ -+#define MSG_FUNC_ENTRY(f) MSG(FUC, "<FUN_ENT>: %s\n", __FUNCTION__) -+#else -+#define MSG(evt, fmt, args...) do{}while(0) -+#define MSG_FUNC_ENTRY(f) do{}while(0) -+#endif -+ -+#define RAMDOM_READ 1<<0 -+#define CACHE_READ 1<<1 -+ -+typedef struct -+{ -+ u16 id; //deviceid+menuid -+ u32 ext_id; -+ u8 addr_cycle; -+ u8 iowidth; -+ u16 totalsize; -+ u16 blocksize; -+ u16 pagesize; -+ u16 sparesize; -+ u32 timmingsetting; -+ char devciename[14]; -+ u32 advancedmode; // -+}flashdev_info,*pflashdev_info; -+ -+/* NAND driver */ -+#if 0 -+struct mtk_nand_host_hw { -+ unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */ -+ unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */ -+ unsigned int nfi_cs_num; /* NFI_CS_NUM */ -+ unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */ -+ unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */ -+ unsigned int nand_ecc_size; -+ unsigned int nand_ecc_bytes; -+ unsigned int nand_ecc_mode; -+}; -+extern struct mtk_nand_host_hw mt7621_nand_hw; -+extern u32 CFG_BLOCKSIZE; -+#endif -+#endif ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -48,7 +48,7 @@ - #include <linux/mtd/partitions.h> - #include <linux/of.h> - --static int nand_get_device(struct mtd_info *mtd, int new_state); -+int nand_get_device(struct mtd_info *mtd, int new_state); - - static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops); -@@ -240,7 +240,7 @@ static int check_offs_len(struct mtd_inf - * - * Release chip lock and wake up anyone waiting on the device. - */ --static void nand_release_device(struct mtd_info *mtd) -+void nand_release_device(struct mtd_info *mtd) - { - struct nand_chip *chip = mtd_to_nand(mtd); - -@@ -968,7 +968,7 @@ static void panic_nand_get_device(struct - * - * Get the device and lock it for exclusive access - */ --static int -+int - nand_get_device(struct mtd_info *mtd, int new_state) - { - struct nand_chip *chip = mtd_to_nand(mtd); ---- /dev/null -+++ b/drivers/mtd/nand/nand_def.h -@@ -0,0 +1,123 @@ -+#ifndef __NAND_DEF_H__ -+#define __NAND_DEF_H__ -+ -+#define VERSION "v2.1 Fix AHB virt2phys error" -+#define MODULE_NAME "# MTK NAND #" -+#define PROCNAME "driver/nand" -+ -+#undef TESTTIME -+//#define __UBOOT_NAND__ 1 -+#define __KERNEL_NAND__ 1 -+//#define __PRELOADER_NAND__ 1 -+//#define PMT 1 -+//#define _MTK_NAND_DUMMY_DRIVER -+//#define CONFIG_BADBLOCK_CHECK 1 -+//#ifdef CONFIG_BADBLOCK_CHECK -+//#define MTK_NAND_BMT 1 -+//#endif -+#define ECC_ENABLE 1 -+#define MANUAL_CORRECT 1 -+//#define __INTERNAL_USE_AHB_MODE__ (0) -+#define SKIP_BAD_BLOCK -+#define FACT_BBT -+ -+#ifndef NAND_OTP_SUPPORT -+#define NAND_OTP_SUPPORT 0 -+#endif -+ -+/******************************************************************************* -+ * Macro definition -+ *******************************************************************************/ -+//#define NFI_SET_REG32(reg, value) (DRV_WriteReg32(reg, DRV_Reg32(reg) | (value))) -+//#define NFI_SET_REG16(reg, value) (DRV_WriteReg16(reg, DRV_Reg16(reg) | (value))) -+//#define NFI_CLN_REG32(reg, value) (DRV_WriteReg32(reg, DRV_Reg32(reg) & (~(value)))) -+//#define NFI_CLN_REG16(reg, value) (DRV_WriteReg16(reg, DRV_Reg16(reg) & (~(value)))) -+ -+#if defined (__KERNEL_NAND__) -+#define NFI_SET_REG32(reg, value) \ -+do { \ -+ g_value = (DRV_Reg32(reg) | (value));\ -+ DRV_WriteReg32(reg, g_value); \ -+} while(0) -+ -+#define NFI_SET_REG16(reg, value) \ -+do { \ -+ g_value = (DRV_Reg16(reg) | (value));\ -+ DRV_WriteReg16(reg, g_value); \ -+} while(0) -+ -+#define NFI_CLN_REG32(reg, value) \ -+do { \ -+ g_value = (DRV_Reg32(reg) & (~(value)));\ -+ DRV_WriteReg32(reg, g_value); \ -+} while(0) -+ -+#define NFI_CLN_REG16(reg, value) \ -+do { \ -+ g_value = (DRV_Reg16(reg) & (~(value)));\ -+ DRV_WriteReg16(reg, g_value); \ -+} while(0) -+#endif -+ -+#define NFI_WAIT_STATE_DONE(state) do{;}while (__raw_readl(NFI_STA_REG32) & state) -+#define NFI_WAIT_TO_READY() do{;}while (!(__raw_readl(NFI_STA_REG32) & STA_BUSY2READY)) -+ -+ -+#define NAND_SECTOR_SIZE (512) -+#define OOB_PER_SECTOR (16) -+#define OOB_AVAI_PER_SECTOR (8) -+ -+#ifndef PART_SIZE_BMTPOOL -+#define BMT_POOL_SIZE (80) -+#else -+#define BMT_POOL_SIZE (PART_SIZE_BMTPOOL) -+#endif -+ -+#define PMT_POOL_SIZE (2) -+ -+#define TIMEOUT_1 0x1fff -+#define TIMEOUT_2 0x8ff -+#define TIMEOUT_3 0xffff -+#define TIMEOUT_4 0xffff//5000 //PIO -+ -+ -+/* temporarity definiation */ -+#if !defined (__KERNEL_NAND__) -+#define KERN_INFO -+#define KERN_WARNING -+#define KERN_ERR -+#define PAGE_SIZE (4096) -+#endif -+#define AddStorageTrace //AddStorageTrace -+#define STORAGE_LOGGER_MSG_NAND 0 -+#define NFI_BASE RALINK_NAND_CTRL_BASE -+#define NFIECC_BASE RALINK_NANDECC_CTRL_BASE -+ -+#ifdef __INTERNAL_USE_AHB_MODE__ -+#define MT65xx_POLARITY_LOW 0 -+#define MT65XX_PDN_PERI_NFI 0 -+#define MT65xx_EDGE_SENSITIVE 0 -+#define MT6575_NFI_IRQ_ID (58) -+#endif -+ -+#if defined (__KERNEL_NAND__) -+#define RALINK_REG(x) (*((volatile u32 *)(x))) -+#define __virt_to_phys(x) virt_to_phys((volatile void*)x) -+#else -+#define CONFIG_MTD_NAND_VERIFY_WRITE (1) -+#define printk printf -+#define ra_dbg printf -+#define BUG() //BUG() -+#define BUG_ON(x) //BUG_ON() -+#define NUM_PARTITIONS 1 -+#endif -+ -+#define NFI_DEFAULT_ACCESS_TIMING (0x30C77fff) //(0x44333) -+ -+//uboot only support 1 cs -+#define NFI_CS_NUM (1) -+#define NFI_DEFAULT_CS (0) -+ -+#include "mt6575_typedefs.h" -+ -+#endif /* __NAND_DEF_H__ */ ---- /dev/null -+++ b/drivers/mtd/nand/nand_device_list.h -@@ -0,0 +1,60 @@ -+/* Copyright Statement: -+ * -+ * This software/firmware and related documentation ("MediaTek Software") are -+ * protected under relevant copyright laws. The information contained herein -+ * is confidential and proprietary to MediaTek Inc. and/or its licensors. -+ * Without the prior written permission of MediaTek inc. and/or its licensors, -+ * any reproduction, modification, use or disclosure of MediaTek Software, -+ * and information contained herein, in whole or in part, shall be strictly prohibited. -+ */ -+/* MediaTek Inc. (C) 2010. All rights reserved. -+ * -+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON -+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH -+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES -+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES -+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK -+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR -+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND -+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO -+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -+ * -+ * The following software/firmware and/or related documentation ("MediaTek Software") -+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's -+ * applicable license agreements with MediaTek Inc. -+ */ -+ -+#ifndef __NAND_DEVICE_LIST_H__ -+#define __NAND_DEVICE_LIST_H__ -+ -+static const flashdev_info gen_FlashTable[]={ -+ {0x20BC, 0x105554, 5, 16, 512, 128, 2048, 64, 0x1123, "EHD013151MA_5", 0}, -+ {0xECBC, 0x005554, 5, 16, 512, 128, 2048, 64, 0x1123, "K524G2GACB_A0", 0}, -+ {0x2CBC, 0x905556, 5, 16, 512, 128, 2048, 64, 0x21044333, "MT29C4G96MAZA", 0}, -+ {0x2CDA, 0x909506, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "MT29F2G08ABAE", 0}, -+ {0xADBC, 0x905554, 5, 16, 512, 128, 2048, 64, 0x10801011, "H9DA4GH4JJAMC", 0}, -+ {0x01F1, 0x801D01, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "S34ML01G100TF", 0}, -+ {0x92F1, 0x8095FF, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81A", 0}, -+ {0xC8D1, 0x809540, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "F59L1G81MA", 0}, -+ {0xC8DA, 0x909544, 5, 8, 256, 128, 2048, 64, 0x30C77fff, "F59L2G81A", 0}, -+ {0xC8DC, 0x909554, 5, 8, 512, 128, 2048, 64, 0x30C77fff, "F59L4G81A", 0}, -+ {0xECD3, 0x519558, 5, 8, 1024, 128, 2048, 64, 0x44333, "K9K8G8000", 0}, -+ {0xC2F1, 0x801DC2, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "MX30LF1G08AA", 0}, -+ {0xC2F1, 0x809502, 4, 8, 128, 128, 2048, 64, 0x30C77fff, "MX30LF1G18AC", 0}, -+ {0x98D3, 0x902676, 5, 8, 1024, 256, 4096, 224, 0x00C25332, "TC58NVG3S0F", 0}, -+ {0x01DA, 0x909546, 5, 8, 256, 128, 2048, 128, 0x30C77fff, "S34ML02G200TF", 0}, -+ {0x01DC, 0x909556, 5, 8, 512, 128, 2048, 128, 0x30C77fff, "S34ML04G200TF", 0}, -+ {0x0000, 0x000000, 0, 0, 0, 0, 0, 0, 0, "xxxxxxxxxx", 0}, -+}; -+ -+ -+#endif ---- /dev/null -+++ b/drivers/mtd/nand/partition.h -@@ -0,0 +1,115 @@ -+/* Copyright Statement: -+ * -+ * This software/firmware and related documentation ("MediaTek Software") are -+ * protected under relevant copyright laws. The information contained herein -+ * is confidential and proprietary to MediaTek Inc. and/or its licensors. -+ * Without the prior written permission of MediaTek inc. and/or its licensors, -+ * any reproduction, modification, use or disclosure of MediaTek Software, -+ * and information contained herein, in whole or in part, shall be strictly prohibited. -+ */ -+/* MediaTek Inc. (C) 2010. All rights reserved. -+ * -+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES -+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") -+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON -+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, -+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. -+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE -+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR -+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH -+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES -+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES -+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK -+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR -+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND -+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, -+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, -+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO -+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. -+ * -+ * The following software/firmware and/or related documentation ("MediaTek Software") -+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's -+ * applicable license agreements with MediaTek Inc. -+ */ -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/rawnand.h> -+#include <linux/mtd/partitions.h> -+ -+#define RECONFIG_PARTITION_SIZE 1 -+ -+#define MTD_BOOT_PART_SIZE 0x80000 -+#define MTD_CONFIG_PART_SIZE 0x20000 -+#define MTD_FACTORY_PART_SIZE 0x20000 -+ -+extern unsigned int CFG_BLOCKSIZE; -+#define LARGE_MTD_BOOT_PART_SIZE (CFG_BLOCKSIZE<<2) -+#define LARGE_MTD_CONFIG_PART_SIZE (CFG_BLOCKSIZE<<2) -+#define LARGE_MTD_FACTORY_PART_SIZE (CFG_BLOCKSIZE<<1) -+ -+/*=======================================================================*/ -+/* NAND PARTITION Mapping */ -+/*=======================================================================*/ -+//#ifdef CONFIG_MTD_PARTITIONS -+static struct mtd_partition g_pasStatic_Partition[] = { -+ { -+ name: "ALL", -+ size: MTDPART_SIZ_FULL, -+ offset: 0, -+ }, -+ /* Put your own partition definitions here */ -+ { -+ name: "Bootloader", -+ size: MTD_BOOT_PART_SIZE, -+ offset: 0, -+ }, { -+ name: "Config", -+ size: MTD_CONFIG_PART_SIZE, -+ offset: MTDPART_OFS_APPEND -+ }, { -+ name: "Factory", -+ size: MTD_FACTORY_PART_SIZE, -+ offset: MTDPART_OFS_APPEND -+#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH -+ }, { -+ name: "Kernel", -+ size: MTD_KERN_PART_SIZE, -+ offset: MTDPART_OFS_APPEND, -+ }, { -+ name: "RootFS", -+ size: MTD_ROOTFS_PART_SIZE, -+ offset: MTDPART_OFS_APPEND, -+#ifdef CONFIG_ROOTFS_IN_FLASH_NO_PADDING -+ }, { -+ name: "Kernel_RootFS", -+ size: MTD_KERN_PART_SIZE + MTD_ROOTFS_PART_SIZE, -+ offset: MTD_BOOT_PART_SIZE + MTD_CONFIG_PART_SIZE + MTD_FACTORY_PART_SIZE, -+#endif -+#else //CONFIG_RT2880_ROOTFS_IN_RAM -+ }, { -+ name: "Kernel", -+ size: 0x10000, -+ offset: MTDPART_OFS_APPEND, -+#endif -+#ifdef CONFIG_DUAL_IMAGE -+ }, { -+ name: "Kernel2", -+ size: MTD_KERN2_PART_SIZE, -+ offset: MTD_KERN2_PART_OFFSET, -+#ifdef CONFIG_RT2880_ROOTFS_IN_FLASH -+ }, { -+ name: "RootFS2", -+ size: MTD_ROOTFS2_PART_SIZE, -+ offset: MTD_ROOTFS2_PART_OFFSET, -+#endif -+#endif -+ } -+ -+}; -+ -+#define NUM_PARTITIONS ARRAY_SIZE(g_pasStatic_Partition) -+extern int part_num; // = NUM_PARTITIONS; -+//#endif -+#undef RECONFIG_PARTITION_SIZE -+ diff --git a/target/linux/ramips/patches-5.4/0040-nand-hack.patch b/target/linux/ramips/patches-5.4/0040-nand-hack.patch deleted file mode 100644 index 58cdf1bce7..0000000000 --- a/target/linux/ramips/patches-5.4/0040-nand-hack.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1908,6 +1908,9 @@ static int nand_do_read_ops(struct mtd_i - __func__, buf); - - read_retry: -+#ifdef CONFIG_MTK_MTD_NAND -+ ret = chip->read_page(mtd, chip, bufpoi, page); -+#else - if (nand_standard_page_accessors(&chip->ecc)) - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - -@@ -1927,6 +1930,7 @@ read_retry: - else - ret = chip->ecc.read_page(mtd, chip, bufpoi, - oob_required, page); -+#endif - if (ret < 0) { - if (use_bufpoi) - /* Invalidate page cache */ ---- a/include/linux/mtd/rawnand.h -+++ b/include/linux/mtd/rawnand.h -@@ -897,6 +897,9 @@ struct nand_chip { - int (*setup_data_interface)(struct mtd_info *mtd, int chipnr, - const struct nand_data_interface *conf); - -+#ifdef CONFIG_MTK_MTD_NAND -+ int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int page); -+#endif /* CONFIG_MTK_MTD_NAND */ - - int chip_delay; - unsigned int options; diff --git a/target/linux/ramips/patches-5.4/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-5.4/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch index 1dd9f40c39..652371617a 100644 --- a/target/linux/ramips/patches-5.4/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch +++ b/target/linux/ramips/patches-5.4/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch @@ -16,9 +16,9 @@ Acked-by: John Crispin <blogic@openwrt.org> --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -563,6 +563,12 @@ config SPI_QUP +@@ -605,6 +605,12 @@ config SPI_QCOM_GENI This driver can also be built as a module. If so, the module - will be called spi_qup. + will be called spi-geni-qcom. +config SPI_RT2880 + tristate "Ralink RT288x SPI Controller" @@ -31,7 +31,7 @@ Acked-by: John Crispin <blogic@openwrt.org> depends on ARCH_S3C24XX --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -81,6 +81,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o +@@ -87,6 +87,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o diff --git a/target/linux/ramips/patches-5.4/0043-spi-add-mt7621-support.patch b/target/linux/ramips/patches-5.4/0043-spi-add-mt7621-support.patch deleted file mode 100644 index b607f2bdf4..0000000000 --- a/target/linux/ramips/patches-5.4/0043-spi-add-mt7621-support.patch +++ /dev/null @@ -1,487 +0,0 @@ -From cbd66c626e16743b05af807ad48012c0a097b9fb Mon Sep 17 00:00:00 2001 -From: Stefan Roese <sr@denx.de> -Date: Mon, 25 Mar 2019 09:29:25 +0100 -Subject: [PATCH] spi: mt7621: Move SPI driver out of staging - -This patch moves the MT7621 SPI driver, which is used on some Ralink / -MediaTek MT76xx MIPS SoC's, out of the staging directory. No changes to -the source code are done in this patch. - -This driver version was tested successfully on an MT7688 based platform -with an SPI NOR on CS0 and an SPI NAND on CS1 without any issues (so -far). - -This patch also documents the devicetree bindings for the MT7621 SPI -device driver. - -Signed-off-by: Stefan Roese <sr@denx.de> -Cc: Rob Herring <robh@kernel.org> -Cc: Mark Brown <broonie@kernel.org> -Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -Cc: NeilBrown <neil@brown.name> -Cc: Sankalp Negi <sankalpnegi2310@gmail.com> -Cc: Chuanhong Guo <gch981213@gmail.com> -Cc: John Crispin <john@phrozen.org> -Cc: Armando Miraglia <arma2ff0@gmail.com> -Signed-off-by: Mark Brown <broonie@kernel.org> ---- - .../devicetree/bindings/spi/spi-mt7621.txt | 26 ++++++ - drivers/spi/Kconfig | 6 ++ - drivers/spi/Makefile | 1 + - .../{staging/mt7621-spi => spi}/spi-mt7621.c | 83 +++++++++---------- - drivers/staging/Kconfig | 2 - - drivers/staging/Makefile | 1 - - drivers/staging/mt7621-spi/Kconfig | 6 -- - drivers/staging/mt7621-spi/Makefile | 1 - - drivers/staging/mt7621-spi/TODO | 5 -- - 9 files changed, 74 insertions(+), 57 deletions(-) - create mode 100644 Documentation/devicetree/bindings/spi/spi-mt7621.txt - rename drivers/{staging/mt7621-spi => spi}/spi-mt7621.c (88%) - delete mode 100644 drivers/staging/mt7621-spi/Kconfig - delete mode 100644 drivers/staging/mt7621-spi/Makefile - delete mode 100644 drivers/staging/mt7621-spi/TODO - ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -569,6 +569,12 @@ config SPI_RT2880 - help - This selects a driver for the Ralink RT288x/RT305x SPI Controller. - -+config SPI_MT7621 -+ tristate "MediaTek MT7621 SPI Controller" -+ depends on RALINK -+ help -+ This selects a driver for the MediaTek MT7621 SPI Controller. -+ - config SPI_S3C24XX - tristate "Samsung S3C24XX series SPI" - depends on ARCH_S3C24XX ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -60,6 +60,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_MT7621) += spi-mt7621.o - obj-$(CONFIG_SPI_MXS) += spi-mxs.o - obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o - obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o ---- /dev/null -+++ b/drivers/spi/spi-mt7621.c -@@ -0,0 +1,416 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// -+// spi-mt7621.c -- MediaTek MT7621 SPI controller driver -+// -+// Copyright (C) 2011 Sergiy <piratfm@gmail.com> -+// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> -+// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> -+// -+// Some parts are based on spi-orion.c: -+// Author: Shadi Ammouri <shadi@marvell.com> -+// Copyright (C) 2007-2008 Marvell Ltd. -+ -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/of_device.h> -+#include <linux/reset.h> -+#include <linux/spi/spi.h> -+ -+#define DRIVER_NAME "spi-mt7621" -+ -+/* in usec */ -+#define RALINK_SPI_WAIT_MAX_LOOP 2000 -+ -+/* SPISTAT register bit field */ -+#define SPISTAT_BUSY BIT(0) -+ -+#define MT7621_SPI_TRANS 0x00 -+#define SPITRANS_BUSY BIT(16) -+ -+#define MT7621_SPI_OPCODE 0x04 -+#define MT7621_SPI_DATA0 0x08 -+#define MT7621_SPI_DATA4 0x18 -+#define SPI_CTL_TX_RX_CNT_MASK 0xff -+#define SPI_CTL_START BIT(8) -+ -+#define MT7621_SPI_MASTER 0x28 -+#define MASTER_MORE_BUFMODE BIT(2) -+#define MASTER_FULL_DUPLEX BIT(10) -+#define MASTER_RS_CLK_SEL GENMASK(27, 16) -+#define MASTER_RS_CLK_SEL_SHIFT 16 -+#define MASTER_RS_SLAVE_SEL GENMASK(31, 29) -+ -+#define MT7621_SPI_MOREBUF 0x2c -+#define MT7621_SPI_POLAR 0x38 -+#define MT7621_SPI_SPACE 0x3c -+ -+#define MT7621_CPHA BIT(5) -+#define MT7621_CPOL BIT(4) -+#define MT7621_LSB_FIRST BIT(3) -+ -+struct mt7621_spi { -+ struct spi_controller *master; -+ void __iomem *base; -+ unsigned int sys_freq; -+ unsigned int speed; -+ struct clk *clk; -+ int pending_write; -+}; -+ -+static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) -+{ -+ return spi_controller_get_devdata(spi->master); -+} -+ -+static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg) -+{ -+ return ioread32(rs->base + reg); -+} -+ -+static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) -+{ -+ iowrite32(val, rs->base + reg); -+} -+ -+static void mt7621_spi_set_cs(struct spi_device *spi, int enable) -+{ -+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); -+ int cs = spi->chip_select; -+ u32 polar = 0; -+ u32 master; -+ -+ /* -+ * Select SPI device 7, enable "more buffer mode" and disable -+ * full-duplex (only half-duplex really works on this chip -+ * reliably) -+ */ -+ master = mt7621_spi_read(rs, MT7621_SPI_MASTER); -+ master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE; -+ master &= ~MASTER_FULL_DUPLEX; -+ mt7621_spi_write(rs, MT7621_SPI_MASTER, master); -+ -+ rs->pending_write = 0; -+ -+ if (enable) -+ polar = BIT(cs); -+ mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); -+} -+ -+static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed) -+{ -+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); -+ u32 rate; -+ u32 reg; -+ -+ dev_dbg(&spi->dev, "speed:%u\n", speed); -+ -+ rate = DIV_ROUND_UP(rs->sys_freq, speed); -+ dev_dbg(&spi->dev, "rate-1:%u\n", rate); -+ -+ if (rate > 4097) -+ return -EINVAL; -+ -+ if (rate < 2) -+ rate = 2; -+ -+ reg = mt7621_spi_read(rs, MT7621_SPI_MASTER); -+ reg &= ~MASTER_RS_CLK_SEL; -+ reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT; -+ rs->speed = speed; -+ -+ reg &= ~MT7621_LSB_FIRST; -+ if (spi->mode & SPI_LSB_FIRST) -+ reg |= MT7621_LSB_FIRST; -+ -+ /* -+ * This SPI controller seems to be tested on SPI flash only and some -+ * bits are swizzled under other SPI modes probably due to incorrect -+ * wiring inside the silicon. Only mode 0 works correctly. -+ */ -+ reg &= ~(MT7621_CPHA | MT7621_CPOL); -+ -+ mt7621_spi_write(rs, MT7621_SPI_MASTER, reg); -+ -+ return 0; -+} -+ -+static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs) -+{ -+ int i; -+ -+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { -+ u32 status; -+ -+ status = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ if ((status & SPITRANS_BUSY) == 0) -+ return 0; -+ cpu_relax(); -+ udelay(1); -+ } -+ -+ return -ETIMEDOUT; -+} -+ -+static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, -+ int rx_len, u8 *buf) -+{ -+ int tx_len; -+ -+ /* -+ * Combine with any pending write, and perform one or more half-duplex -+ * transactions reading 'len' bytes. Data to be written is already in -+ * MT7621_SPI_DATA. -+ */ -+ tx_len = rs->pending_write; -+ rs->pending_write = 0; -+ -+ while (rx_len || tx_len) { -+ int i; -+ u32 val = (min(tx_len, 4) * 8) << 24; -+ int rx = min(rx_len, 32); -+ -+ if (tx_len > 4) -+ val |= (tx_len - 4) * 8; -+ val |= (rx * 8) << 12; -+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); -+ -+ tx_len = 0; -+ -+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS); -+ val |= SPI_CTL_START; -+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val); -+ -+ mt7621_spi_wait_till_ready(rs); -+ -+ for (i = 0; i < rx; i++) { -+ if ((i % 4) == 0) -+ val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); -+ *buf++ = val & 0xff; -+ val >>= 8; -+ } -+ -+ rx_len -= i; -+ } -+} -+ -+static inline void mt7621_spi_flush(struct mt7621_spi *rs) -+{ -+ mt7621_spi_read_half_duplex(rs, 0, NULL); -+} -+ -+static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, -+ int tx_len, const u8 *buf) -+{ -+ int len = rs->pending_write; -+ int val = 0; -+ -+ if (len & 3) { -+ val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3)); -+ if (len < 4) { -+ val <<= (4 - len) * 8; -+ val = swab32(val); -+ } -+ } -+ -+ while (tx_len > 0) { -+ if (len >= 36) { -+ rs->pending_write = len; -+ mt7621_spi_flush(rs); -+ len = 0; -+ } -+ -+ val |= *buf++ << (8 * (len & 3)); -+ len++; -+ if ((len & 3) == 0) { -+ if (len == 4) -+ /* The byte-order of the opcode is weird! */ -+ val = swab32(val); -+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val); -+ val = 0; -+ } -+ tx_len -= 1; -+ } -+ -+ if (len & 3) { -+ if (len < 4) { -+ val = swab32(val); -+ val >>= (4 - len) * 8; -+ } -+ mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val); -+ } -+ -+ rs->pending_write = len; -+} -+ -+static int mt7621_spi_transfer_one_message(struct spi_controller *master, -+ struct spi_message *m) -+{ -+ struct mt7621_spi *rs = spi_controller_get_devdata(master); -+ struct spi_device *spi = m->spi; -+ unsigned int speed = spi->max_speed_hz; -+ struct spi_transfer *t = NULL; -+ int status = 0; -+ -+ mt7621_spi_wait_till_ready(rs); -+ -+ list_for_each_entry(t, &m->transfers, transfer_list) -+ if (t->speed_hz < speed) -+ speed = t->speed_hz; -+ -+ if (mt7621_spi_prepare(spi, speed)) { -+ status = -EIO; -+ goto msg_done; -+ } -+ -+ /* Assert CS */ -+ mt7621_spi_set_cs(spi, 1); -+ -+ m->actual_length = 0; -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ if ((t->rx_buf) && (t->tx_buf)) { -+ /* -+ * This controller will shift some extra data out -+ * of spi_opcode if (mosi_bit_cnt > 0) && -+ * (cmd_bit_cnt == 0). So the claimed full-duplex -+ * support is broken since we have no way to read -+ * the MISO value during that bit. -+ */ -+ status = -EIO; -+ goto msg_done; -+ } else if (t->rx_buf) { -+ mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); -+ } else if (t->tx_buf) { -+ mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); -+ } -+ m->actual_length += t->len; -+ } -+ -+ /* Flush data and deassert CS */ -+ mt7621_spi_flush(rs); -+ mt7621_spi_set_cs(spi, 0); -+ -+msg_done: -+ m->status = status; -+ spi_finalize_current_message(master); -+ -+ return 0; -+} -+ -+static int mt7621_spi_setup(struct spi_device *spi) -+{ -+ struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); -+ -+ if ((spi->max_speed_hz == 0) || -+ (spi->max_speed_hz > (rs->sys_freq / 2))) -+ spi->max_speed_hz = (rs->sys_freq / 2); -+ -+ if (spi->max_speed_hz < (rs->sys_freq / 4097)) { -+ dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", -+ spi->max_speed_hz); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct of_device_id mt7621_spi_match[] = { -+ { .compatible = "ralink,mt7621-spi" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mt7621_spi_match); -+ -+static int mt7621_spi_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *match; -+ struct spi_controller *master; -+ struct mt7621_spi *rs; -+ void __iomem *base; -+ struct resource *r; -+ int status = 0; -+ struct clk *clk; -+ int ret; -+ -+ match = of_match_device(mt7621_spi_match, &pdev->dev); -+ if (!match) -+ return -EINVAL; -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, r); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n", -+ status); -+ return PTR_ERR(clk); -+ } -+ -+ status = clk_prepare_enable(clk); -+ if (status) -+ return status; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*rs)); -+ if (!master) { -+ dev_info(&pdev->dev, "master allocation failed\n"); -+ return -ENOMEM; -+ } -+ -+ master->mode_bits = SPI_LSB_FIRST; -+ master->flags = SPI_CONTROLLER_HALF_DUPLEX; -+ master->setup = mt7621_spi_setup; -+ master->transfer_one_message = mt7621_spi_transfer_one_message; -+ master->bits_per_word_mask = SPI_BPW_MASK(8); -+ master->dev.of_node = pdev->dev.of_node; -+ master->num_chipselect = 2; -+ -+ dev_set_drvdata(&pdev->dev, master); -+ -+ rs = spi_controller_get_devdata(master); -+ rs->base = base; -+ rs->clk = clk; -+ rs->master = master; -+ rs->sys_freq = clk_get_rate(rs->clk); -+ rs->pending_write = 0; -+ dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); -+ -+ ret = device_reset(&pdev->dev); -+ if (ret) { -+ dev_err(&pdev->dev, "SPI reset failed!\n"); -+ return ret; -+ } -+ -+ return devm_spi_register_controller(&pdev->dev, master); -+} -+ -+static int mt7621_spi_remove(struct platform_device *pdev) -+{ -+ struct spi_controller *master; -+ struct mt7621_spi *rs; -+ -+ master = dev_get_drvdata(&pdev->dev); -+ rs = spi_controller_get_devdata(master); -+ -+ clk_disable_unprepare(rs->clk); -+ -+ return 0; -+} -+ -+MODULE_ALIAS("platform:" DRIVER_NAME); -+ -+static struct platform_driver mt7621_spi_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .of_match_table = mt7621_spi_match, -+ }, -+ .probe = mt7621_spi_probe, -+ .remove = mt7621_spi_remove, -+}; -+ -+module_platform_driver(mt7621_spi_driver); -+ -+MODULE_DESCRIPTION("MT7621 SPI driver"); -+MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/ramips/patches-5.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-5.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch index 4905aba046..e3bb7f2488 100644 --- a/target/linux/ramips/patches-5.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch +++ b/target/linux/ramips/patches-5.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch @@ -45,7 +45,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> +}; --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -864,6 +864,11 @@ config I2C_RK3X +@@ -922,6 +922,11 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. @@ -59,14 +59,14 @@ Signed-off-by: John Crispin <blogic@openwrt.org> help --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile -@@ -84,6 +84,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o +@@ -91,6 +91,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o +obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o + obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o - obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o --- /dev/null +++ b/drivers/i2c/busses/i2c-ralink.c @@ -0,0 +1,435 @@ diff --git a/target/linux/ramips/patches-5.4/0045-i2c-add-mt7621-driver.patch b/target/linux/ramips/patches-5.4/0045-i2c-add-mt7621-driver.patch deleted file mode 100644 index a848085520..0000000000 --- a/target/linux/ramips/patches-5.4/0045-i2c-add-mt7621-driver.patch +++ /dev/null @@ -1,473 +0,0 @@ -From d5c54ff3d1db0a4348fa04d8e78f3bf6063e3afc Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Mon, 7 Dec 2015 17:21:27 +0100 -Subject: [PATCH 45/53] i2c: add mt7621 driver - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/i2c/busses/Kconfig | 4 + - drivers/i2c/busses/Makefile | 1 + - drivers/i2c/busses/i2c-mt7621.c | 303 +++++++++++++++++++++++++++++++++++++++ - 3 files changed, 308 insertions(+) - create mode 100644 drivers/i2c/busses/i2c-mt7621.c - ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -869,6 +869,11 @@ config I2C_RALINK - depends on RALINK && !SOC_MT7621 - select OF_I2C - -+config I2C_MT7621 -+ tristate "MT7621/MT7628 I2C Controller" -+ depends on RALINK && (SOC_MT7620 || SOC_MT7621) -+ select OF_I2C -+ - config HAVE_S3C2410_I2C - bool - help ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o - obj-$(CONFIG_I2C_PXA) += i2c-pxa.o - obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o - obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o -+obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o - obj-$(CONFIG_I2C_QUP) += i2c-qup.o - obj-$(CONFIG_I2C_RIIC) += i2c-riic.o - obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o ---- /dev/null -+++ b/drivers/i2c/busses/i2c-mt7621.c -@@ -0,0 +1,433 @@ -+/* -+ * drivers/i2c/busses/i2c-mt7621.c -+ * -+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> -+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> -+ * -+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. -+ * (C) 2014 Sittisak <sittisaks@hotmail.com> -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ */ -+ -+#include <linux/interrupt.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/reset.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/errno.h> -+#include <linux/platform_device.h> -+#include <linux/of_platform.h> -+#include <linux/i2c.h> -+#include <linux/io.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+ -+#define REG_SM0CFG0 0x08 -+#define REG_SM0DOUT 0x10 -+#define REG_SM0DIN 0x14 -+#define REG_SM0ST 0x18 -+#define REG_SM0AUTO 0x1C -+#define REG_SM0CFG1 0x20 -+#define REG_SM0CFG2 0x28 -+#define REG_SM0CTL0 0x40 -+#define REG_SM0CTL1 0x44 -+#define REG_SM0D0 0x50 -+#define REG_SM0D1 0x54 -+#define REG_PINTEN 0x5C -+#define REG_PINTST 0x60 -+#define REG_PINTCL 0x64 -+ -+/* REG_SM0CFG0 */ -+#define I2C_DEVADDR_MASK 0x7f -+ -+/* REG_SM0ST */ -+#define I2C_DATARDY BIT(2) -+#define I2C_SDOEMPTY BIT(1) -+#define I2C_BUSY BIT(0) -+ -+/* REG_SM0AUTO */ -+#define READ_CMD BIT(0) -+ -+/* REG_SM0CFG1 */ -+#define BYTECNT_MAX 64 -+#define SET_BYTECNT(x) (x - 1) -+ -+/* REG_SM0CFG2 */ -+#define AUTOMODE_EN BIT(0) -+ -+/* REG_SM0CTL0 */ -+#define ODRAIN_HIGH_SM0 BIT(31) -+#define VSYNC_SHIFT 28 -+#define VSYNC_MASK 0x3 -+#define VSYNC_PULSE (0x1 << VSYNC_SHIFT) -+#define VSYNC_RISING (0x2 << VSYNC_SHIFT) -+#define CLK_DIV_SHIFT 16 -+#define CLK_DIV_MASK 0xfff -+#define DEG_CNT_SHIFT 8 -+#define DEG_CNT_MASK 0xff -+#define WAIT_HIGH BIT(6) -+#define DEG_EN BIT(5) -+#define CS_STATUA BIT(4) -+#define SCL_STATUS BIT(3) -+#define SDA_STATUS BIT(2) -+#define SM0_EN BIT(1) -+#define SCL_STRECH BIT(0) -+ -+/* REG_SM0CTL1 */ -+#define ACK_SHIFT 16 -+#define ACK_MASK 0xff -+#define PGLEN_SHIFT 8 -+#define PGLEN_MASK 0x7 -+#define SM0_MODE_SHIFT 4 -+#define SM0_MODE_MASK 0x7 -+#define SM0_MODE_START 0x1 -+#define SM0_MODE_WRITE 0x2 -+#define SM0_MODE_STOP 0x3 -+#define SM0_MODE_READ_NACK 0x4 -+#define SM0_MODE_READ_ACK 0x5 -+#define SM0_TRI_BUSY BIT(0) -+ -+/* timeout waiting for I2C devices to respond (clock streching) */ -+#define TIMEOUT_MS 1000 -+#define DELAY_INTERVAL_US 100 -+ -+struct mtk_i2c { -+ void __iomem *base; -+ struct clk *clk; -+ struct device *dev; -+ struct i2c_adapter adap; -+ u32 cur_clk; -+ u32 clk_div; -+ u32 flags; -+}; -+ -+static void mtk_i2c_w32(struct mtk_i2c *i2c, u32 val, unsigned reg) -+{ -+ iowrite32(val, i2c->base + reg); -+} -+ -+static u32 mtk_i2c_r32(struct mtk_i2c *i2c, unsigned reg) -+{ -+ return ioread32(i2c->base + reg); -+} -+ -+static int poll_down_timeout(void __iomem *addr, u32 mask) -+{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); -+ -+ do { -+ if (!(readl_relaxed(addr) & mask)) -+ return 0; -+ -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); -+ -+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; -+} -+ -+static int mtk_i2c_wait_idle(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ ret = poll_down_timeout(i2c->base + REG_SM0ST, I2C_BUSY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "idle err(%d)\n", ret); -+ -+ return ret; -+} -+ -+static int poll_up_timeout(void __iomem *addr, u32 mask) -+{ -+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); -+ u32 status; -+ -+ do { -+ status = readl_relaxed(addr); -+ if (status & mask) -+ return 0; -+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); -+ } while (time_before(jiffies, timeout)); -+ -+ return -ETIMEDOUT; -+} -+ -+static int mtk_i2c_wait_rx_done(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_DATARDY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "rx err(%d)\n", ret); -+ -+ return ret; -+} -+ -+static int mtk_i2c_wait_tx_done(struct mtk_i2c *i2c) -+{ -+ int ret; -+ -+ ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_SDOEMPTY); -+ if (ret < 0) -+ dev_dbg(i2c->dev, "tx err(%d)\n", ret); -+ -+ return ret; -+} -+ -+static void mtk_i2c_reset(struct mtk_i2c *i2c) -+{ -+ u32 reg; -+ device_reset(i2c->adap.dev.parent); -+ barrier(); -+ -+ /* ctrl0 */ -+ reg = ODRAIN_HIGH_SM0 | VSYNC_PULSE | (i2c->clk_div << CLK_DIV_SHIFT) | -+ WAIT_HIGH | SM0_EN; -+ mtk_i2c_w32(i2c, reg, REG_SM0CTL0); -+ -+ /* auto mode */ -+ mtk_i2c_w32(i2c, AUTOMODE_EN, REG_SM0CFG2); -+} -+ -+static void mtk_i2c_dump_reg(struct mtk_i2c *i2c) -+{ -+ dev_dbg(i2c->dev, "cfg0 %08x, dout %08x, din %08x, " \ -+ "status %08x, auto %08x, cfg1 %08x, " \ -+ "cfg2 %08x, ctl0 %08x, ctl1 %08x\n", -+ mtk_i2c_r32(i2c, REG_SM0CFG0), -+ mtk_i2c_r32(i2c, REG_SM0DOUT), -+ mtk_i2c_r32(i2c, REG_SM0DIN), -+ mtk_i2c_r32(i2c, REG_SM0ST), -+ mtk_i2c_r32(i2c, REG_SM0AUTO), -+ mtk_i2c_r32(i2c, REG_SM0CFG1), -+ mtk_i2c_r32(i2c, REG_SM0CFG2), -+ mtk_i2c_r32(i2c, REG_SM0CTL0), -+ mtk_i2c_r32(i2c, REG_SM0CTL1)); -+} -+ -+static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, -+ int num) -+{ -+ struct mtk_i2c *i2c; -+ struct i2c_msg *pmsg; -+ int i, j, ret; -+ u32 cmd; -+ -+ i2c = i2c_get_adapdata(adap); -+ -+ for (i = 0; i < num; i++) { -+ pmsg = &msgs[i]; -+ cmd = 0; -+ -+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x\n", -+ pmsg->addr, pmsg->len, pmsg->flags); -+ -+ /* wait hardware idle */ -+ if ((ret = mtk_i2c_wait_idle(i2c))) -+ goto err_timeout; -+ -+ if (pmsg->flags & I2C_M_TEN) { -+ dev_dbg(i2c->dev, "10 bits addr not supported\n"); -+ return -EINVAL; -+ } else { -+ /* 7 bits address */ -+ mtk_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, -+ REG_SM0CFG0); -+ } -+ -+ /* buffer length */ -+ if (pmsg->len == 0) { -+ dev_dbg(i2c->dev, "length is 0\n"); -+ return -EINVAL; -+ } else -+ mtk_i2c_w32(i2c, SET_BYTECNT(pmsg->len), -+ REG_SM0CFG1); -+ -+ j = 0; -+ if (pmsg->flags & I2C_M_RD) { -+ cmd |= READ_CMD; -+ /* start transfer */ -+ barrier(); -+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); -+ do { -+ /* wait */ -+ if ((ret = mtk_i2c_wait_rx_done(i2c))) -+ goto err_timeout; -+ /* read data */ -+ if (pmsg->len) -+ pmsg->buf[j] = mtk_i2c_r32(i2c, -+ REG_SM0DIN); -+ j++; -+ } while (j < pmsg->len); -+ } else { -+ do { -+ /* write data */ -+ if (pmsg->len) -+ mtk_i2c_w32(i2c, pmsg->buf[j], -+ REG_SM0DOUT); -+ /* start transfer */ -+ if (j == 0) { -+ barrier(); -+ mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); -+ } -+ /* wait */ -+ if ((ret = mtk_i2c_wait_tx_done(i2c))) -+ goto err_timeout; -+ j++; -+ } while (j < pmsg->len); -+ } -+ } -+ /* the return value is number of executed messages */ -+ ret = i; -+ -+ return ret; -+ -+err_timeout: -+ mtk_i2c_dump_reg(i2c); -+ mtk_i2c_reset(i2c); -+ return ret; -+} -+ -+static u32 mtk_i2c_func(struct i2c_adapter *a) -+{ -+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -+} -+ -+static const struct i2c_algorithm mtk_i2c_algo = { -+ .master_xfer = mtk_i2c_master_xfer, -+ .functionality = mtk_i2c_func, -+}; -+ -+static const struct of_device_id i2c_mtk_dt_ids[] = { -+ { .compatible = "mediatek,mt7621-i2c" }, -+ { /* sentinel */ } -+}; -+ -+MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids); -+ -+static struct i2c_adapter_quirks mtk_i2c_quirks = { -+ .max_write_len = BYTECNT_MAX, -+ .max_read_len = BYTECNT_MAX, -+}; -+ -+static void mtk_i2c_init(struct mtk_i2c *i2c) -+{ -+ i2c->clk_div = clk_get_rate(i2c->clk) / i2c->cur_clk; -+ if (i2c->clk_div > CLK_DIV_MASK) -+ i2c->clk_div = CLK_DIV_MASK; -+ -+ mtk_i2c_reset(i2c); -+} -+ -+static int mtk_i2c_probe(struct platform_device *pdev) -+{ -+ struct resource *res; -+ struct mtk_i2c *i2c; -+ struct i2c_adapter *adap; -+ const struct of_device_id *match; -+ int ret; -+ -+ match = of_match_device(i2c_mtk_dt_ids, &pdev->dev); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) { -+ dev_err(&pdev->dev, "no memory resource found\n"); -+ return -ENODEV; -+ } -+ -+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); -+ if (!i2c) { -+ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); -+ return -ENOMEM; -+ } -+ -+ i2c->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(i2c->base)) -+ return PTR_ERR(i2c->base); -+ -+ i2c->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(i2c->clk)) { -+ dev_err(&pdev->dev, "no clock defined\n"); -+ return -ENODEV; -+ } -+ clk_prepare_enable(i2c->clk); -+ i2c->dev = &pdev->dev; -+ -+ if (of_property_read_u32(pdev->dev.of_node, -+ "clock-frequency", &i2c->cur_clk)) -+ i2c->cur_clk = 100000; -+ -+ adap = &i2c->adap; -+ adap->owner = THIS_MODULE; -+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; -+ adap->algo = &mtk_i2c_algo; -+ adap->retries = 3; -+ adap->dev.parent = &pdev->dev; -+ i2c_set_adapdata(adap, i2c); -+ adap->dev.of_node = pdev->dev.of_node; -+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); -+ adap->quirks = &mtk_i2c_quirks; -+ -+ platform_set_drvdata(pdev, i2c); -+ -+ mtk_i2c_init(i2c); -+ -+ ret = i2c_add_adapter(adap); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to add adapter\n"); -+ clk_disable_unprepare(i2c->clk); -+ return ret; -+ } -+ -+ dev_info(&pdev->dev, "clock %uKHz, re-start not support\n", -+ i2c->cur_clk/1000); -+ -+ return ret; -+} -+ -+static int mtk_i2c_remove(struct platform_device *pdev) -+{ -+ struct mtk_i2c *i2c = platform_get_drvdata(pdev); -+ -+ i2c_del_adapter(&i2c->adap); -+ clk_disable_unprepare(i2c->clk); -+ -+ return 0; -+} -+ -+static struct platform_driver mtk_i2c_driver = { -+ .probe = mtk_i2c_probe, -+ .remove = mtk_i2c_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "i2c-mt7621", -+ .of_match_table = i2c_mtk_dt_ids, -+ }, -+}; -+ -+static int __init i2c_mtk_init (void) -+{ -+ return platform_driver_register(&mtk_i2c_driver); -+} -+subsys_initcall(i2c_mtk_init); -+ -+static void __exit i2c_mtk_exit (void) -+{ -+ platform_driver_unregister(&mtk_i2c_driver); -+} -+module_exit(i2c_mtk_exit); -+ -+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); -+MODULE_DESCRIPTION("MT7621 I2c host driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:MT7621-I2C"); diff --git a/target/linux/ramips/patches-5.4/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch b/target/linux/ramips/patches-5.4/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch index 0535811ea3..f3912a1054 100644 --- a/target/linux/ramips/patches-5.4/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch +++ b/target/linux/ramips/patches-5.4/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch @@ -25,9 +25,9 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig -@@ -901,3 +901,5 @@ config MMC_SDHCI_XENON - This selects Marvell Xenon eMMC/SD/SDIO SDHCI. +@@ -1019,3 +1019,5 @@ config MMC_SDHCI_AM654 If you have a controller with this interface, say Y or M here. + If unsure, say N. + +source "drivers/mmc/host/mtk-mmc/Kconfig" diff --git a/target/linux/ramips/patches-5.4/0047-DMA-ralink-add-rt2880-dma-engine.patch b/target/linux/ramips/patches-5.4/0047-DMA-ralink-add-rt2880-dma-engine.patch deleted file mode 100644 index b74a48a220..0000000000 --- a/target/linux/ramips/patches-5.4/0047-DMA-ralink-add-rt2880-dma-engine.patch +++ /dev/null @@ -1,1757 +0,0 @@ -From f1c4d9e622c800e1f38b3818f933ec7597d1ccfb Mon Sep 17 00:00:00 2001 -From: John Crispin <blogic@openwrt.org> -Date: Sun, 27 Jul 2014 09:29:51 +0100 -Subject: [PATCH 47/53] DMA: ralink: add rt2880 dma engine - -Signed-off-by: John Crispin <blogic@openwrt.org> ---- - drivers/dma/Kconfig | 6 + - drivers/dma/Makefile | 1 + - drivers/dma/ralink-gdma.c | 577 +++++++++++++++++++++++++++++++++++++++++++++ - include/linux/dmaengine.h | 1 + - 4 files changed, 585 insertions(+) - create mode 100644 drivers/dma/ralink-gdma.c - ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -40,6 +40,18 @@ config ASYNC_TX_ENABLE_CHANNEL_SWITCH - config ARCH_HAS_ASYNC_TX_FIND_CHANNEL - bool - -+config DMA_RALINK -+ tristate "RALINK DMA support" -+ depends on RALINK && !SOC_RT288X -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ -+config MTK_HSDMA -+ tristate "MTK HSDMA support" -+ depends on RALINK && SOC_MT7621 -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ - config DMA_ENGINE - bool - ---- a/drivers/dma/Makefile -+++ b/drivers/dma/Makefile -@@ -71,6 +71,8 @@ obj-$(CONFIG_TI_EDMA) += edma.o - obj-$(CONFIG_XGENE_DMA) += xgene-dma.o - obj-$(CONFIG_ZX_DMA) += zx_dma.o - obj-$(CONFIG_ST_FDMA) += st_fdma.o -+obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o -+obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o - - obj-y += qcom/ - obj-y += xilinx/ ---- /dev/null -+++ b/drivers/dma/ralink-gdma.c -@@ -0,0 +1,928 @@ -+/* -+ * Copyright (C) 2013, Lars-Peter Clausen <lars@metafoo.de> -+ * GDMA4740 DMAC support -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include <linux/dmaengine.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/irq.h> -+#include <linux/of_dma.h> -+#include <linux/reset.h> -+#include <linux/of_device.h> -+ -+#include "virt-dma.h" -+ -+#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10) -+#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10) -+ -+#define GDMA_REG_CTRL0(x) (0x08 + (x) * 0x10) -+#define GDMA_REG_CTRL0_TX_MASK 0xffff -+#define GDMA_REG_CTRL0_TX_SHIFT 16 -+#define GDMA_REG_CTRL0_CURR_MASK 0xff -+#define GDMA_REG_CTRL0_CURR_SHIFT 8 -+#define GDMA_REG_CTRL0_SRC_ADDR_FIXED BIT(7) -+#define GDMA_REG_CTRL0_DST_ADDR_FIXED BIT(6) -+#define GDMA_REG_CTRL0_BURST_MASK 0x7 -+#define GDMA_REG_CTRL0_BURST_SHIFT 3 -+#define GDMA_REG_CTRL0_DONE_INT BIT(2) -+#define GDMA_REG_CTRL0_ENABLE BIT(1) -+#define GDMA_REG_CTRL0_SW_MODE BIT(0) -+ -+#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10) -+#define GDMA_REG_CTRL1_SEG_MASK 0xf -+#define GDMA_REG_CTRL1_SEG_SHIFT 22 -+#define GDMA_REG_CTRL1_REQ_MASK 0x3f -+#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16 -+#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8 -+#define GDMA_REG_CTRL1_CONTINOUS BIT(14) -+#define GDMA_REG_CTRL1_NEXT_MASK 0x1f -+#define GDMA_REG_CTRL1_NEXT_SHIFT 3 -+#define GDMA_REG_CTRL1_COHERENT BIT(2) -+#define GDMA_REG_CTRL1_FAIL BIT(1) -+#define GDMA_REG_CTRL1_MASK BIT(0) -+ -+#define GDMA_REG_UNMASK_INT 0x200 -+#define GDMA_REG_DONE_INT 0x204 -+ -+#define GDMA_REG_GCT 0x220 -+#define GDMA_REG_GCT_CHAN_MASK 0x3 -+#define GDMA_REG_GCT_CHAN_SHIFT 3 -+#define GDMA_REG_GCT_VER_MASK 0x3 -+#define GDMA_REG_GCT_VER_SHIFT 1 -+#define GDMA_REG_GCT_ARBIT_RR BIT(0) -+ -+#define GDMA_REG_REQSTS 0x2a0 -+#define GDMA_REG_ACKSTS 0x2a4 -+#define GDMA_REG_FINSTS 0x2a8 -+ -+/* for RT305X gdma registers */ -+#define GDMA_RT305X_CTRL0_REQ_MASK 0xf -+#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12 -+#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8 -+ -+#define GDMA_RT305X_CTRL1_FAIL BIT(4) -+#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7 -+#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1 -+ -+#define GDMA_RT305X_STATUS_INT 0x80 -+#define GDMA_RT305X_STATUS_SIGNAL 0x84 -+#define GDMA_RT305X_GCT 0x88 -+ -+/* for MT7621 gdma registers */ -+#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8) -+#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8) -+ -+enum gdma_dma_transfer_size { -+ GDMA_TRANSFER_SIZE_4BYTE = 0, -+ GDMA_TRANSFER_SIZE_8BYTE = 1, -+ GDMA_TRANSFER_SIZE_16BYTE = 2, -+ GDMA_TRANSFER_SIZE_32BYTE = 3, -+ GDMA_TRANSFER_SIZE_64BYTE = 4, -+}; -+ -+struct gdma_dma_sg { -+ dma_addr_t src_addr; -+ dma_addr_t dst_addr; -+ u32 len; -+}; -+ -+struct gdma_dma_desc { -+ struct virt_dma_desc vdesc; -+ -+ enum dma_transfer_direction direction; -+ bool cyclic; -+ -+ u32 residue; -+ unsigned int num_sgs; -+ struct gdma_dma_sg sg[]; -+}; -+ -+struct gdma_dmaengine_chan { -+ struct virt_dma_chan vchan; -+ unsigned int id; -+ unsigned int slave_id; -+ -+ dma_addr_t fifo_addr; -+ enum gdma_dma_transfer_size burst_size; -+ -+ struct gdma_dma_desc *desc; -+ unsigned int next_sg; -+}; -+ -+struct gdma_dma_dev { -+ struct dma_device ddev; -+ struct device_dma_parameters dma_parms; -+ struct gdma_data *data; -+ void __iomem *base; -+ struct tasklet_struct task; -+ volatile unsigned long chan_issued; -+ atomic_t cnt; -+ -+ struct gdma_dmaengine_chan chan[]; -+}; -+ -+struct gdma_data -+{ -+ int chancnt; -+ u32 done_int_reg; -+ void (*init)(struct gdma_dma_dev *dma_dev); -+ int (*start_transfer)(struct gdma_dmaengine_chan *chan); -+}; -+ -+static struct gdma_dma_dev *gdma_dma_chan_get_dev( -+ struct gdma_dmaengine_chan *chan) -+{ -+ return container_of(chan->vchan.chan.device, struct gdma_dma_dev, -+ ddev); -+} -+ -+static struct gdma_dmaengine_chan *to_gdma_dma_chan(struct dma_chan *c) -+{ -+ return container_of(c, struct gdma_dmaengine_chan, vchan.chan); -+} -+ -+static struct gdma_dma_desc *to_gdma_dma_desc(struct virt_dma_desc *vdesc) -+{ -+ return container_of(vdesc, struct gdma_dma_desc, vdesc); -+} -+ -+static inline uint32_t gdma_dma_read(struct gdma_dma_dev *dma_dev, -+ unsigned int reg) -+{ -+ return readl(dma_dev->base + reg); -+} -+ -+static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev, -+ unsigned reg, uint32_t val) -+{ -+ writel(val, dma_dev->base + reg); -+} -+ -+static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs) -+{ -+ return kzalloc(sizeof(struct gdma_dma_desc) + -+ sizeof(struct gdma_dma_sg) * num_sgs, GFP_ATOMIC); -+} -+ -+static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst) -+{ -+ if (maxburst < 2) -+ return GDMA_TRANSFER_SIZE_4BYTE; -+ else if (maxburst < 4) -+ return GDMA_TRANSFER_SIZE_8BYTE; -+ else if (maxburst < 8) -+ return GDMA_TRANSFER_SIZE_16BYTE; -+ else if (maxburst < 16) -+ return GDMA_TRANSFER_SIZE_32BYTE; -+ else -+ return GDMA_TRANSFER_SIZE_64BYTE; -+} -+ -+static int gdma_dma_config(struct dma_chan *c, -+ struct dma_slave_config *config) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ -+ if (config->device_fc) { -+ dev_err(dma_dev->ddev.dev, "not support flow controller\n"); -+ return -EINVAL; -+ } -+ -+ switch (config->direction) { -+ case DMA_MEM_TO_DEV: -+ if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { -+ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); -+ return -EINVAL; -+ } -+ chan->slave_id = config->slave_id; -+ chan->fifo_addr = config->dst_addr; -+ chan->burst_size = gdma_dma_maxburst(config->dst_maxburst); -+ break; -+ case DMA_DEV_TO_MEM: -+ if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { -+ dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); -+ return -EINVAL; -+ } -+ chan->slave_id = config->slave_id; -+ chan->fifo_addr = config->src_addr; -+ chan->burst_size = gdma_dma_maxburst(config->src_maxburst); -+ break; -+ default: -+ dev_err(dma_dev->ddev.dev, "direction type %d error\n", -+ config->direction); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int gdma_dma_terminate_all(struct dma_chan *c) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ unsigned long flags, timeout; -+ LIST_HEAD(head); -+ int i = 0; -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ chan->desc = NULL; -+ clear_bit(chan->id, &dma_dev->chan_issued); -+ vchan_get_all_descriptors(&chan->vchan, &head); -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+ -+ vchan_dma_desc_free_list(&chan->vchan, &head); -+ -+ /* wait dma transfer complete */ -+ timeout = jiffies + msecs_to_jiffies(5000); -+ while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) & -+ GDMA_REG_CTRL0_ENABLE) { -+ if (time_after_eq(jiffies, timeout)) { -+ dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n", -+ chan->id); -+ /* restore to init value */ -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0); -+ break; -+ } -+ cpu_relax(); -+ i++; -+ } -+ -+ if (i) -+ dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n", -+ chan->id, i); -+ -+ return 0; -+} -+ -+static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id) -+{ -+ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ -+ "ctr1 %08x, intr %08x, signal %08x\n", id, -+ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), -+ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT), -+ gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL)); -+} -+ -+static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan) -+{ -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ dma_addr_t src_addr, dst_addr; -+ struct gdma_dma_sg *sg; -+ uint32_t ctrl0, ctrl1; -+ -+ /* verify chan is already stopped */ -+ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); -+ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { -+ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", -+ chan->id, ctrl0); -+ rt305x_dump_reg(dma_dev, chan->id); -+ return -EINVAL; -+ } -+ -+ sg = &chan->desc->sg[chan->next_sg]; -+ if (chan->desc->direction == DMA_MEM_TO_DEV) { -+ src_addr = sg->src_addr; -+ dst_addr = chan->fifo_addr; -+ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \ -+ (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ -+ (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); -+ } else if (chan->desc->direction == DMA_DEV_TO_MEM) { -+ src_addr = chan->fifo_addr; -+ dst_addr = sg->dst_addr; -+ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \ -+ (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ -+ (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); -+ } else if (chan->desc->direction == DMA_MEM_TO_MEM) { -+ /* -+ * TODO: memcpy function have bugs. sometime it will copy -+ * more 8 bytes data when using dmatest verify. -+ */ -+ src_addr = sg->src_addr; -+ dst_addr = sg->dst_addr; -+ ctrl0 = GDMA_REG_CTRL0_SW_MODE | \ -+ (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ -+ (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT); -+ } else { -+ dev_err(dma_dev->ddev.dev, "direction type %d error\n", -+ chan->desc->direction); -+ return -EINVAL; -+ } -+ -+ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ -+ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ -+ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; -+ ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; -+ -+ chan->next_sg++; -+ gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); -+ gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); -+ -+ /* make sure next_sg is update */ -+ wmb(); -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); -+ -+ return 0; -+} -+ -+static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id) -+{ -+ dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ -+ "ctr1 %08x, unmask %08x, done %08x, " \ -+ "req %08x, ack %08x, fin %08x\n", id, -+ gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), -+ gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT), -+ gdma_dma_read(dma_dev, GDMA_REG_DONE_INT), -+ gdma_dma_read(dma_dev, GDMA_REG_REQSTS), -+ gdma_dma_read(dma_dev, GDMA_REG_ACKSTS), -+ gdma_dma_read(dma_dev, GDMA_REG_FINSTS)); -+} -+ -+static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan) -+{ -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ dma_addr_t src_addr, dst_addr; -+ struct gdma_dma_sg *sg; -+ uint32_t ctrl0, ctrl1; -+ -+ /* verify chan is already stopped */ -+ ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); -+ if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { -+ dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", -+ chan->id, ctrl0); -+ rt3883_dump_reg(dma_dev, chan->id); -+ return -EINVAL; -+ } -+ -+ sg = &chan->desc->sg[chan->next_sg]; -+ if (chan->desc->direction == DMA_MEM_TO_DEV) { -+ src_addr = sg->src_addr; -+ dst_addr = chan->fifo_addr; -+ ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED; -+ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ -+ (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT); -+ } else if (chan->desc->direction == DMA_DEV_TO_MEM) { -+ src_addr = chan->fifo_addr; -+ dst_addr = sg->dst_addr; -+ ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED; -+ ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ -+ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ -+ GDMA_REG_CTRL1_COHERENT; -+ } else if (chan->desc->direction == DMA_MEM_TO_MEM) { -+ src_addr = sg->src_addr; -+ dst_addr = sg->dst_addr; -+ ctrl0 = GDMA_REG_CTRL0_SW_MODE; -+ ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ -+ (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ -+ GDMA_REG_CTRL1_COHERENT; -+ } else { -+ dev_err(dma_dev->ddev.dev, "direction type %d error\n", -+ chan->desc->direction); -+ return -EINVAL; -+ } -+ -+ ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ -+ (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ -+ GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; -+ ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; -+ -+ chan->next_sg++; -+ gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); -+ gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); -+ -+ /* make sure next_sg is update */ -+ wmb(); -+ gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); -+ -+ return 0; -+} -+ -+static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev, -+ struct gdma_dmaengine_chan *chan) -+{ -+ return dma_dev->data->start_transfer(chan); -+} -+ -+static int gdma_next_desc(struct gdma_dmaengine_chan *chan) -+{ -+ struct virt_dma_desc *vdesc; -+ -+ vdesc = vchan_next_desc(&chan->vchan); -+ if (!vdesc) { -+ chan->desc = NULL; -+ return 0; -+ } -+ chan->desc = to_gdma_dma_desc(vdesc); -+ chan->next_sg = 0; -+ -+ return 1; -+} -+ -+static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev, -+ struct gdma_dmaengine_chan *chan) -+{ -+ struct gdma_dma_desc *desc; -+ unsigned long flags; -+ int chan_issued; -+ -+ chan_issued = 0; -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ desc = chan->desc; -+ if (desc) { -+ if (desc->cyclic) { -+ vchan_cyclic_callback(&desc->vdesc); -+ if (chan->next_sg == desc->num_sgs) -+ chan->next_sg = 0; -+ chan_issued = 1; -+ } else { -+ desc->residue -= desc->sg[chan->next_sg - 1].len; -+ if (chan->next_sg == desc->num_sgs) { -+ list_del(&desc->vdesc.node); -+ vchan_cookie_complete(&desc->vdesc); -+ chan_issued = gdma_next_desc(chan); -+ } else -+ chan_issued = 1; -+ } -+ } else -+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n", -+ chan->id); -+ if (chan_issued) -+ set_bit(chan->id, &dma_dev->chan_issued); -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+} -+ -+static irqreturn_t gdma_dma_irq(int irq, void *devid) -+{ -+ struct gdma_dma_dev *dma_dev = devid; -+ u32 done, done_reg; -+ unsigned int i; -+ -+ done_reg = dma_dev->data->done_int_reg; -+ done = gdma_dma_read(dma_dev, done_reg); -+ if (unlikely(!done)) -+ return IRQ_NONE; -+ -+ /* clean done bits */ -+ gdma_dma_write(dma_dev, done_reg, done); -+ -+ i = 0; -+ while (done) { -+ if (done & 0x1) { -+ gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]); -+ atomic_dec(&dma_dev->cnt); -+ } -+ done >>= 1; -+ i++; -+ } -+ -+ /* start only have work to do */ -+ if (dma_dev->chan_issued) -+ tasklet_schedule(&dma_dev->task); -+ -+ return IRQ_HANDLED; -+} -+ -+static void gdma_dma_issue_pending(struct dma_chan *c) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) { -+ if (gdma_next_desc(chan)) { -+ set_bit(chan->id, &dma_dev->chan_issued); -+ tasklet_schedule(&dma_dev->task); -+ } else -+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", -+ chan->id); -+ } -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+} -+ -+static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg( -+ struct dma_chan *c, struct scatterlist *sgl, -+ unsigned int sg_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_desc *desc; -+ struct scatterlist *sg; -+ unsigned int i; -+ -+ desc = gdma_dma_alloc_desc(sg_len); -+ if (!desc) { -+ dev_err(c->device->dev, "alloc sg decs error\n"); -+ return NULL; -+ } -+ desc->residue = 0; -+ -+ for_each_sg(sgl, sg, sg_len, i) { -+ if (direction == DMA_MEM_TO_DEV) -+ desc->sg[i].src_addr = sg_dma_address(sg); -+ else if (direction == DMA_DEV_TO_MEM) -+ desc->sg[i].dst_addr = sg_dma_address(sg); -+ else { -+ dev_err(c->device->dev, "direction type %d error\n", -+ direction); -+ goto free_desc; -+ } -+ -+ if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) { -+ dev_err(c->device->dev, "sg len too large %d\n", -+ sg_dma_len(sg)); -+ goto free_desc; -+ } -+ desc->sg[i].len = sg_dma_len(sg); -+ desc->residue += sg_dma_len(sg); -+ } -+ -+ desc->num_sgs = sg_len; -+ desc->direction = direction; -+ desc->cyclic = false; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+ -+free_desc: -+ kfree(desc); -+ return NULL; -+} -+ -+static struct dma_async_tx_descriptor * gdma_dma_prep_dma_memcpy( -+ struct dma_chan *c, dma_addr_t dest, dma_addr_t src, -+ size_t len, unsigned long flags) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_desc *desc; -+ unsigned int num_periods, i; -+ size_t xfer_count; -+ -+ if (len <= 0) -+ return NULL; -+ -+ chan->burst_size = gdma_dma_maxburst(len >> 2); -+ -+ xfer_count = GDMA_REG_CTRL0_TX_MASK; -+ num_periods = DIV_ROUND_UP(len, xfer_count); -+ -+ desc = gdma_dma_alloc_desc(num_periods); -+ if (!desc) { -+ dev_err(c->device->dev, "alloc memcpy decs error\n"); -+ return NULL; -+ } -+ desc->residue = len; -+ -+ for (i = 0; i < num_periods; i++) { -+ desc->sg[i].src_addr = src; -+ desc->sg[i].dst_addr = dest; -+ if (len > xfer_count) { -+ desc->sg[i].len = xfer_count; -+ } else { -+ desc->sg[i].len = len; -+ } -+ src += desc->sg[i].len; -+ dest += desc->sg[i].len; -+ len -= desc->sg[i].len; -+ } -+ -+ desc->num_sgs = num_periods; -+ desc->direction = DMA_MEM_TO_MEM; -+ desc->cyclic = false; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+} -+ -+static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic( -+ struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, -+ size_t period_len, enum dma_transfer_direction direction, -+ unsigned long flags) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct gdma_dma_desc *desc; -+ unsigned int num_periods, i; -+ -+ if (buf_len % period_len) -+ return NULL; -+ -+ if (period_len > GDMA_REG_CTRL0_TX_MASK) { -+ dev_err(c->device->dev, "cyclic len too large %d\n", -+ period_len); -+ return NULL; -+ } -+ -+ num_periods = buf_len / period_len; -+ desc = gdma_dma_alloc_desc(num_periods); -+ if (!desc) { -+ dev_err(c->device->dev, "alloc cyclic decs error\n"); -+ return NULL; -+ } -+ desc->residue = buf_len; -+ -+ for (i = 0; i < num_periods; i++) { -+ if (direction == DMA_MEM_TO_DEV) -+ desc->sg[i].src_addr = buf_addr; -+ else if (direction == DMA_DEV_TO_MEM) -+ desc->sg[i].dst_addr = buf_addr; -+ else { -+ dev_err(c->device->dev, "direction type %d error\n", -+ direction); -+ goto free_desc; -+ } -+ desc->sg[i].len = period_len; -+ buf_addr += period_len; -+ } -+ -+ desc->num_sgs = num_periods; -+ desc->direction = direction; -+ desc->cyclic = true; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+ -+free_desc: -+ kfree(desc); -+ return NULL; -+} -+ -+static enum dma_status gdma_dma_tx_status(struct dma_chan *c, -+ dma_cookie_t cookie, struct dma_tx_state *state) -+{ -+ struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); -+ struct virt_dma_desc *vdesc; -+ enum dma_status status; -+ unsigned long flags; -+ struct gdma_dma_desc *desc; -+ -+ status = dma_cookie_status(c, cookie, state); -+ if (status == DMA_COMPLETE || !state) -+ return status; -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ desc = chan->desc; -+ if (desc && (cookie == desc->vdesc.tx.cookie)) { -+ /* -+ * We never update edesc->residue in the cyclic case, so we -+ * can tell the remaining room to the end of the circular -+ * buffer. -+ */ -+ if (desc->cyclic) -+ state->residue = desc->residue - -+ ((chan->next_sg - 1) * desc->sg[0].len); -+ else -+ state->residue = desc->residue; -+ } else if ((vdesc = vchan_find_desc(&chan->vchan, cookie))) -+ state->residue = to_gdma_dma_desc(vdesc)->residue; -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+ -+ dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue); -+ -+ return status; -+} -+ -+static void gdma_dma_free_chan_resources(struct dma_chan *c) -+{ -+ vchan_free_chan_resources(to_virt_chan(c)); -+} -+ -+static void gdma_dma_desc_free(struct virt_dma_desc *vdesc) -+{ -+ kfree(container_of(vdesc, struct gdma_dma_desc, vdesc)); -+} -+ -+static void gdma_dma_tasklet(unsigned long arg) -+{ -+ struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg; -+ struct gdma_dmaengine_chan *chan; -+ static unsigned int last_chan; -+ unsigned int i, chan_mask; -+ -+ /* record last chan to round robin all chans */ -+ i = last_chan; -+ chan_mask = dma_dev->data->chancnt - 1; -+ do { -+ /* -+ * on mt7621. when verify with dmatest with all -+ * channel is enable. we need to limit only two -+ * channel is working at the same time. otherwise the -+ * data will have problem. -+ */ -+ if (atomic_read(&dma_dev->cnt) >= 2) { -+ last_chan = i; -+ break; -+ } -+ -+ if (test_and_clear_bit(i, &dma_dev->chan_issued)) { -+ chan = &dma_dev->chan[i]; -+ if (chan->desc) { -+ atomic_inc(&dma_dev->cnt); -+ gdma_start_transfer(dma_dev, chan); -+ } else -+ dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id); -+ -+ if (!dma_dev->chan_issued) -+ break; -+ } -+ -+ i = (i + 1) & chan_mask; -+ } while (i != last_chan); -+} -+ -+static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev) -+{ -+ uint32_t gct; -+ -+ /* all chans round robin */ -+ gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR); -+ -+ gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT); -+ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", -+ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, -+ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & -+ GDMA_REG_GCT_CHAN_MASK)); -+} -+ -+static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev) -+{ -+ uint32_t gct; -+ -+ /* all chans round robin */ -+ gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); -+ -+ gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); -+ dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", -+ (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, -+ 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & -+ GDMA_REG_GCT_CHAN_MASK)); -+} -+ -+static struct gdma_data rt305x_gdma_data = { -+ .chancnt = 8, -+ .done_int_reg = GDMA_RT305X_STATUS_INT, -+ .init = rt305x_gdma_init, -+ .start_transfer = rt305x_gdma_start_transfer, -+}; -+ -+static struct gdma_data rt3883_gdma_data = { -+ .chancnt = 16, -+ .done_int_reg = GDMA_REG_DONE_INT, -+ .init = rt3883_gdma_init, -+ .start_transfer = rt3883_gdma_start_transfer, -+}; -+ -+static const struct of_device_id gdma_of_match_table[] = { -+ { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data }, -+ { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, -+ { }, -+}; -+ -+static int gdma_dma_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *match; -+ struct gdma_dmaengine_chan *chan; -+ struct gdma_dma_dev *dma_dev; -+ struct dma_device *dd; -+ unsigned int i; -+ struct resource *res; -+ int ret; -+ int irq; -+ void __iomem *base; -+ struct gdma_data *data; -+ -+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return ret; -+ -+ match = of_match_device(gdma_of_match_table, &pdev->dev); -+ if (!match) -+ return -EINVAL; -+ data = (struct gdma_data *) match->data; -+ -+ dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev) + -+ (sizeof(struct gdma_dmaengine_chan) * data->chancnt), -+ GFP_KERNEL); -+ if (!dma_dev) { -+ dev_err(&pdev->dev, "alloc dma device failed\n"); -+ return -EINVAL; -+ } -+ dma_dev->data = data; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ dma_dev->base = base; -+ tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ dev_err(&pdev->dev, "failed to get irq\n"); -+ return -EINVAL; -+ } -+ ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq, -+ 0, dev_name(&pdev->dev), dma_dev); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to request irq\n"); -+ return ret; -+ } -+ -+ device_reset(&pdev->dev); -+ -+ dd = &dma_dev->ddev; -+ dma_cap_set(DMA_MEMCPY, dd->cap_mask); -+ dma_cap_set(DMA_SLAVE, dd->cap_mask); -+ dma_cap_set(DMA_CYCLIC, dd->cap_mask); -+ dd->device_free_chan_resources = gdma_dma_free_chan_resources; -+ dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy; -+ dd->device_prep_slave_sg = gdma_dma_prep_slave_sg; -+ dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic; -+ dd->device_config = gdma_dma_config; -+ dd->device_terminate_all = gdma_dma_terminate_all; -+ dd->device_tx_status = gdma_dma_tx_status; -+ dd->device_issue_pending = gdma_dma_issue_pending; -+ -+ dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); -+ dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); -+ dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); -+ dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; -+ -+ dd->dev = &pdev->dev; -+ dd->dev->dma_parms = &dma_dev->dma_parms; -+ dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK); -+ INIT_LIST_HEAD(&dd->channels); -+ -+ for (i = 0; i < data->chancnt; i++) { -+ chan = &dma_dev->chan[i]; -+ chan->id = i; -+ chan->vchan.desc_free = gdma_dma_desc_free; -+ vchan_init(&chan->vchan, dd); -+ } -+ -+ /* init hardware */ -+ data->init(dma_dev); -+ -+ ret = dma_async_device_register(dd); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to register dma device\n"); -+ return ret; -+ } -+ -+ ret = of_dma_controller_register(pdev->dev.of_node, -+ of_dma_xlate_by_chan_id, dma_dev); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to register of dma controller\n"); -+ goto err_unregister; -+ } -+ -+ platform_set_drvdata(pdev, dma_dev); -+ -+ return 0; -+ -+err_unregister: -+ dma_async_device_unregister(dd); -+ return ret; -+} -+ -+static int gdma_dma_remove(struct platform_device *pdev) -+{ -+ struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev); -+ -+ tasklet_kill(&dma_dev->task); -+ of_dma_controller_free(pdev->dev.of_node); -+ dma_async_device_unregister(&dma_dev->ddev); -+ -+ return 0; -+} -+ -+static struct platform_driver gdma_dma_driver = { -+ .probe = gdma_dma_probe, -+ .remove = gdma_dma_remove, -+ .driver = { -+ .name = "gdma-rt2880", -+ .of_match_table = gdma_of_match_table, -+ }, -+}; -+module_platform_driver(gdma_dma_driver); -+ -+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -+MODULE_DESCRIPTION("Ralink/MTK DMA driver"); -+MODULE_LICENSE("GPL v2"); ---- a/include/linux/dmaengine.h -+++ b/include/linux/dmaengine.h -@@ -525,6 +525,7 @@ static inline void dma_set_unmap(struct - struct dmaengine_unmap_data * - dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags); - void dmaengine_unmap_put(struct dmaengine_unmap_data *unmap); -+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan); - #else - static inline void dma_set_unmap(struct dma_async_tx_descriptor *tx, - struct dmaengine_unmap_data *unmap) ---- /dev/null -+++ b/drivers/dma/mtk-hsdma.c -@@ -0,0 +1,767 @@ -+/* -+ * Copyright (C) 2015, Michael Lee <igvtee@gmail.com> -+ * MTK HSDMA support -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#include <linux/dmaengine.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/irq.h> -+#include <linux/of_dma.h> -+#include <linux/reset.h> -+#include <linux/of_device.h> -+ -+#include "virt-dma.h" -+ -+#define HSDMA_BASE_OFFSET 0x800 -+ -+#define HSDMA_REG_TX_BASE 0x00 -+#define HSDMA_REG_TX_CNT 0x04 -+#define HSDMA_REG_TX_CTX 0x08 -+#define HSDMA_REG_TX_DTX 0x0c -+#define HSDMA_REG_RX_BASE 0x100 -+#define HSDMA_REG_RX_CNT 0x104 -+#define HSDMA_REG_RX_CRX 0x108 -+#define HSDMA_REG_RX_DRX 0x10c -+#define HSDMA_REG_INFO 0x200 -+#define HSDMA_REG_GLO_CFG 0x204 -+#define HSDMA_REG_RST_CFG 0x208 -+#define HSDMA_REG_DELAY_INT 0x20c -+#define HSDMA_REG_FREEQ_THRES 0x210 -+#define HSDMA_REG_INT_STATUS 0x220 -+#define HSDMA_REG_INT_MASK 0x228 -+#define HSDMA_REG_SCH_Q01 0x280 -+#define HSDMA_REG_SCH_Q23 0x284 -+ -+#define HSDMA_DESCS_MAX 0xfff -+#define HSDMA_DESCS_NUM 8 -+#define HSDMA_DESCS_MASK (HSDMA_DESCS_NUM - 1) -+#define HSDMA_NEXT_DESC(x) (((x) + 1) & HSDMA_DESCS_MASK) -+ -+/* HSDMA_REG_INFO */ -+#define HSDMA_INFO_INDEX_MASK 0xf -+#define HSDMA_INFO_INDEX_SHIFT 24 -+#define HSDMA_INFO_BASE_MASK 0xff -+#define HSDMA_INFO_BASE_SHIFT 16 -+#define HSDMA_INFO_RX_MASK 0xff -+#define HSDMA_INFO_RX_SHIFT 8 -+#define HSDMA_INFO_TX_MASK 0xff -+#define HSDMA_INFO_TX_SHIFT 0 -+ -+/* HSDMA_REG_GLO_CFG */ -+#define HSDMA_GLO_TX_2B_OFFSET BIT(31) -+#define HSDMA_GLO_CLK_GATE BIT(30) -+#define HSDMA_GLO_BYTE_SWAP BIT(29) -+#define HSDMA_GLO_MULTI_DMA BIT(10) -+#define HSDMA_GLO_TWO_BUF BIT(9) -+#define HSDMA_GLO_32B_DESC BIT(8) -+#define HSDMA_GLO_BIG_ENDIAN BIT(7) -+#define HSDMA_GLO_TX_DONE BIT(6) -+#define HSDMA_GLO_BT_MASK 0x3 -+#define HSDMA_GLO_BT_SHIFT 4 -+#define HSDMA_GLO_RX_BUSY BIT(3) -+#define HSDMA_GLO_RX_DMA BIT(2) -+#define HSDMA_GLO_TX_BUSY BIT(1) -+#define HSDMA_GLO_TX_DMA BIT(0) -+ -+#define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) -+#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) -+#define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) -+#define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) -+ -+#define HSDMA_GLO_DEFAULT (HSDMA_GLO_MULTI_DMA | \ -+ HSDMA_GLO_RX_DMA | HSDMA_GLO_TX_DMA | HSDMA_BT_SIZE_32BYTES) -+ -+/* HSDMA_REG_RST_CFG */ -+#define HSDMA_RST_RX_SHIFT 16 -+#define HSDMA_RST_TX_SHIFT 0 -+ -+/* HSDMA_REG_DELAY_INT */ -+#define HSDMA_DELAY_INT_EN BIT(15) -+#define HSDMA_DELAY_PEND_OFFSET 8 -+#define HSDMA_DELAY_TIME_OFFSET 0 -+#define HSDMA_DELAY_TX_OFFSET 16 -+#define HSDMA_DELAY_RX_OFFSET 0 -+ -+#define HSDMA_DELAY_INIT(x) (HSDMA_DELAY_INT_EN | \ -+ ((x) << HSDMA_DELAY_PEND_OFFSET)) -+#define HSDMA_DELAY(x) ((HSDMA_DELAY_INIT(x) << \ -+ HSDMA_DELAY_TX_OFFSET) | HSDMA_DELAY_INIT(x)) -+ -+/* HSDMA_REG_INT_STATUS */ -+#define HSDMA_INT_DELAY_RX_COH BIT(31) -+#define HSDMA_INT_DELAY_RX_INT BIT(30) -+#define HSDMA_INT_DELAY_TX_COH BIT(29) -+#define HSDMA_INT_DELAY_TX_INT BIT(28) -+#define HSDMA_INT_RX_MASK 0x3 -+#define HSDMA_INT_RX_SHIFT 16 -+#define HSDMA_INT_RX_Q0 BIT(16) -+#define HSDMA_INT_TX_MASK 0xf -+#define HSDMA_INT_TX_SHIFT 0 -+#define HSDMA_INT_TX_Q0 BIT(0) -+ -+/* tx/rx dma desc flags */ -+#define HSDMA_PLEN_MASK 0x3fff -+#define HSDMA_DESC_DONE BIT(31) -+#define HSDMA_DESC_LS0 BIT(30) -+#define HSDMA_DESC_PLEN0(_x) (((_x) & HSDMA_PLEN_MASK) << 16) -+#define HSDMA_DESC_TAG BIT(15) -+#define HSDMA_DESC_LS1 BIT(14) -+#define HSDMA_DESC_PLEN1(_x) ((_x) & HSDMA_PLEN_MASK) -+ -+/* align 4 bytes */ -+#define HSDMA_ALIGN_SIZE 3 -+/* align size 128bytes */ -+#define HSDMA_MAX_PLEN 0x3f80 -+ -+struct hsdma_desc { -+ u32 addr0; -+ u32 flags; -+ u32 addr1; -+ u32 unused; -+}; -+ -+struct mtk_hsdma_sg { -+ dma_addr_t src_addr; -+ dma_addr_t dst_addr; -+ u32 len; -+}; -+ -+struct mtk_hsdma_desc { -+ struct virt_dma_desc vdesc; -+ unsigned int num_sgs; -+ struct mtk_hsdma_sg sg[1]; -+}; -+ -+struct mtk_hsdma_chan { -+ struct virt_dma_chan vchan; -+ unsigned int id; -+ dma_addr_t desc_addr; -+ int tx_idx; -+ int rx_idx; -+ struct hsdma_desc *tx_ring; -+ struct hsdma_desc *rx_ring; -+ struct mtk_hsdma_desc *desc; -+ unsigned int next_sg; -+}; -+ -+struct mtk_hsdam_engine { -+ struct dma_device ddev; -+ struct device_dma_parameters dma_parms; -+ void __iomem *base; -+ struct tasklet_struct task; -+ volatile unsigned long chan_issued; -+ -+ struct mtk_hsdma_chan chan[1]; -+}; -+ -+static inline struct mtk_hsdam_engine *mtk_hsdma_chan_get_dev( -+ struct mtk_hsdma_chan *chan) -+{ -+ return container_of(chan->vchan.chan.device, struct mtk_hsdam_engine, -+ ddev); -+} -+ -+static inline struct mtk_hsdma_chan *to_mtk_hsdma_chan(struct dma_chan *c) -+{ -+ return container_of(c, struct mtk_hsdma_chan, vchan.chan); -+} -+ -+static inline struct mtk_hsdma_desc *to_mtk_hsdma_desc( -+ struct virt_dma_desc *vdesc) -+{ -+ return container_of(vdesc, struct mtk_hsdma_desc, vdesc); -+} -+ -+static inline u32 mtk_hsdma_read(struct mtk_hsdam_engine *hsdma, u32 reg) -+{ -+ return readl(hsdma->base + reg); -+} -+ -+static inline void mtk_hsdma_write(struct mtk_hsdam_engine *hsdma, -+ unsigned reg, u32 val) -+{ -+ writel(val, hsdma->base + reg); -+} -+ -+static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ chan->tx_idx = 0; -+ chan->rx_idx = HSDMA_DESCS_NUM - 1; -+ -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); -+ -+ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, -+ 0x1 << (chan->id + HSDMA_RST_TX_SHIFT)); -+ mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, -+ 0x1 << (chan->id + HSDMA_RST_RX_SHIFT)); -+} -+ -+static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) -+{ -+ dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " \ -+ "tctx %08x, tdtx: %08x, rbase %08x, " \ -+ "rcnt %08x, rctx %08x, rdtx %08x\n", -+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), -+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), -+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX), -+ mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX), -+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE), -+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT), -+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), -+ mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); -+ -+ dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " \ -+ "intr_stat %08x, intr_mask %08x\n", -+ mtk_hsdma_read(hsdma, HSDMA_REG_INFO), -+ mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), -+ mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT), -+ mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS), -+ mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK)); -+} -+ -+static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ struct hsdma_desc *tx_desc; -+ struct hsdma_desc *rx_desc; -+ int i; -+ -+ dev_dbg(hsdma->ddev.dev, "tx idx: %d, rx idx: %d\n", -+ chan->tx_idx, chan->rx_idx); -+ -+ for (i = 0; i < HSDMA_DESCS_NUM; i++) { -+ tx_desc = &chan->tx_ring[i]; -+ rx_desc = &chan->rx_ring[i]; -+ -+ dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " \ -+ "tx addr1: %08x, rx addr0 %08x, flags %08x\n", -+ i, tx_desc->addr0, tx_desc->flags, \ -+ tx_desc->addr1, rx_desc->addr0, rx_desc->flags); -+ } -+} -+ -+static void mtk_hsdma_reset(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ int i; -+ -+ /* disable dma */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); -+ -+ /* disable intr */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); -+ -+ /* init desc value */ -+ for (i = 0; i < HSDMA_DESCS_NUM; i++) { -+ chan->tx_ring[i].addr0 = 0; -+ chan->tx_ring[i].flags = HSDMA_DESC_LS0 | -+ HSDMA_DESC_DONE; -+ } -+ for (i = 0; i < HSDMA_DESCS_NUM; i++) { -+ chan->rx_ring[i].addr0 = 0; -+ chan->rx_ring[i].flags = 0; -+ } -+ -+ /* reset */ -+ mtk_hsdma_reset_chan(hsdma, chan); -+ -+ /* enable intr */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); -+ -+ /* enable dma */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); -+} -+ -+static int mtk_hsdma_terminate_all(struct dma_chan *c) -+{ -+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); -+ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); -+ unsigned long timeout; -+ LIST_HEAD(head); -+ -+ spin_lock_bh(&chan->vchan.lock); -+ chan->desc = NULL; -+ clear_bit(chan->id, &hsdma->chan_issued); -+ vchan_get_all_descriptors(&chan->vchan, &head); -+ spin_unlock_bh(&chan->vchan.lock); -+ -+ vchan_dma_desc_free_list(&chan->vchan, &head); -+ -+ /* wait dma transfer complete */ -+ timeout = jiffies + msecs_to_jiffies(2000); -+ while (mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG) & -+ (HSDMA_GLO_RX_BUSY | HSDMA_GLO_TX_BUSY)) { -+ if (time_after_eq(jiffies, timeout)) { -+ hsdma_dump_desc(hsdma, chan); -+ mtk_hsdma_reset(hsdma, chan); -+ dev_err(hsdma->ddev.dev, "timeout, reset it\n"); -+ break; -+ } -+ cpu_relax(); -+ } -+ -+ return 0; -+} -+ -+static int mtk_hsdma_start_transfer(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ dma_addr_t src, dst; -+ size_t len, tlen; -+ struct hsdma_desc *tx_desc, *rx_desc; -+ struct mtk_hsdma_sg *sg; -+ unsigned int i; -+ int rx_idx; -+ -+ sg = &chan->desc->sg[0]; -+ len = sg->len; -+ chan->desc->num_sgs = DIV_ROUND_UP(len, HSDMA_MAX_PLEN); -+ -+ /* tx desc */ -+ src = sg->src_addr; -+ for (i = 0; i < chan->desc->num_sgs; i++) { -+ if (len > HSDMA_MAX_PLEN) -+ tlen = HSDMA_MAX_PLEN; -+ else -+ tlen = len; -+ -+ if (i & 0x1) { -+ tx_desc->addr1 = src; -+ tx_desc->flags |= HSDMA_DESC_PLEN1(tlen); -+ } else { -+ tx_desc = &chan->tx_ring[chan->tx_idx]; -+ tx_desc->addr0 = src; -+ tx_desc->flags = HSDMA_DESC_PLEN0(tlen); -+ -+ /* update index */ -+ chan->tx_idx = HSDMA_NEXT_DESC(chan->tx_idx); -+ } -+ -+ src += tlen; -+ len -= tlen; -+ } -+ if (i & 0x1) -+ tx_desc->flags |= HSDMA_DESC_LS0; -+ else -+ tx_desc->flags |= HSDMA_DESC_LS1; -+ -+ /* rx desc */ -+ rx_idx = HSDMA_NEXT_DESC(chan->rx_idx); -+ len = sg->len; -+ dst = sg->dst_addr; -+ for (i = 0; i < chan->desc->num_sgs; i++) { -+ rx_desc = &chan->rx_ring[rx_idx]; -+ if (len > HSDMA_MAX_PLEN) -+ tlen = HSDMA_MAX_PLEN; -+ else -+ tlen = len; -+ -+ rx_desc->addr0 = dst; -+ rx_desc->flags = HSDMA_DESC_PLEN0(tlen); -+ -+ dst += tlen; -+ len -= tlen; -+ -+ /* update index */ -+ rx_idx = HSDMA_NEXT_DESC(rx_idx); -+ } -+ -+ /* make sure desc and index all up to date */ -+ wmb(); -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); -+ -+ return 0; -+} -+ -+static int gdma_next_desc(struct mtk_hsdma_chan *chan) -+{ -+ struct virt_dma_desc *vdesc; -+ -+ vdesc = vchan_next_desc(&chan->vchan); -+ if (!vdesc) { -+ chan->desc = NULL; -+ return 0; -+ } -+ chan->desc = to_mtk_hsdma_desc(vdesc); -+ chan->next_sg = 0; -+ -+ return 1; -+} -+ -+static void mtk_hsdma_chan_done(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ struct mtk_hsdma_desc *desc; -+ int chan_issued; -+ -+ chan_issued = 0; -+ spin_lock_bh(&chan->vchan.lock); -+ desc = chan->desc; -+ if (likely(desc)) { -+ if (chan->next_sg == desc->num_sgs) { -+ list_del(&desc->vdesc.node); -+ vchan_cookie_complete(&desc->vdesc); -+ chan_issued = gdma_next_desc(chan); -+ } -+ } else -+ dev_dbg(hsdma->ddev.dev, "no desc to complete\n"); -+ -+ if (chan_issued) -+ set_bit(chan->id, &hsdma->chan_issued); -+ spin_unlock_bh(&chan->vchan.lock); -+} -+ -+static irqreturn_t mtk_hsdma_irq(int irq, void *devid) -+{ -+ struct mtk_hsdam_engine *hsdma = devid; -+ u32 status; -+ -+ status = mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS); -+ if (unlikely(!status)) -+ return IRQ_NONE; -+ -+ if (likely(status & HSDMA_INT_RX_Q0)) -+ tasklet_schedule(&hsdma->task); -+ else -+ dev_dbg(hsdma->ddev.dev, "unhandle irq status %08x\n", -+ status); -+ /* clean intr bits */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_STATUS, status); -+ -+ return IRQ_HANDLED; -+} -+ -+static void mtk_hsdma_issue_pending(struct dma_chan *c) -+{ -+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); -+ struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); -+ -+ spin_lock_bh(&chan->vchan.lock); -+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) { -+ if (gdma_next_desc(chan)) { -+ set_bit(chan->id, &hsdma->chan_issued); -+ tasklet_schedule(&hsdma->task); -+ } else -+ dev_dbg(hsdma->ddev.dev, "no desc to issue\n"); -+ } -+ spin_unlock_bh(&chan->vchan.lock); -+} -+ -+static struct dma_async_tx_descriptor * mtk_hsdma_prep_dma_memcpy( -+ struct dma_chan *c, dma_addr_t dest, dma_addr_t src, -+ size_t len, unsigned long flags) -+{ -+ struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); -+ struct mtk_hsdma_desc *desc; -+ -+ if (len <= 0) -+ return NULL; -+ -+ desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC); -+ if (!desc) { -+ dev_err(c->device->dev, "alloc memcpy decs error\n"); -+ return NULL; -+ } -+ -+ desc->sg[0].src_addr = src; -+ desc->sg[0].dst_addr = dest; -+ desc->sg[0].len = len; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+} -+ -+static enum dma_status mtk_hsdma_tx_status(struct dma_chan *c, -+ dma_cookie_t cookie, struct dma_tx_state *state) -+{ -+ return dma_cookie_status(c, cookie, state); -+} -+ -+static void mtk_hsdma_free_chan_resources(struct dma_chan *c) -+{ -+ vchan_free_chan_resources(to_virt_chan(c)); -+} -+ -+static void mtk_hsdma_desc_free(struct virt_dma_desc *vdesc) -+{ -+ kfree(container_of(vdesc, struct mtk_hsdma_desc, vdesc)); -+} -+ -+static void mtk_hsdma_tx(struct mtk_hsdam_engine *hsdma) -+{ -+ struct mtk_hsdma_chan *chan; -+ -+ if (test_and_clear_bit(0, &hsdma->chan_issued)) { -+ chan = &hsdma->chan[0]; -+ if (chan->desc) { -+ mtk_hsdma_start_transfer(hsdma, chan); -+ } else -+ dev_dbg(hsdma->ddev.dev,"chan 0 no desc to issue\n"); -+ } -+} -+ -+static void mtk_hsdma_rx(struct mtk_hsdam_engine *hsdma) -+{ -+ struct mtk_hsdma_chan *chan; -+ int next_idx, drx_idx, cnt; -+ -+ chan = &hsdma->chan[0]; -+ next_idx = HSDMA_NEXT_DESC(chan->rx_idx); -+ drx_idx = mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX); -+ -+ cnt = (drx_idx - next_idx) & HSDMA_DESCS_MASK; -+ if (!cnt) -+ return; -+ -+ chan->next_sg += cnt; -+ chan->rx_idx = (chan->rx_idx + cnt) & HSDMA_DESCS_MASK; -+ -+ /* update rx crx */ -+ wmb(); -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); -+ -+ mtk_hsdma_chan_done(hsdma, chan); -+} -+ -+static void mtk_hsdma_tasklet(unsigned long arg) -+{ -+ struct mtk_hsdam_engine *hsdma = (struct mtk_hsdam_engine *)arg; -+ -+ mtk_hsdma_rx(hsdma); -+ mtk_hsdma_tx(hsdma); -+} -+ -+static int mtk_hsdam_alloc_desc(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ int i; -+ -+ chan->tx_ring = dma_alloc_coherent(hsdma->ddev.dev, -+ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), -+ &chan->desc_addr, GFP_ATOMIC | __GFP_ZERO); -+ if (!chan->tx_ring) -+ goto no_mem; -+ -+ chan->rx_ring = &chan->tx_ring[HSDMA_DESCS_NUM]; -+ -+ /* init tx ring value */ -+ for (i = 0; i < HSDMA_DESCS_NUM; i++) -+ chan->tx_ring[i].flags = HSDMA_DESC_LS0 | HSDMA_DESC_DONE; -+ -+ return 0; -+no_mem: -+ return -ENOMEM; -+} -+ -+static void mtk_hsdam_free_desc(struct mtk_hsdam_engine *hsdma, -+ struct mtk_hsdma_chan *chan) -+{ -+ if (chan->tx_ring) { -+ dma_free_coherent(hsdma->ddev.dev, -+ 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), -+ chan->tx_ring, chan->desc_addr); -+ chan->tx_ring = NULL; -+ chan->rx_ring = NULL; -+ } -+} -+ -+static int mtk_hsdma_init(struct mtk_hsdam_engine *hsdma) -+{ -+ struct mtk_hsdma_chan *chan; -+ int ret; -+ u32 reg; -+ -+ /* init desc */ -+ chan = &hsdma->chan[0]; -+ ret = mtk_hsdam_alloc_desc(hsdma, chan); -+ if (ret) -+ return ret; -+ -+ /* tx */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, chan->desc_addr); -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, HSDMA_DESCS_NUM); -+ /* rx */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, chan->desc_addr + -+ (sizeof(struct hsdma_desc) * HSDMA_DESCS_NUM)); -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, HSDMA_DESCS_NUM); -+ /* reset */ -+ mtk_hsdma_reset_chan(hsdma, chan); -+ -+ /* enable rx intr */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); -+ -+ /* enable dma */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); -+ -+ /* hardware info */ -+ reg = mtk_hsdma_read(hsdma, HSDMA_REG_INFO); -+ dev_info(hsdma->ddev.dev, "rx: %d, tx: %d\n", -+ (reg >> HSDMA_INFO_RX_SHIFT) & HSDMA_INFO_RX_MASK, -+ (reg >> HSDMA_INFO_TX_SHIFT) & HSDMA_INFO_TX_MASK); -+ -+ hsdma_dump_reg(hsdma); -+ -+ return ret; -+} -+ -+static void mtk_hsdma_uninit(struct mtk_hsdam_engine *hsdma) -+{ -+ struct mtk_hsdma_chan *chan; -+ -+ /* disable dma */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); -+ -+ /* disable intr */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); -+ -+ /* free desc */ -+ chan = &hsdma->chan[0]; -+ mtk_hsdam_free_desc(hsdma, chan); -+ -+ /* tx */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, 0); -+ mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, 0); -+ /* rx */ -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, 0); -+ mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, 0); -+ /* reset */ -+ mtk_hsdma_reset_chan(hsdma, chan); -+} -+ -+static const struct of_device_id mtk_hsdma_of_match[] = { -+ { .compatible = "mediatek,mt7621-hsdma" }, -+ { }, -+}; -+ -+static int mtk_hsdma_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *match; -+ struct mtk_hsdma_chan *chan; -+ struct mtk_hsdam_engine *hsdma; -+ struct dma_device *dd; -+ struct resource *res; -+ int ret; -+ int irq; -+ void __iomem *base; -+ -+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return ret; -+ -+ match = of_match_device(mtk_hsdma_of_match, &pdev->dev); -+ if (!match) -+ return -EINVAL; -+ -+ hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL); -+ if (!hsdma) { -+ dev_err(&pdev->dev, "alloc dma device failed\n"); -+ return -EINVAL; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ hsdma->base = base + HSDMA_BASE_OFFSET; -+ tasklet_init(&hsdma->task, mtk_hsdma_tasklet, (unsigned long)hsdma); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ dev_err(&pdev->dev, "failed to get irq\n"); -+ return -EINVAL; -+ } -+ ret = devm_request_irq(&pdev->dev, irq, mtk_hsdma_irq, -+ 0, dev_name(&pdev->dev), hsdma); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to request irq\n"); -+ return ret; -+ } -+ -+ device_reset(&pdev->dev); -+ -+ dd = &hsdma->ddev; -+ dma_cap_set(DMA_MEMCPY, dd->cap_mask); -+ dd->copy_align = HSDMA_ALIGN_SIZE; -+ dd->device_free_chan_resources = mtk_hsdma_free_chan_resources; -+ dd->device_prep_dma_memcpy = mtk_hsdma_prep_dma_memcpy; -+ dd->device_terminate_all = mtk_hsdma_terminate_all; -+ dd->device_tx_status = mtk_hsdma_tx_status; -+ dd->device_issue_pending = mtk_hsdma_issue_pending; -+ dd->dev = &pdev->dev; -+ dd->dev->dma_parms = &hsdma->dma_parms; -+ dma_set_max_seg_size(dd->dev, HSDMA_MAX_PLEN); -+ INIT_LIST_HEAD(&dd->channels); -+ -+ chan = &hsdma->chan[0]; -+ chan->id = 0; -+ chan->vchan.desc_free = mtk_hsdma_desc_free; -+ vchan_init(&chan->vchan, dd); -+ -+ /* init hardware */ -+ ret = mtk_hsdma_init(hsdma); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to alloc ring descs\n"); -+ return ret; -+ } -+ -+ ret = dma_async_device_register(dd); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to register dma device\n"); -+ return ret; -+ } -+ -+ ret = of_dma_controller_register(pdev->dev.of_node, -+ of_dma_xlate_by_chan_id, hsdma); -+ if (ret) { -+ dev_err(&pdev->dev, "failed to register of dma controller\n"); -+ goto err_unregister; -+ } -+ -+ platform_set_drvdata(pdev, hsdma); -+ -+ return 0; -+ -+err_unregister: -+ dma_async_device_unregister(dd); -+ return ret; -+} -+ -+static int mtk_hsdma_remove(struct platform_device *pdev) -+{ -+ struct mtk_hsdam_engine *hsdma = platform_get_drvdata(pdev); -+ -+ mtk_hsdma_uninit(hsdma); -+ -+ of_dma_controller_free(pdev->dev.of_node); -+ dma_async_device_unregister(&hsdma->ddev); -+ -+ return 0; -+} -+ -+static struct platform_driver mtk_hsdma_driver = { -+ .probe = mtk_hsdma_probe, -+ .remove = mtk_hsdma_remove, -+ .driver = { -+ .name = "hsdma-mt7621", -+ .of_match_table = mtk_hsdma_of_match, -+ }, -+}; -+module_platform_driver(mtk_hsdma_driver); -+ -+MODULE_AUTHOR("Michael Lee <igvtee@gmail.com>"); -+MODULE_DESCRIPTION("MTK HSDMA driver"); -+MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch index 1834e88538..d0d4141a8d 100644 --- a/target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch +++ b/target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch @@ -20,15 +20,15 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -15,6 +15,7 @@ +@@ -13,6 +13,7 @@ #include <linux/of_fdt.h> #include <linux/kernel.h> - #include <linux/bootmem.h> + #include <linux/memblock.h> +#include <linux/module.h> #include <linux/of_platform.h> #include <linux/of_address.h> -@@ -26,6 +27,7 @@ +@@ -24,6 +25,7 @@ #include "common.h" __iomem void *rt_sysc_membase; @@ -38,7 +38,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> __iomem void *plat_of_remap_node(const char *node) --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig -@@ -59,6 +59,7 @@ source "sound/soc/mxs/Kconfig" +@@ -60,6 +60,7 @@ source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/qcom/Kconfig" source "sound/soc/rockchip/Kconfig" @@ -48,7 +48,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> source "sound/soc/sirf/Kconfig" --- a/sound/soc/Makefile +++ b/sound/soc/Makefile -@@ -40,6 +40,7 @@ obj-$(CONFIG_SND_SOC) += kirkwood/ +@@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += qcom/ obj-$(CONFIG_SND_SOC) += rockchip/ diff --git a/target/linux/ramips/patches-5.4/0051-serial-add-ugly-custom-baud-rate-hack.patch b/target/linux/ramips/patches-5.4/0051-serial-add-ugly-custom-baud-rate-hack.patch index 2ad1f6f9f8..4822226610 100644 --- a/target/linux/ramips/patches-5.4/0051-serial-add-ugly-custom-baud-rate-hack.patch +++ b/target/linux/ramips/patches-5.4/0051-serial-add-ugly-custom-baud-rate-hack.patch @@ -10,7 +10,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c -@@ -428,6 +428,9 @@ uart_get_baud_rate(struct uart_port *por +@@ -416,6 +416,9 @@ uart_get_baud_rate(struct uart_port *por break; } diff --git a/target/linux/ramips/patches-5.4/0052-pwm-add-mediatek-support.patch b/target/linux/ramips/patches-5.4/0052-pwm-add-mediatek-support.patch index 6eb7f16b9d..d2c5724c06 100644 --- a/target/linux/ramips/patches-5.4/0052-pwm-add-mediatek-support.patch +++ b/target/linux/ramips/patches-5.4/0052-pwm-add-mediatek-support.patch @@ -13,7 +13,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig -@@ -302,6 +302,15 @@ config PWM_MEDIATEK +@@ -316,6 +316,15 @@ config PWM_MEDIATEK To compile this driver as a module, choose M here: the module will be called pwm-mediatek. @@ -31,7 +31,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org> depends on ARCH_MXS && OF --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile -@@ -28,6 +28,7 @@ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-p +@@ -29,6 +29,7 @@ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-p obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o obj-$(CONFIG_PWM_MESON) += pwm-meson.o obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o diff --git a/target/linux/ramips/patches-5.4/0053-mtd-spi-nor-add-w25q256-3b-mode-switch.patch b/target/linux/ramips/patches-5.4/0053-mtd-spi-nor-add-w25q256-3b-mode-switch.patch deleted file mode 100644 index aa2fb60a2b..0000000000 --- a/target/linux/ramips/patches-5.4/0053-mtd-spi-nor-add-w25q256-3b-mode-switch.patch +++ /dev/null @@ -1,214 +0,0 @@ -mtd: spi-nor: add support for switching between 3-byte and 4-byte addressing on w25q256 flash - -On some devices the flash chip needs to be in 3-byte addressing mode during -reboot, otherwise the boot loader will fail to start. -This mode however does not allow regular reads/writes onto the upper 16M -half. W25Q256 has separate read commands for reading from >16M, however -it does not have any separate write commands. -This patch changes the code to leave the chip in 3-byte mode most of the -time and only switch during erase/write cycles that go to >16M -addresses. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> ---- ---- a/drivers/mtd/spi-nor/spi-nor.c -+++ b/drivers/mtd/spi-nor/spi-nor.c -@@ -89,6 +89,10 @@ struct flash_info { - #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ - #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ - #define USE_CLSR BIT(14) /* use CLSR command */ -+#define SPI_NOR_4B_READ_OP BIT(15) /* -+ * Like SPI_NOR_4B_OPCODES, but for read -+ * op code only. -+ */ - }; - - #define JEDEC_MFR(info) ((info)->id[0]) -@@ -240,6 +244,15 @@ static inline u8 spi_nor_convert_3to4_er - ARRAY_SIZE(spi_nor_3to4_erase)); - } - -+static void spi_nor_set_4byte_read(struct spi_nor *nor, -+ const struct flash_info *info) -+{ -+ nor->addr_width = 3; -+ nor->ext_addr = 0; -+ nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); -+ nor->flags |= SNOR_F_4B_EXT_ADDR; -+} -+ - static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, - const struct flash_info *info) - { -@@ -467,6 +480,36 @@ static int spi_nor_erase_sector(struct s - return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); - } - -+static int spi_nor_check_ext_addr(struct spi_nor *nor, u32 addr) -+{ -+ bool ext_addr; -+ int ret; -+ u8 cmd; -+ -+ if (!(nor->flags & SNOR_F_4B_EXT_ADDR)) -+ return 0; -+ -+ ext_addr = !!(addr & 0xff000000); -+ if (nor->ext_addr == ext_addr) -+ return 0; -+ -+ cmd = ext_addr ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; -+ write_enable(nor); -+ ret = nor->write_reg(nor, cmd, NULL, 0); -+ if (ret) -+ return ret; -+ -+ cmd = 0; -+ ret = nor->write_reg(nor, SPINOR_OP_WREAR, &cmd, 1); -+ if (ret) -+ return ret; -+ -+ nor->addr_width = 3 + ext_addr; -+ nor->ext_addr = ext_addr; -+ write_disable(nor); -+ return 0; -+} -+ - /* - * Erase an address range on the nor chip. The address range may extend - * one or more erase sectors. Return an error is there is a problem erasing. -@@ -492,6 +535,10 @@ static int spi_nor_erase(struct mtd_info - if (ret) - return ret; - -+ ret = spi_nor_check_ext_addr(nor, addr + len); -+ if (ret) -+ return ret; -+ - /* whole-chip erase? */ - if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { - unsigned long timeout; -@@ -542,6 +589,7 @@ static int spi_nor_erase(struct mtd_info - write_disable(nor); - - erase_err: -+ spi_nor_check_ext_addr(nor, 0); - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); - - instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE; -@@ -834,7 +882,9 @@ static int spi_nor_lock(struct mtd_info - if (ret) - return ret; - -+ spi_nor_check_ext_addr(nor, ofs + len); - ret = nor->flash_lock(nor, ofs, len); -+ spi_nor_check_ext_addr(nor, 0); - - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); - return ret; -@@ -849,7 +899,9 @@ static int spi_nor_unlock(struct mtd_inf - if (ret) - return ret; - -+ spi_nor_check_ext_addr(nor, ofs + len); - ret = nor->flash_unlock(nor, ofs, len); -+ spi_nor_check_ext_addr(nor, 0); - - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); - return ret; -@@ -1182,7 +1234,7 @@ static const struct flash_info spi_nor_i - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, -- { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_READ_OP) }, - { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024, - SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, - -@@ -1245,6 +1297,9 @@ static int spi_nor_read(struct mtd_info - if (ret) - return ret; - -+ if (nor->flags & SNOR_F_4B_EXT_ADDR) -+ nor->addr_width = 4; -+ - while (len) { - loff_t addr = from; - -@@ -1269,6 +1324,18 @@ static int spi_nor_read(struct mtd_info - ret = 0; - - read_err: -+ if (nor->flags & SNOR_F_4B_EXT_ADDR) { -+ u8 val = 0; -+ -+ if ((from + len) & 0xff000000) { -+ write_enable(nor); -+ nor->write_reg(nor, SPINOR_OP_WREAR, &val, 1); -+ write_disable(nor); -+ } -+ -+ nor->addr_width = 3; -+ } -+ - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); - return ret; - } -@@ -1370,6 +1437,10 @@ static int spi_nor_write(struct mtd_info - if (ret) - return ret; - -+ ret = spi_nor_check_ext_addr(nor, to + len); -+ if (ret < 0) -+ return ret; -+ - for (i = 0; i < len; ) { - ssize_t written; - loff_t addr = to + i; -@@ -1410,6 +1481,7 @@ static int spi_nor_write(struct mtd_info - } - - write_err: -+ spi_nor_check_ext_addr(nor, 0); - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); - return ret; - } -@@ -2826,8 +2898,10 @@ int spi_nor_scan(struct spi_nor *nor, co - } else if (mtd->size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_width = 4; -- if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || -- info->flags & SPI_NOR_4B_OPCODES) -+ if (info->flags & SPI_NOR_4B_READ_OP) -+ spi_nor_set_4byte_read(nor, info); -+ else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || -+ info->flags & SPI_NOR_4B_OPCODES) - spi_nor_set_4byte_opcodes(nor, info); - else - set_4byte(nor, info, 1); ---- a/include/linux/mtd/spi-nor.h -+++ b/include/linux/mtd/spi-nor.h -@@ -102,6 +102,7 @@ - /* Used for Macronix and Winbond flashes. */ - #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ - #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ -+#define SPINOR_OP_WREAR 0xc5 /* Write extended address register */ - - /* Used for Spansion flashes only. */ - #define SPINOR_OP_BRWR 0x17 /* Bank register write */ -@@ -229,6 +230,7 @@ enum spi_nor_option_flags { - SNOR_F_S3AN_ADDR_DEFAULT = BIT(3), - SNOR_F_READY_XSR_RDY = BIT(4), - SNOR_F_USE_CLSR = BIT(5), -+ SNOR_F_4B_EXT_ADDR = BIT(6), - }; - - /** -@@ -280,6 +282,7 @@ struct spi_nor { - enum spi_nor_protocol reg_proto; - bool sst_write_second; - u32 flags; -+ u8 ext_addr; - u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; - - int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); diff --git a/target/linux/ramips/patches-5.4/0054-mtd-spi-nor-w25q256-respect-default-mode.patch b/target/linux/ramips/patches-5.4/0054-mtd-spi-nor-w25q256-respect-default-mode.patch deleted file mode 100644 index a686937989..0000000000 --- a/target/linux/ramips/patches-5.4/0054-mtd-spi-nor-w25q256-respect-default-mode.patch +++ /dev/null @@ -1,73 +0,0 @@ ---- a/drivers/mtd/spi-nor/spi-nor.c -+++ b/drivers/mtd/spi-nor/spi-nor.c -@@ -142,20 +142,29 @@ static int read_fsr(struct spi_nor *nor) - * location. Return the configuration register value. - * Returns negative if error occurred. - */ --static int read_cr(struct spi_nor *nor) -+static int _read_cr(struct spi_nor *nor, u8 reg) - { - int ret; - u8 val; - -- ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); -+ ret = nor->read_reg(nor, reg, &val, 1); - if (ret < 0) { -- dev_err(nor->dev, "error %d reading CR\n", ret); -+ dev_err(nor->dev, "error %d reading %s\n", ret, -+ (reg==SPINOR_OP_RDCR)?"CR":"XCR"); - return ret; - } - - return val; - } - -+static inline int read_cr(struct spi_nor *nor) { -+ return _read_cr(nor, SPINOR_OP_RDCR); -+} -+ -+static inline int read_xcr(struct spi_nor *nor) { -+ return _read_cr(nor, SPINOR_OP_RDXCR); -+} -+ - /* - * Write status register 1 byte - * Returns negative if error occurred. -@@ -2898,9 +2907,16 @@ int spi_nor_scan(struct spi_nor *nor, co - } else if (mtd->size > 0x1000000) { - /* enable 4-byte addressing if the device exceeds 16MiB */ - nor->addr_width = 4; -- if (info->flags & SPI_NOR_4B_READ_OP) -- spi_nor_set_4byte_read(nor, info); -- else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || -+ if (info->flags & SPI_NOR_4B_READ_OP) { -+ if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) { -+ ret = read_xcr(nor); -+ if (!(ret > 0 && (ret & XCR_DEF_4B_ADDR_MODE))) -+ spi_nor_set_4byte_read(nor, info); -+ else -+ set_4byte(nor, info, 1); -+ } else -+ spi_nor_set_4byte_read(nor, info); -+ } else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || - info->flags & SPI_NOR_4B_OPCODES) - spi_nor_set_4byte_opcodes(nor, info); - else ---- a/include/linux/mtd/spi-nor.h -+++ b/include/linux/mtd/spi-nor.h -@@ -103,6 +103,7 @@ - #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ - #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ - #define SPINOR_OP_WREAR 0xc5 /* Write extended address register */ -+#define SPINOR_OP_RDXCR 0x15 /* Read extended configuration register */ - - /* Used for Spansion flashes only. */ - #define SPINOR_OP_BRWR 0x17 /* Bank register write */ -@@ -135,6 +136,7 @@ - - /* Configuration Register bits. */ - #define CR_QUAD_EN_SPAN BIT(1) /* Spansion Quad I/O */ -+#define XCR_DEF_4B_ADDR_MODE BIT(1) /* Winbond 4B mode default */ - - /* Status Register 2 bits. */ - #define SR2_QUAD_EN_BIT7 BIT(7) diff --git a/target/linux/ramips/patches-5.4/0069-awake-rt305x-dwc2-controller.patch b/target/linux/ramips/patches-5.4/0069-awake-rt305x-dwc2-controller.patch index 0e09e1d4e0..1ce8fac682 100644 --- a/target/linux/ramips/patches-5.4/0069-awake-rt305x-dwc2-controller.patch +++ b/target/linux/ramips/patches-5.4/0069-awake-rt305x-dwc2-controller.patch @@ -1,12 +1,12 @@ --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c -@@ -406,6 +406,12 @@ static int dwc2_driver_probe(struct plat - if (retval) - return retval; +@@ -432,6 +432,12 @@ static int dwc2_driver_probe(struct plat + + hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg); + /* Enable USB port before any regs access */ -+ if (dwc2_readl(hsotg->regs + PCGCTL) & 0x0f) { -+ dwc2_writel(0x00, hsotg->regs + PCGCTL); ++ if (dwc2_readl(hsotg, PCGCTL) & 0x0f) { ++ dwc2_writel(0x00, hsotg, PCGCTL); + /* TODO: mdelay(25) here? vendor driver don't use it */ + } + diff --git a/target/linux/ramips/patches-5.4/0070-weak_reordering.patch b/target/linux/ramips/patches-5.4/0070-weak_reordering.patch index 52e6641324..fe3fdec289 100644 --- a/target/linux/ramips/patches-5.4/0070-weak_reordering.patch +++ b/target/linux/ramips/patches-5.4/0070-weak_reordering.patch @@ -1,9 +1,9 @@ --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig -@@ -58,6 +58,7 @@ choice +@@ -57,6 +57,7 @@ choice select COMMON_CLK select CLKSRC_MIPS_GIC - select HW_HAS_PCI + select HAVE_PCI if PCI_MT7621 + select WEAK_REORDERING_BEYOND_LLSC endchoice diff --git a/target/linux/ramips/patches-5.4/0098-disable_cm.patch b/target/linux/ramips/patches-5.4/0098-disable_cm.patch index bc00619dff..9b280aef99 100644 --- a/target/linux/ramips/patches-5.4/0098-disable_cm.patch +++ b/target/linux/ramips/patches-5.4/0098-disable_cm.patch @@ -1,6 +1,6 @@ --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c -@@ -237,6 +237,7 @@ int mips_cm_probe(void) +@@ -233,6 +233,7 @@ int mips_cm_probe(void) /* disable CM regions */ write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR); @@ -8,7 +8,7 @@ write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK); write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR); write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK); -@@ -244,7 +245,7 @@ int mips_cm_probe(void) +@@ -240,7 +241,7 @@ int mips_cm_probe(void) write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK); write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR); write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK); diff --git a/target/linux/ramips/patches-5.4/0099-pci-mt7620.patch b/target/linux/ramips/patches-5.4/0099-pci-mt7620.patch deleted file mode 100644 index 997fb6a2b3..0000000000 --- a/target/linux/ramips/patches-5.4/0099-pci-mt7620.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/arch/mips/pci/pci-mt7620.c -+++ b/arch/mips/pci/pci-mt7620.c -@@ -33,7 +33,6 @@ - #define RALINK_GPIOMODE 0x60 - - #define PPLL_CFG1 0x9c --#define PDRV_SW_SET BIT(23) - - #define PPLL_DRV 0xa0 - #define PDRV_SW_SET (1<<31) diff --git a/target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch b/target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch index cd1462fbcf..9142faaf43 100644 --- a/target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch +++ b/target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch @@ -1,13 +1,13 @@ --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -56,6 +56,7 @@ obj-$(CONFIG_CXL_BASE) += cxl/ - obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o - obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o +@@ -52,6 +52,7 @@ obj-$(CONFIG_ECHO) += echo/ + obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o + obj-$(CONFIG_CXL_BASE) += cxl/ obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o +obj-$(CONFIG_SOC_MT7620) += linkit.o - - lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o - lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o + obj-$(CONFIG_OCXL) += ocxl/ + obj-y += cardreader/ + obj-$(CONFIG_PVPANIC) += pvpanic.o --- /dev/null +++ b/drivers/misc/linkit.c @@ -0,0 +1,84 @@ diff --git a/target/linux/ramips/patches-5.4/100-mt7621-core-detect-hack.patch b/target/linux/ramips/patches-5.4/100-mt7621-core-detect-hack.patch index 991e19b6df..1c8b61f8ef 100644 --- a/target/linux/ramips/patches-5.4/100-mt7621-core-detect-hack.patch +++ b/target/linux/ramips/patches-5.4/100-mt7621-core-detect-hack.patch @@ -7,7 +7,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c -@@ -47,6 +47,11 @@ static unsigned core_vpe_count(unsigned +@@ -43,6 +43,11 @@ static unsigned core_vpe_count(unsigned return mips_cps_numvps(cluster, core); } @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> static void __init cps_smp_setup(void) { unsigned int nclusters, ncores, nvpes, core_vpes; -@@ -64,6 +69,8 @@ static void __init cps_smp_setup(void) +@@ -60,6 +65,8 @@ static void __init cps_smp_setup(void) ncores = mips_cps_numcores(cl); for (c = 0; c < ncores; c++) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> if (c > 0) --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c -@@ -15,6 +15,7 @@ +@@ -13,6 +13,7 @@ #include <asm/mips-cps.h> #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/mt7621.h> @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> #include <pinmux.h> -@@ -162,6 +163,20 @@ void __init ralink_of_remap(void) +@@ -160,6 +161,20 @@ void __init ralink_of_remap(void) panic("Failed to remap core resources"); } diff --git a/target/linux/ramips/patches-5.4/101-mt7621-timer.patch b/target/linux/ramips/patches-5.4/101-mt7621-timer.patch index 10edafd412..8528b71c88 100644 --- a/target/linux/ramips/patches-5.4/101-mt7621-timer.patch +++ b/target/linux/ramips/patches-5.4/101-mt7621-timer.patch @@ -1,6 +1,6 @@ --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c -@@ -9,6 +9,7 @@ +@@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/init.h> @@ -8,7 +8,7 @@ #include <asm/mipsregs.h> #include <asm/smp-ops.h> -@@ -16,6 +17,7 @@ +@@ -14,6 +15,7 @@ #include <asm/mach-ralink/ralink_regs.h> #include <asm/mach-ralink/mt7621.h> #include <asm/mips-boards/launch.h> @@ -16,7 +16,7 @@ #include <pinmux.h> -@@ -177,6 +179,58 @@ bool plat_cpu_core_present(int core) +@@ -175,6 +177,58 @@ bool plat_cpu_core_present(int core) return true; } @@ -77,9 +77,9 @@ void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE); --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig -@@ -59,6 +59,7 @@ choice +@@ -58,6 +58,7 @@ choice select CLKSRC_MIPS_GIC - select HW_HAS_PCI + select HAVE_PCI if PCI_MT7621 select WEAK_REORDERING_BEYOND_LLSC + select GENERIC_CLOCKEVENTS_BROADCAST endchoice diff --git a/target/linux/ramips/patches-5.4/102-mt7621-fix-cpu-clk-add-clkdev.patch b/target/linux/ramips/patches-5.4/102-mt7621-fix-cpu-clk-add-clkdev.patch index e647a2f4c8..0c997a3f28 100644 --- a/target/linux/ramips/patches-5.4/102-mt7621-fix-cpu-clk-add-clkdev.patch +++ b/target/linux/ramips/patches-5.4/102-mt7621-fix-cpu-clk-add-clkdev.patch @@ -1,6 +1,6 @@ --- a/arch/mips/include/asm/mach-ralink/mt7621.h +++ b/arch/mips/include/asm/mach-ralink/mt7621.h -@@ -19,6 +19,10 @@ +@@ -17,6 +17,10 @@ #define SYSC_REG_CHIP_REV 0x0c #define SYSC_REG_SYSTEM_CONFIG0 0x10 #define SYSC_REG_SYSTEM_CONFIG1 0x14 @@ -11,7 +11,7 @@ #define CHIP_REV_PKG_MASK 0x1 #define CHIP_REV_PKG_SHIFT 16 -@@ -26,6 +30,22 @@ +@@ -24,6 +28,22 @@ #define CHIP_REV_VER_SHIFT 8 #define CHIP_REV_ECO_MASK 0xf @@ -36,7 +36,7 @@ #define MT7621_DDR2_SIZE_MAX 256 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c -@@ -10,6 +10,10 @@ +@@ -8,6 +8,10 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/jiffies.h> @@ -47,7 +47,7 @@ #include <asm/mipsregs.h> #include <asm/smp-ops.h> -@@ -18,16 +22,12 @@ +@@ -16,16 +20,12 @@ #include <asm/mach-ralink/mt7621.h> #include <asm/mips-boards/launch.h> #include <asm/delay.h> @@ -65,7 +65,7 @@ #define MT7621_GPIO_MODE_UART1 1 #define MT7621_GPIO_MODE_I2C 2 #define MT7621_GPIO_MODE_UART3_MASK 0x3 -@@ -113,49 +113,89 @@ static struct rt2880_pmx_group mt7621_pi +@@ -111,49 +111,89 @@ static struct rt2880_pmx_group mt7621_pi { 0 } }; @@ -184,7 +184,7 @@ rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc"); --- a/arch/mips/ralink/timer-gic.c +++ b/arch/mips/ralink/timer-gic.c -@@ -11,14 +11,14 @@ +@@ -9,14 +9,14 @@ #include <linux/of.h> #include <linux/clk-provider.h> diff --git a/target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch b/target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch index b19b57fd66..08b4b0de29 100644 --- a/target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch +++ b/target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch @@ -28,7 +28,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> --- a/arch/mips/include/asm/mach-ralink/mt7621.h +++ b/arch/mips/include/asm/mach-ralink/mt7621.h -@@ -46,9 +46,10 @@ +@@ -44,9 +44,10 @@ #define CPU_PLL_FBDIV_MASK 0x7f #define CPU_PLL_FBDIV_SHIFT 4 @@ -44,7 +44,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> #define MT7621_CHIP_NAME1 0x20203132 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c -@@ -15,6 +15,7 @@ +@@ -13,6 +13,7 @@ #include <linux/clk-provider.h> #include <dt-bindings/clock/mt7621-clk.h> @@ -52,7 +52,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> #include <asm/mipsregs.h> #include <asm/smp-ops.h> #include <asm/mips-cps.h> -@@ -57,6 +58,8 @@ +@@ -55,6 +56,8 @@ #define MT7621_GPIO_MODE_SDHCI_SHIFT 18 #define MT7621_GPIO_MODE_SDHCI_GPIO 1 @@ -61,7 +61,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> static struct rt2880_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) }; static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) }; static struct rt2880_pmx_func uart3_grp[] = { -@@ -141,6 +144,28 @@ static struct clk *__init mt7621_add_sys +@@ -139,6 +142,28 @@ static struct clk *__init mt7621_add_sys return clk; } @@ -90,7 +90,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> void __init ralink_clk_init(void) { u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac; -@@ -319,10 +344,7 @@ void prom_soc_init(struct ralink_soc_inf +@@ -317,10 +342,7 @@ void prom_soc_init(struct ralink_soc_inf (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, (rev & CHIP_REV_ECO_MASK)); @@ -104,7 +104,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> --- a/arch/mips/ralink/common.h +++ b/arch/mips/ralink/common.h -@@ -19,6 +19,7 @@ struct ralink_soc_info { +@@ -17,6 +17,7 @@ struct ralink_soc_info { unsigned long mem_size; unsigned long mem_size_min; unsigned long mem_size_max; @@ -114,7 +114,7 @@ Signed-off-by: Chuanhong Guo <gch981213@gmail.com> --- a/arch/mips/ralink/of.c +++ b/arch/mips/ralink/of.c -@@ -89,6 +89,8 @@ void __init plat_mem_setup(void) +@@ -87,6 +87,8 @@ void __init plat_mem_setup(void) of_scan_flat_dt(early_init_dt_find_memory, NULL); if (memory_dtb) of_scan_flat_dt(early_init_dt_scan_memory, NULL); diff --git a/target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch b/target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch index 4c40e65ab9..dfeac7eb99 100644 --- a/target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch +++ b/target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch @@ -1,6 +1,6 @@ --- a/arch/mips/ralink/irq-gic.c +++ b/arch/mips/ralink/irq-gic.c -@@ -15,6 +15,12 @@ +@@ -13,6 +13,12 @@ int get_c0_perfcount_int(void) { diff --git a/target/linux/ramips/patches-5.4/300-mt7620-export-chip-version-and-pkg.patch b/target/linux/ramips/patches-5.4/300-mt7620-export-chip-version-and-pkg.patch index 0cb1fede30..8b4335eb03 100644 --- a/target/linux/ramips/patches-5.4/300-mt7620-export-chip-version-and-pkg.patch +++ b/target/linux/ramips/patches-5.4/300-mt7620-export-chip-version-and-pkg.patch @@ -1,6 +1,6 @@ --- a/arch/mips/include/asm/mach-ralink/mt7620.h +++ b/arch/mips/include/asm/mach-ralink/mt7620.h -@@ -137,4 +137,16 @@ static inline int mt7620_get_eco(void) +@@ -135,4 +135,16 @@ static inline int mt7620_get_eco(void) return rt_sysc_r32(SYSC_REG_CHIP_REV) & CHIP_REV_ECO_MASK; } diff --git a/target/linux/ramips/patches-5.4/302-spi-nor-add-gd25q512.patch b/target/linux/ramips/patches-5.4/302-spi-nor-add-gd25q512.patch index 0a3a65d70a..3e229bcc1b 100644 --- a/target/linux/ramips/patches-5.4/302-spi-nor-add-gd25q512.patch +++ b/target/linux/ramips/patches-5.4/302-spi-nor-add-gd25q512.patch @@ -1,8 +1,8 @@ --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c -@@ -1066,6 +1066,11 @@ static const struct flash_info spi_nor_i - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) +@@ -2238,6 +2238,11 @@ static const struct flash_info spi_nor_i + SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + .fixups = &gd25q256_fixups, }, + { + "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024, diff --git a/target/linux/ramips/patches-5.4/304-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch b/target/linux/ramips/patches-5.4/304-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch deleted file mode 100644 index 8b59a106e1..0000000000 --- a/target/linux/ramips/patches-5.4/304-spi-nor-enable-4B-opcodes-for-mx25l25635f.patch +++ /dev/null @@ -1,72 +0,0 @@ -This hack can be dropped after the next stable release from -v5.x-tree. - -The problem was fixed upstream by - -commit 2bffa65da43e ("mtd: spi-nor: Add a post BFPT fixup for MX25L25635E") - -For reference see: -<https://github.com/openwrt/openwrt/pull/1743> - ---- a/drivers/mtd/spi-nor/spi-nor.c -+++ b/drivers/mtd/spi-nor/spi-nor.c -@@ -1103,6 +1103,7 @@ static const struct flash_info spi_nor_i - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, - { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, - { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, -@@ -1275,11 +1276,12 @@ static const struct flash_info spi_nor_i - { }, - }; - --static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) -+static const struct flash_info *spi_nor_read_id(struct spi_nor *nor, -+ const char *name) - { - int tmp; - u8 id[SPI_NOR_MAX_ID_LEN]; -- const struct flash_info *info; -+ const struct flash_info *info, *first_match = NULL; - - tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); - if (tmp < 0) { -@@ -1290,10 +1292,16 @@ static const struct flash_info *spi_nor_ - for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { - info = &spi_nor_ids[tmp]; - if (info->id_len) { -- if (!memcmp(info->id, id, info->id_len)) -- return &spi_nor_ids[tmp]; -+ if (!memcmp(info->id, id, info->id_len)) { -+ if (!name || !strcmp(name, info->name)) -+ return info; -+ if (!first_match) -+ first_match = info; -+ } - } - } -+ if (first_match) -+ return first_match; - dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", - id[0], id[1], id[2]); - return ERR_PTR(-ENODEV); -@@ -2773,7 +2781,7 @@ int spi_nor_scan(struct spi_nor *nor, co - info = spi_nor_match_id(name); - /* Try to auto-detect if chip name wasn't specified or not found */ - if (!info) -- info = spi_nor_read_id(nor); -+ info = spi_nor_read_id(nor, NULL); - if (IS_ERR_OR_NULL(info)) - return -ENOENT; - -@@ -2784,7 +2792,7 @@ int spi_nor_scan(struct spi_nor *nor, co - if (name && info->id_len) { - const struct flash_info *jinfo; - -- jinfo = spi_nor_read_id(nor); -+ jinfo = spi_nor_read_id(nor, name); - if (IS_ERR(jinfo)) { - return PTR_ERR(jinfo); - } else if (jinfo != info) { diff --git a/target/linux/ramips/patches-5.4/999-fix-pci-init-mt7620.patch b/target/linux/ramips/patches-5.4/999-fix-pci-init-mt7620.patch index 3310a6bdba..7c00d4c9ae 100644 --- a/target/linux/ramips/patches-5.4/999-fix-pci-init-mt7620.patch +++ b/target/linux/ramips/patches-5.4/999-fix-pci-init-mt7620.patch @@ -1,14 +1,14 @@ --- a/arch/mips/pci/pci-mt7620.c +++ b/arch/mips/pci/pci-mt7620.c -@@ -35,6 +35,7 @@ +@@ -32,6 +32,7 @@ #define PPLL_CFG1 0x9c #define PPLL_DRV 0xa0 -+#define PPLL_LD (1<<23) - #define PDRV_SW_SET (1<<31) - #define LC_CKDRVPD (1<<19) - #define LC_CKDRVOHZ (1<<18) -@@ -242,8 +243,8 @@ static int mt7620_pci_hw_init(struct pla ++#define PPLL_LD BIT(23) + #define PDRV_SW_SET BIT(31) + #define LC_CKDRVPD BIT(19) + #define LC_CKDRVOHZ BIT(18) +@@ -239,8 +240,8 @@ static int mt7620_pci_hw_init(struct pla rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); mdelay(100); |