ramips: 5.10: rename patches to follow guide
authorIlya Lipnitskiy <ilya.lipnitskiy@gmail.com>
Sun, 28 Feb 2021 00:00:24 +0000 (16:00 -0800)
committerAdrian Schmutzler <freifunk@adrianschmutzler.de>
Sat, 6 Mar 2021 10:24:12 +0000 (11:24 +0100)
Rename patches to follow the 3-digit classification from the OpenWrt
Developer Guide.

https://openwrt.org/docs/guide-developer/build-system/use-patches-with-buildsystem#naming_patches

Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
72 files changed:
target/linux/ramips/patches-5.10/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch [deleted file]
target/linux/ramips/patches-5.10/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch [deleted file]
target/linux/ramips/patches-5.10/0006-MIPS-ralink-add-cpu-frequency-scaling.patch [deleted file]
target/linux/ramips/patches-5.10/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch [deleted file]
target/linux/ramips/patches-5.10/0010-MIPS-add-bootargs-override-property.patch [deleted file]
target/linux/ramips/patches-5.10/0013-owrt-hack-fix-mt7688-cache-issue.patch [deleted file]
target/linux/ramips/patches-5.10/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch [deleted file]
target/linux/ramips/patches-5.10/0024-GPIO-add-named-gpio-exports.patch [deleted file]
target/linux/ramips/patches-5.10/0026-DT-Add-documentation-for-gpio-ralink.patch [deleted file]
target/linux/ramips/patches-5.10/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch [deleted file]
target/linux/ramips/patches-5.10/0029-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch [deleted file]
target/linux/ramips/patches-5.10/0031-uvc-add-iPassion-iP2970-support.patch [deleted file]
target/linux/ramips/patches-5.10/0037-mtd-cfi-cmdset-0002-force-word-write.patch [deleted file]
target/linux/ramips/patches-5.10/0041-DT-Add-documentation-for-spi-rt2880.patch [deleted file]
target/linux/ramips/patches-5.10/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch [deleted file]
target/linux/ramips/patches-5.10/0044-i2c-MIPS-adds-ralink-I2C-driver.patch [deleted file]
target/linux/ramips/patches-5.10/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch [deleted file]
target/linux/ramips/patches-5.10/0048-asoc-add-mt7620-support.patch [deleted file]
target/linux/ramips/patches-5.10/0051-serial-add-ugly-custom-baud-rate-hack.patch [deleted file]
target/linux/ramips/patches-5.10/0052-pwm-add-mediatek-support.patch [deleted file]
target/linux/ramips/patches-5.10/0069-awake-rt305x-dwc2-controller.patch [deleted file]
target/linux/ramips/patches-5.10/0070-weak_reordering.patch [deleted file]
target/linux/ramips/patches-5.10/0123-mips-ralink-manage-low-reset-lines.patch [deleted file]
target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/0200-linkit_bootstrap.patch [deleted file]
target/linux/ramips/patches-5.10/0300-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch [deleted file]
target/linux/ramips/patches-5.10/0301-dt-bindings-add-documentation-for-mt7621-nand-driver.patch [deleted file]
target/linux/ramips/patches-5.10/100-mt7621-core-detect-hack.patch [deleted file]
target/linux/ramips/patches-5.10/101-mt7621-timer.patch [deleted file]
target/linux/ramips/patches-5.10/102-mt7621-fix-cpu-clk-add-clkdev.patch [deleted file]
target/linux/ramips/patches-5.10/105-mt7621-memory-detect.patch [deleted file]
target/linux/ramips/patches-5.10/110-mt7621-perfctr-fix.patch [deleted file]
target/linux/ramips/patches-5.10/202-weak_reordering.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/302-spi-nor-add-gd25q512.patch [deleted file]
target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/314-MIPS-add-bootargs-override-property.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/321-mt7621-timer.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/401-net-ethernet-mediatek-support-net-labels.patch [deleted file]
target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/710-at803x.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch [new file with mode: 0644]
target/linux/ramips/patches-5.10/990-NET-no-auto-carrier-off-support.patch [deleted file]
target/linux/ramips/patches-5.10/991-at803x.patch [deleted file]
target/linux/ramips/patches-5.10/999-fix-pci-init-mt7620.patch [deleted file]

diff --git a/target/linux/ramips/patches-5.10/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch b/target/linux/ramips/patches-5.10/0003-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch
deleted file mode 100644 (file)
index 63429f4..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-From: Tobias Wolf <dev-NTEO@vplace.de>
-Subject: [v2] MIPS: Fix memory reservation in bootmem_init for certain non-usermem setups
-
-Commit 67a3ba25aa95 ("MIPS: Fix incorrect mem=X@Y handling") introduced a new
-issue for rt288x where "PHYS_OFFSET" is 0x0 but the calculated "ramstart" is
-not. As the prerequisite of custom memory map has been removed, this results
-in the full memory range of 0x0 - 0x8000000 to be marked as reserved for this
-platform.
-
-v2: Correctly compare that usermem is not null.
-
-This patch adds the originally intended prerequisite again.
-
-Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
----
-
---- a/arch/mips/kernel/setup.c
-+++ b/arch/mips/kernel/setup.c
-@@ -287,6 +287,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)
-@@ -325,7 +327,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)
-               memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
-       if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
-@@ -386,8 +388,6 @@ static void __init bootmem_init(void)
- #endif        /* CONFIG_SGI_IP27 */
--static int usermem __initdata;
--
- static int __init early_parse_mem(char *p)
- {
-       phys_addr_t start, size;
diff --git a/target/linux/ramips/patches-5.10/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch b/target/linux/ramips/patches-5.10/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch
deleted file mode 100644 (file)
index 773c74f..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 14 Jul 2013 23:08:11 +0200
-Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
- irq
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/Kconfig |    5 +++++
- 1 file changed, 5 insertions(+)
-
---- a/arch/mips/ralink/Kconfig
-+++ b/arch/mips/ralink/Kconfig
-@@ -1,12 +1,17 @@
- # SPDX-License-Identifier: GPL-2.0
- if RALINK
-+config CEVT_SYSTICK_QUIRK
-+      bool
-+      default n
-+
- config CLKEVT_RT3352
-       bool
-       depends on SOC_RT305X || SOC_MT7620
-       default y
-       select TIMER_OF
-       select CLKSRC_MMIO
-+      select CEVT_SYSTICK_QUIRK
- config RALINK_ILL_ACC
-       bool
---- a/arch/mips/kernel/cevt-r4k.c
-+++ b/arch/mips/kernel/cevt-r4k.c
-@@ -15,6 +15,26 @@
- #include <asm/time.h>
- #include <asm/cevt-r4k.h>
-+static int mips_state_oneshot(struct clock_event_device *evt)
-+{
-+      if (!cp0_timer_irq_installed) {
-+              cp0_timer_irq_installed = 1;
-+              setup_irq(evt->irq, &c0_compare_irqaction);
-+      }
-+
-+      return 0;
-+}
-+
-+static int mips_state_shutdown(struct clock_event_device *evt)
-+{
-+      if (cp0_timer_irq_installed) {
-+              cp0_timer_irq_installed = 0;
-+              remove_irq(evt->irq, &c0_compare_irqaction);
-+      }
-+
-+      return 0;
-+}
-+
- static int mips_next_event(unsigned long delta,
-                          struct clock_event_device *evt)
- {
-@@ -281,17 +301,21 @@ int r4k_clockevent_init(void)
-       cd->rating              = 300;
-       cd->irq                 = irq;
-       cd->cpumask             = cpumask_of(cpu);
-+      cd->set_state_shutdown  = mips_state_shutdown;
-+      cd->set_state_oneshot   = mips_state_oneshot;
-       cd->set_next_event      = mips_next_event;
-       cd->event_handler       = mips_event_handler;
-       clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
-+#ifndef CONFIG_CEVT_SYSTICK_QUIRK
-       if (cp0_timer_irq_installed)
-               return 0;
-       cp0_timer_irq_installed = 1;
-       setup_irq(irq, &c0_compare_irqaction);
-+#endif
-       return 0;
- }
diff --git a/target/linux/ramips/patches-5.10/0006-MIPS-ralink-add-cpu-frequency-scaling.patch b/target/linux/ramips/patches-5.10/0006-MIPS-ralink-add-cpu-frequency-scaling.patch
deleted file mode 100644 (file)
index a3b8e4d..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 28 Jul 2013 16:26:41 +0200
-Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
-
-This feature will break udelay() and cause the delay loop to have longer delays
-when the frequency is scaled causing a performance hit.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/cevt-rt3352.c |   38 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 38 insertions(+)
-
---- a/arch/mips/ralink/cevt-rt3352.c
-+++ b/arch/mips/ralink/cevt-rt3352.c
-@@ -29,6 +29,10 @@
- /* enable the counter */
- #define CFG_CNT_EN            0x1
-+/* mt7620 frequency scaling defines */
-+#define CLK_LUT_CFG   0x40
-+#define SLEEP_EN      BIT(31)
-+
- struct systick_device {
-       void __iomem *membase;
-       struct clock_event_device dev;
-@@ -36,21 +40,53 @@ struct systick_device {
-       int freq_scale;
- };
-+static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
-+
- static int systick_set_oneshot(struct clock_event_device *evt);
- static int systick_shutdown(struct clock_event_device *evt);
-+static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
-+{
-+      if (sdev->freq_scale == status)
-+              return;
-+
-+      sdev->freq_scale = status;
-+
-+      pr_info("%s: %s autosleep mode\n", sdev->dev.name,
-+                      (status) ? ("enable") : ("disable"));
-+      if (status)
-+              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
-+      else
-+              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
-+}
-+
-+static inline unsigned int read_count(struct systick_device *sdev)
-+{
-+      return ioread32(sdev->membase + SYSTICK_COUNT);
-+}
-+
-+static inline unsigned int read_compare(struct systick_device *sdev)
-+{
-+      return ioread32(sdev->membase + SYSTICK_COMPARE);
-+}
-+
-+static inline void write_compare(struct systick_device *sdev, unsigned int val)
-+{
-+      iowrite32(val, sdev->membase + SYSTICK_COMPARE);
-+}
-+
- static int systick_next_event(unsigned long delta,
-                               struct clock_event_device *evt)
- {
-       struct systick_device *sdev;
--      u32 count;
-+      int res;
-       sdev = container_of(evt, struct systick_device, dev);
--      count = ioread32(sdev->membase + SYSTICK_COUNT);
--      count = (count + delta) % SYSTICK_FREQ;
--      iowrite32(count, sdev->membase + SYSTICK_COMPARE);
-+      delta += read_count(sdev);
-+      write_compare(sdev, delta);
-+      res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
--      return 0;
-+      return res;
- }
- static void systick_event_handler(struct clock_event_device *dev)
-@@ -60,20 +96,25 @@ static void systick_event_handler(struct
- static irqreturn_t systick_interrupt(int irq, void *dev_id)
- {
--      struct clock_event_device *dev = (struct clock_event_device *) dev_id;
-+      int ret = 0;
-+      struct clock_event_device *cdev;
-+      struct systick_device *sdev;
--      dev->event_handler(dev);
-+      if (read_c0_cause() & STATUSF_IP7) {
-+              cdev = (struct clock_event_device *) dev_id;
-+              sdev = container_of(cdev, struct systick_device, dev);
-+
-+              /* Clear Count/Compare Interrupt */
-+              write_compare(sdev, read_compare(sdev));
-+              cdev->event_handler(cdev);
-+              ret = 1;
-+      }
--      return IRQ_HANDLED;
-+      return IRQ_RETVAL(ret);
- }
- static struct systick_device systick = {
-       .dev = {
--              /*
--               * cevt-r4k uses 300, make sure systick
--               * gets used if available
--               */
--              .rating                 = 310,
-               .features               = CLOCK_EVT_FEAT_ONESHOT,
-               .set_next_event         = systick_next_event,
-               .set_state_shutdown     = systick_shutdown,
-@@ -95,9 +136,15 @@ static int systick_shutdown(struct clock
-       sdev = container_of(evt, struct systick_device, dev);
-       if (sdev->irq_requested)
--              free_irq(systick.dev.irq, &systick_irqaction);
-+              remove_irq(systick.dev.irq, &systick_irqaction);
-       sdev->irq_requested = 0;
--      iowrite32(0, systick.membase + SYSTICK_CONFIG);
-+      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
-+
-+      if (systick_freq_scaling)
-+              systick_freq_scaling(sdev, 0);
-+
-+      if (systick_freq_scaling)
-+              systick_freq_scaling(sdev, 1);
-       return 0;
- }
-@@ -117,34 +164,48 @@ static int systick_set_oneshot(struct cl
-       return 0;
- }
-+static const struct of_device_id systick_match[] = {
-+      { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
-+      {},
-+};
-+
- static int __init ralink_systick_init(struct device_node *np)
- {
-+      const struct of_device_id *match;
-+      int rating = 200;
-       int ret;
-       systick.membase = of_iomap(np, 0);
-       if (!systick.membase)
-               return -ENXIO;
--      systick_irqaction.name = np->name;
--      systick.dev.name = np->name;
--      clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
--      systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
--      systick.dev.max_delta_ticks = 0x7fff;
--      systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
--      systick.dev.min_delta_ticks = 0x3;
-+      match = of_match_node(systick_match, np);
-+      if (match) {
-+              systick_freq_scaling = match->data;
-+              /*
-+               * cevt-r4k uses 300, make sure systick
-+               * gets used if available
-+               */
-+              rating = 310;
-+      }
-+
-+      /* enable counter than register clock source */
-+      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
-+      clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
-+                      SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
-+
-+      /* register clock event */
-       systick.dev.irq = irq_of_parse_and_map(np, 0);
-       if (!systick.dev.irq) {
-               pr_err("%pOFn: request_irq failed", np);
-               return -EINVAL;
-       }
--      ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
--                                  SYSTICK_FREQ, 301, 16,
--                                  clocksource_mmio_readl_up);
--      if (ret)
--              return ret;
--
--      clockevents_register_device(&systick.dev);
-+      systick_irqaction.name = np->name;
-+      systick.dev.name = np->name;
-+      systick.dev.rating = rating;
-+      systick.dev.cpumask = cpumask_of(0);
-+      clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
-       pr_info("%pOFn: running - mult: %d, shift: %d\n",
-                       np, systick.dev.mult, systick.dev.shift);
diff --git a/target/linux/ramips/patches-5.10/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-5.10/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
deleted file mode 100644 (file)
index 54af571..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 4 Aug 2014 18:46:02 +0200
-Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/of.c |    2 ++
- 1 file changed, 2 insertions(+)
-
---- a/arch/mips/ralink/of.c
-+++ b/arch/mips/ralink/of.c
-@@ -80,6 +80,8 @@ void __init plat_mem_setup(void)
-       __dt_setup_arch(dtb);
-+      strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
-+
-       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.10/0010-MIPS-add-bootargs-override-property.patch b/target/linux/ramips/patches-5.10/0010-MIPS-add-bootargs-override-property.patch
deleted file mode 100644 (file)
index c19a0fb..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-From f15d27f9c90ede4b16eb37f9ae573ef81c2b6996 Mon Sep 17 00:00:00 2001
-From: David Bauer <mail@david-bauer.net>
-Date: Thu, 31 Dec 2020 18:49:12 +0100
-Subject: [PATCH] MIPS: add bootargs-override property
-
-Add support for the bootargs-override property to the chosen node
-similar to the one used on ipq806x or mpc85xx.
-
-This is necessary, as the U-Boot used on some boards, notably the
-Ubiquiti UniFi 6 Lite, overwrite the bootargs property of the chosen
-node leading to a kernel panic when loading OpenWrt.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
----
- arch/mips/kernel/setup.c | 30 ++++++++++++++++++++++++++++++
- 1 file changed, 30 insertions(+)
-
---- a/arch/mips/kernel/setup.c
-+++ b/arch/mips/kernel/setup.c
-@@ -571,8 +571,28 @@ static int __init bootcmdline_scan_chose
-       return 1;
- }
-+static int __init bootcmdline_scan_chosen_override(unsigned long node, const char *uname,
-+                                                 int depth, void *data)
-+{
-+      bool *dt_bootargs = data;
-+      const char *p;
-+      int l;
-+
-+      if (depth != 1 || !data || strcmp(uname, "chosen") != 0)
-+              return 0;
-+
-+      p = of_get_flat_dt_prop(node, "bootargs-override", &l);
-+      if (p != NULL && l > 0) {
-+              strlcpy(boot_command_line, p, COMMAND_LINE_SIZE);
-+              *dt_bootargs = true;
-+      }
-+
-+      return 1;
-+}
-+
- static void __init bootcmdline_init(char **cmdline_p)
- {
-+      bool dt_bootargs_override = false;
-       bool dt_bootargs = false;
-       /*
-@@ -586,6 +606,14 @@ static void __init bootcmdline_init(char
-       }
-       /*
-+       * If bootargs-override in the chosen node is set, use this as the
-+       * command line
-+       */
-+      of_scan_flat_dt(bootcmdline_scan_chosen_override, &dt_bootargs_override);
-+      if (dt_bootargs_override)
-+              return;
-+
-+      /*
-        * If the user specified a built-in command line &
-        * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
-        * prepended to arguments from the bootloader or DT so we'll copy them
diff --git a/target/linux/ramips/patches-5.10/0013-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-5.10/0013-owrt-hack-fix-mt7688-cache-issue.patch
deleted file mode 100644 (file)
index bedea14..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 7 Dec 2015 17:15:32 +0100
-Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/kernel/setup.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/arch/mips/kernel/setup.c
-+++ b/arch/mips/kernel/setup.c
-@@ -723,8 +723,6 @@ static void __init arch_mem_init(char **
-               memblock_reserve(crashk_res.start,
-                                crashk_res.end - crashk_res.start + 1);
- #endif
--      device_tree_init();
--
-       /*
-        * In order to reduce the possibility of kernel panic when failed to
-        * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
-@@ -841,6 +839,7 @@ void __init setup_arch(char **cmdline_p)
-       cpu_cache_init();
-       paging_init();
-+      device_tree_init();
- }
- unsigned long kernelsp[NR_CPUS];
diff --git a/target/linux/ramips/patches-5.10/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch b/target/linux/ramips/patches-5.10/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch
deleted file mode 100644 (file)
index 1dc54cc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 7 Dec 2015 17:18:05 +0100
-Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
- default
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/Kconfig |    4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/mips/ralink/Kconfig
-+++ b/arch/mips/ralink/Kconfig
-@@ -14,9 +14,9 @@ config CLKEVT_RT3352
-       select CEVT_SYSTICK_QUIRK
- config RALINK_ILL_ACC
--      bool
-+      bool "illegal access irq"
-       depends on SOC_RT305X
--      default y
-+      default n
- config IRQ_INTC
-       bool
diff --git a/target/linux/ramips/patches-5.10/0024-GPIO-add-named-gpio-exports.patch b/target/linux/ramips/patches-5.10/0024-GPIO-add-named-gpio-exports.patch
deleted file mode 100644 (file)
index d4ea379..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Tue, 12 Aug 2014 20:49:27 +0200
-Subject: [PATCH 24/53] GPIO: add named gpio exports
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++
- drivers/gpio/gpiolib-sysfs.c  |   10 +++++-
- include/asm-generic/gpio.h    |    6 ++++
- include/linux/gpio/consumer.h |    8 +++++
- 4 files changed, 91 insertions(+), 1 deletion(-)
-
---- a/drivers/gpio/gpiolib-of.c
-+++ b/drivers/gpio/gpiolib-of.c
-@@ -19,6 +19,8 @@
- #include <linux/pinctrl/pinctrl.h>
- #include <linux/slab.h>
- #include <linux/gpio/machine.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
- #include "gpiolib.h"
- #include "gpiolib-of.h"
-@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip
- {
-       of_node_put(chip->of_node);
- }
-+
-+static struct of_device_id gpio_export_ids[] = {
-+      { .compatible = "gpio-export" },
-+      { /* sentinel */ }
-+};
-+
-+static int of_gpio_export_probe(struct platform_device *pdev)
-+{
-+      struct device_node *np = pdev->dev.of_node;
-+      struct device_node *cnp;
-+      u32 val;
-+      int nb = 0;
-+
-+      for_each_child_of_node(np, cnp) {
-+              const char *name = NULL;
-+              int gpio;
-+              bool dmc;
-+              int max_gpio = 1;
-+              int i;
-+
-+              of_property_read_string(cnp, "gpio-export,name", &name);
-+
-+              if (!name)
-+                      max_gpio = of_gpio_count(cnp);
-+
-+              for (i = 0; i < max_gpio; i++) {
-+                      unsigned flags = 0;
-+                      enum of_gpio_flags of_flags;
-+
-+                      gpio = of_get_gpio_flags(cnp, i, &of_flags);
-+                      if (!gpio_is_valid(gpio))
-+                              return gpio;
-+
-+                      if (of_flags == OF_GPIO_ACTIVE_LOW)
-+                              flags |= GPIOF_ACTIVE_LOW;
-+
-+                      if (!of_property_read_u32(cnp, "gpio-export,output", &val))
-+                              flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-+                      else
-+                              flags |= GPIOF_IN;
-+
-+                      if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
-+                              continue;
-+
-+                      dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
-+                      gpio_export_with_name(gpio, dmc, name);
-+                      nb++;
-+              }
-+      }
-+
-+      dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver gpio_export_driver = {
-+      .driver         = {
-+              .name           = "gpio-export",
-+              .owner  = THIS_MODULE,
-+              .of_match_table = of_match_ptr(gpio_export_ids),
-+      },
-+      .probe          = of_gpio_export_probe,
-+};
-+
-+module_platform_driver(gpio_export_driver);
---- a/drivers/gpio/gpiolib-sysfs.c
-+++ b/drivers/gpio/gpiolib-sysfs.c
-@@ -563,7 +563,7 @@ static struct class gpio_class = {
-  *
-  * Returns zero on success, else an error.
-  */
--int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
- {
-       struct gpio_chip        *chip;
-       struct gpio_device      *gdev;
-@@ -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];
-+      if (name)
-+              ioname = name;
-       dev = device_create_with_groups(&gpio_class, &gdev->dev,
-                                       MKDEV(0, 0), data, gpio_groups,
-@@ -646,6 +648,12 @@ err_unlock:
-       gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-       return status;
- }
-+EXPORT_SYMBOL_GPL(__gpiod_export);
-+
-+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-+{
-+      return __gpiod_export(desc, direction_may_change, NULL);
-+}
- EXPORT_SYMBOL_GPL(gpiod_export);
- static int match_export(struct device *dev, const void *desc)
---- a/include/asm-generic/gpio.h
-+++ b/include/asm-generic/gpio.h
-@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
-       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
- }
-+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
-+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
-+{
-+      return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
-+}
-+
- static inline int gpio_export_link(struct device *dev, const char *name,
-                                  unsigned gpio)
- {
---- a/include/linux/gpio/consumer.h
-+++ b/include/linux/gpio/consumer.h
-@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_
- #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
-+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
- 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);
-@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de
- #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
-+static inline int _gpiod_export(struct gpio_desc *desc,
-+                             bool direction_may_change,
-+                             const char *name)
-+{
-+      return -ENOSYS;
-+}
-+
- static inline int gpiod_export(struct gpio_desc *desc,
-                              bool direction_may_change)
- {
diff --git a/target/linux/ramips/patches-5.10/0026-DT-Add-documentation-for-gpio-ralink.patch b/target/linux/ramips/patches-5.10/0026-DT-Add-documentation-for-gpio-ralink.patch
deleted file mode 100644 (file)
index 7d5f98f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 28 Jul 2013 19:45:30 +0200
-Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
-
-Describe gpio-ralink binding.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
-Cc: linux-mips@linux-mips.org
-Cc: devicetree@vger.kernel.org
-Cc: linux-gpio@vger.kernel.org
----
- .../devicetree/bindings/gpio/gpio-ralink.txt       |   40 ++++++++++++++++++++
- 1 file changed, 40 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
-@@ -0,0 +1,40 @@
-+Ralink SoC GPIO controller bindings
-+
-+Required properties:
-+- compatible:
-+  - "ralink,rt2880-gpio" for Ralink controllers
-+- #gpio-cells : Should be two.
-+  - first cell is the pin number
-+  - second cell is used to specify optional parameters (unused)
-+- gpio-controller : Marks the device node as a GPIO controller
-+- reg : Physical base address and length of the controller's registers
-+- interrupt-parent: phandle to the INTC device node
-+- interrupts : Specify the INTC interrupt number
-+- ralink,num-gpios : Specify the number of GPIOs
-+- ralink,register-map : The register layout depends on the GPIO bank and actual
-+              SoC type. Register offsets need to be in this order.
-+              [ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
-+
-+Optional properties:
-+- ralink,gpio-base : Specify the GPIO chips base number
-+
-+Example:
-+
-+      gpio0: gpio@600 {
-+              compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
-+
-+              #gpio-cells = <2>;
-+              gpio-controller;
-+
-+              reg = <0x600 0x34>;
-+
-+              interrupt-parent = <&intc>;
-+              interrupts = <6>;
-+
-+              ralink,gpio-base = <0>;
-+              ralink,num-gpios = <24>;
-+              ralink,register-map = [ 00 04 08 0c
-+                              20 24 28 2c
-+                              30 34 ];
-+
-+      };
diff --git a/target/linux/ramips/patches-5.10/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch b/target/linux/ramips/patches-5.10/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch
deleted file mode 100644 (file)
index eae507b..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 4 Aug 2014 20:36:29 +0200
-Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
-
-Add gpio driver for Ralink SoC. This driver makes the gpio core on
-RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
-Cc: linux-mips@linux-mips.org
-Cc: linux-gpio@vger.kernel.org
----
- arch/mips/include/asm/mach-ralink/gpio.h |   24 ++
- drivers/gpio/Kconfig                     |    6 +
- drivers/gpio/Makefile                    |    1 +
- drivers/gpio/gpio-ralink.c               |  355 ++++++++++++++++++++++++++++++
- 4 files changed, 386 insertions(+)
- create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
- create mode 100644 drivers/gpio/gpio-ralink.c
-
---- /dev/null
-+++ b/arch/mips/include/asm/mach-ralink/gpio.h
-@@ -0,0 +1,24 @@
-+/*
-+ *  Ralink SoC GPIO API support
-+ *
-+ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
-+ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify it
-+ *  under the terms of the GNU General Public License version 2 as published
-+ *  by the Free Software Foundation.
-+ *
-+ */
-+
-+#ifndef __ASM_MACH_RALINK_GPIO_H
-+#define __ASM_MACH_RALINK_GPIO_H
-+
-+#define ARCH_NR_GPIOS 128
-+#include <asm-generic/gpio.h>
-+
-+#define gpio_get_value        __gpio_get_value
-+#define gpio_set_value        __gpio_set_value
-+#define gpio_cansleep __gpio_cansleep
-+#define gpio_to_irq   __gpio_to_irq
-+
-+#endif /* __ASM_MACH_RALINK_GPIO_H */
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -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"
-+      depends on RALINK
-+      help
-+        Say yes here to support the Ralink SoC GPIO device
-+
- config GPIO_SPEAR_SPICS
-       bool "ST SPEAr13xx SPI Chip Select as GPIO support"
-       depends on PLAT_SPEAR
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -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,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
-+ * by the Free Software Foundation.
-+ *
-+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
-+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/io.h>
-+#include <linux/gpio.h>
-+#include <linux/spinlock.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/interrupt.h>
-+
-+enum ralink_gpio_reg {
-+      GPIO_REG_INT = 0,
-+      GPIO_REG_EDGE,
-+      GPIO_REG_RENA,
-+      GPIO_REG_FENA,
-+      GPIO_REG_DATA,
-+      GPIO_REG_DIR,
-+      GPIO_REG_POL,
-+      GPIO_REG_SET,
-+      GPIO_REG_RESET,
-+      GPIO_REG_TOGGLE,
-+      GPIO_REG_MAX
-+};
-+
-+struct ralink_gpio_chip {
-+      struct gpio_chip chip;
-+      u8 regs[GPIO_REG_MAX];
-+
-+      spinlock_t lock;
-+      void __iomem *membase;
-+      struct irq_domain *domain;
-+      int irq;
-+
-+      u32 rising;
-+      u32 falling;
-+};
-+
-+#define MAP_MAX       4
-+static struct irq_domain *irq_map[MAP_MAX];
-+static int irq_map_count;
-+static atomic_t irq_refcount = ATOMIC_INIT(0);
-+
-+static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
-+{
-+      struct ralink_gpio_chip *rg;
-+
-+      rg = container_of(chip, struct ralink_gpio_chip, chip);
-+
-+      return rg;
-+}
-+
-+static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
-+{
-+      iowrite32(val, rg->membase + rg->regs[reg]);
-+}
-+
-+static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
-+{
-+      return ioread32(rg->membase + rg->regs[reg]);
-+}
-+
-+static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-+{
-+      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
-+
-+      rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
-+}
-+
-+static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
-+{
-+      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
-+
-+      return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
-+}
-+
-+static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-+{
-+      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
-+      unsigned long flags;
-+      u32 t;
-+
-+      spin_lock_irqsave(&rg->lock, flags);
-+      t = rt_gpio_r32(rg, GPIO_REG_DIR);
-+      t &= ~BIT(offset);
-+      rt_gpio_w32(rg, GPIO_REG_DIR, t);
-+      spin_unlock_irqrestore(&rg->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int ralink_gpio_direction_output(struct gpio_chip *chip,
-+                                      unsigned offset, int value)
-+{
-+      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
-+      unsigned long flags;
-+      u32 t;
-+
-+      spin_lock_irqsave(&rg->lock, flags);
-+      ralink_gpio_set(chip, offset, value);
-+      t = rt_gpio_r32(rg, GPIO_REG_DIR);
-+      t |= BIT(offset);
-+      rt_gpio_w32(rg, GPIO_REG_DIR, t);
-+      spin_unlock_irqrestore(&rg->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
-+{
-+      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
-+
-+      if (rg->irq < 1)
-+              return -1;
-+
-+      return irq_create_mapping(rg->domain, pin);
-+}
-+
-+static void ralink_gpio_irq_handler(struct irq_desc *desc)
-+{
-+      int i;
-+
-+      for (i = 0; i < irq_map_count; i++) {
-+              struct irq_domain *domain = irq_map[i];
-+              struct ralink_gpio_chip *rg;
-+              unsigned long pending;
-+              int bit;
-+
-+              rg = (struct ralink_gpio_chip *) domain->host_data;
-+              pending = rt_gpio_r32(rg, GPIO_REG_INT);
-+
-+              for_each_set_bit(bit, &pending, rg->chip.ngpio) {
-+                      u32 map = irq_find_mapping(domain, bit);
-+                      generic_handle_irq(map);
-+                      rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
-+              }
-+      }
-+}
-+
-+static void ralink_gpio_irq_unmask(struct irq_data *d)
-+{
-+      struct ralink_gpio_chip *rg;
-+      unsigned long flags;
-+      u32 rise, fall;
-+
-+      rg = (struct ralink_gpio_chip *) d->domain->host_data;
-+      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
-+      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
-+
-+      spin_lock_irqsave(&rg->lock, flags);
-+      rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
-+      rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
-+      spin_unlock_irqrestore(&rg->lock, flags);
-+}
-+
-+static void ralink_gpio_irq_mask(struct irq_data *d)
-+{
-+      struct ralink_gpio_chip *rg;
-+      unsigned long flags;
-+      u32 rise, fall;
-+
-+      rg = (struct ralink_gpio_chip *) d->domain->host_data;
-+      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
-+      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
-+
-+      spin_lock_irqsave(&rg->lock, flags);
-+      rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
-+      rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
-+      spin_unlock_irqrestore(&rg->lock, flags);
-+}
-+
-+static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
-+{
-+      struct ralink_gpio_chip *rg;
-+      u32 mask = BIT(d->hwirq);
-+
-+      rg = (struct ralink_gpio_chip *) d->domain->host_data;
-+
-+      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 ralink_gpio_irq_chip = {
-+      .name           = "GPIO",
-+      .irq_unmask     = ralink_gpio_irq_unmask,
-+      .irq_mask       = ralink_gpio_irq_mask,
-+      .irq_mask_ack   = ralink_gpio_irq_mask,
-+      .irq_set_type   = ralink_gpio_irq_type,
-+};
-+
-+static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
-+{
-+      irq_set_chip_and_handler(irq, &ralink_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 = gpio_map,
-+};
-+
-+static void ralink_gpio_irq_init(struct device_node *np,
-+                               struct ralink_gpio_chip *rg)
-+{
-+      if (irq_map_count >= MAP_MAX)
-+              return;
-+
-+      rg->irq = irq_of_parse_and_map(np, 0);
-+      if (!rg->irq)
-+              return;
-+
-+      rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
-+                                         &irq_domain_ops, rg);
-+      if (!rg->domain) {
-+              dev_err(rg->chip.parent, "irq_domain_add_linear failed\n");
-+              return;
-+      }
-+
-+      irq_map[irq_map_count++] = rg->domain;
-+
-+      rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
-+      rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
-+
-+      if (!atomic_read(&irq_refcount))
-+              irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
-+      atomic_inc(&irq_refcount);
-+
-+      dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio);
-+}
-+
-+static int ralink_gpio_probe(struct platform_device *pdev)
-+{
-+      struct device_node *np = pdev->dev.of_node;
-+      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      struct ralink_gpio_chip *rg;
-+      const __be32 *ngpio, *gpiobase;
-+
-+      if (!res) {
-+              dev_err(&pdev->dev, "failed to find resource\n");
-+              return -ENOMEM;
-+      }
-+
-+      rg = devm_kzalloc(&pdev->dev,
-+                      sizeof(struct ralink_gpio_chip), GFP_KERNEL);
-+      if (!rg)
-+              return -ENOMEM;
-+
-+      rg->membase = devm_ioremap_resource(&pdev->dev, res);
-+      if (!rg->membase) {
-+              dev_err(&pdev->dev, "cannot remap I/O memory region\n");
-+              return -ENOMEM;
-+      }
-+
-+      if (of_property_read_u8_array(np, "ralink,register-map",
-+                      rg->regs, GPIO_REG_MAX)) {
-+              dev_err(&pdev->dev, "failed to read register definition\n");
-+              return -EINVAL;
-+      }
-+
-+      ngpio = of_get_property(np, "ralink,num-gpios", NULL);
-+      if (!ngpio) {
-+              dev_err(&pdev->dev, "failed to read number of pins\n");
-+              return -EINVAL;
-+      }
-+
-+      gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
-+      if (gpiobase)
-+              rg->chip.base = be32_to_cpu(*gpiobase);
-+      else
-+              rg->chip.base = -1;
-+
-+      spin_lock_init(&rg->lock);
-+
-+      rg->chip.parent = &pdev->dev;
-+      rg->chip.label = dev_name(&pdev->dev);
-+      rg->chip.of_node = np;
-+      rg->chip.ngpio = be32_to_cpu(*ngpio);
-+      rg->chip.direction_input = ralink_gpio_direction_input;
-+      rg->chip.direction_output = ralink_gpio_direction_output;
-+      rg->chip.get = ralink_gpio_get;
-+      rg->chip.set = ralink_gpio_set;
-+      rg->chip.request = gpiochip_generic_request;
-+      rg->chip.to_irq = ralink_gpio_to_irq;
-+      rg->chip.free = gpiochip_generic_free;
-+
-+      /* set polarity to low for all lines */
-+      rt_gpio_w32(rg, GPIO_REG_POL, 0);
-+
-+      dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
-+
-+      ralink_gpio_irq_init(np, rg);
-+
-+      return gpiochip_add(&rg->chip);
-+}
-+
-+static const struct of_device_id ralink_gpio_match[] = {
-+      { .compatible = "ralink,rt2880-gpio" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, ralink_gpio_match);
-+
-+static struct platform_driver ralink_gpio_driver = {
-+      .probe = ralink_gpio_probe,
-+      .driver = {
-+              .name = "rt2880_gpio",
-+              .owner = THIS_MODULE,
-+              .of_match_table = ralink_gpio_match,
-+      },
-+};
-+
-+static int __init ralink_gpio_init(void)
-+{
-+      return platform_driver_register(&ralink_gpio_driver);
-+}
-+
-+subsys_initcall(ralink_gpio_init);
diff --git a/target/linux/ramips/patches-5.10/0029-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch b/target/linux/ramips/patches-5.10/0029-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch
deleted file mode 100644 (file)
index 8520ce3..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 57fa7f2f4ef6f78ce1d30509c0d111aa3791b524 Mon Sep 17 00:00:00 2001
-From: Daniel Santos <daniel.santos@pobox.com>
-Date: Sun, 4 Nov 2018 20:24:32 -0600
-Subject: gpio-ralink: Add support for GPIO as interrupt-controller
-
-Signed-off-by: Daniel Santos <daniel.santos@pobox.com>
----
- Documentation/devicetree/bindings/gpio/gpio-ralink.txt | 6 ++++++
- drivers/gpio/gpio-ralink.c                             | 2 +-
- 2 files changed, 7 insertions(+), 1 deletion(-)
-
---- a/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
-+++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
-@@ -17,6 +17,9 @@ Required properties:
- Optional properties:
- - ralink,gpio-base : Specify the GPIO chips base number
-+- interrupt-controller : marks this as an interrupt controller
-+- #interrupt-cells : a standard two-cell interrupt flag, see
-+  interrupt-controller/interrupts.txt
- Example:
-@@ -28,6 +31,9 @@ Example:
-               reg = <0x600 0x34>;
-+              interrupt-controller;
-+              #interrupt-cells = <2>;
-+
-               interrupt-parent = <&intc>;
-               interrupts = <6>;
---- a/drivers/gpio/gpio-ralink.c
-+++ b/drivers/gpio/gpio-ralink.c
-@@ -220,7 +220,7 @@ static int gpio_map(struct irq_domain *d
- }
- static const struct irq_domain_ops irq_domain_ops = {
--      .xlate = irq_domain_xlate_onecell,
-+      .xlate = irq_domain_xlate_twocell,
-       .map = gpio_map,
- };
diff --git a/target/linux/ramips/patches-5.10/0031-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.10/0031-uvc-add-iPassion-iP2970-support.patch
deleted file mode 100644 (file)
index 084b655..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 19 Sep 2013 01:50:59 +0200
-Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/media/usb/uvc/uvc_driver.c |   12 +++
- drivers/media/usb/uvc/uvc_status.c |    2 +
- drivers/media/usb/uvc/uvc_video.c  |  147 ++++++++++++++++++++++++++++++++++++
- drivers/media/usb/uvc/uvcvideo.h   |    5 +-
- 4 files changed, 165 insertions(+), 1 deletion(-)
-
---- a/drivers/media/usb/uvc/uvc_driver.c
-+++ b/drivers/media/usb/uvc/uvc_driver.c
-@@ -2908,6 +2908,18 @@ static const struct usb_device_id uvc_id
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
-+      /* iPassion iP2970 */
-+      { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-+                              | USB_DEVICE_ID_MATCH_INT_INFO,
-+       .idVendor              = 0x1B3B,
-+       .idProduct             = 0x2970,
-+       .bInterfaceClass       = USB_CLASS_VIDEO,
-+       .bInterfaceSubClass    = 1,
-+       .bInterfaceProtocol    = 0,
-+       .driver_info           = UVC_QUIRK_PROBE_MINMAX
-+                              | UVC_QUIRK_STREAM_NO_FID
-+                              | UVC_QUIRK_MOTION
-+                              | UVC_QUIRK_SINGLE_ISO },
-       /* Generic USB Video Class */
-       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
-       { 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
-@@ -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;
-               }
-@@ -271,6 +272,7 @@ int uvc_status_init(struct uvc_device *d
-       }
-       pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
-+      dev->motion = 0;
-       /* For high-speed interrupt endpoints, the bInterval value is used as
-        * 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
-@@ -16,6 +16,11 @@
- #include <linux/wait.h>
- #include <linux/atomic.h>
- #include <asm/unaligned.h>
-+#include <linux/skbuff.h>
-+#include <linux/kobject.h>
-+#include <linux/netlink.h>
-+#include <linux/kobject.h>
-+#include <linux/workqueue.h>
- #include <media/v4l2-common.h>
-@@ -1156,9 +1161,149 @@ static void uvc_video_decode_data(struct
-       uvc_urb->async_operations++;
- }
-+struct bh_priv {
-+      unsigned long   seen;
-+};
-+
-+struct bh_event {
-+      const char              *name;
-+      struct sk_buff          *skb;
-+      struct work_struct      work;
-+};
-+
-+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
-+#define BH_DBG(fmt, args...) do {} while (0)
-+#define BH_SKB_SIZE     2048
-+
-+extern u64 uevent_next_seqnum(void);
-+static int seen = 0;
-+
-+static int bh_event_add_var(struct bh_event *event, int argv,
-+              const char *format, ...)
-+{
-+      static char buf[128];
-+      char *s;
-+      va_list args;
-+      int len;
-+
-+      if (argv)
-+              return 0;
-+
-+      va_start(args, format);
-+      len = vsnprintf(buf, sizeof(buf), format, args);
-+      va_end(args);
-+
-+      if (len >= sizeof(buf)) {
-+              BH_ERR("buffer size too small\n");
-+              WARN_ON(1);
-+              return -ENOMEM;
-+      }
-+
-+      s = skb_put(event->skb, len + 1);
-+      strcpy(s, buf);
-+
-+      BH_DBG("added variable '%s'\n", s);
-+
-+      return 0;
-+}
-+
-+static int motion_hotplug_fill_event(struct bh_event *event)
-+{
-+      int s = jiffies;
-+      int ret;
-+
-+      if (!seen)
-+              seen = jiffies;
-+
-+      ret = bh_event_add_var(event, 0, "HOME=%s", "/");
-+      if (ret)
-+              return ret;
-+
-+      ret = bh_event_add_var(event, 0, "PATH=%s",
-+              "/sbin:/bin:/usr/sbin:/usr/bin");
-+      if (ret)
-+              return ret;
-+
-+      ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
-+      if (ret)
-+              return ret;
-+
-+      ret = bh_event_add_var(event, 0, "ACTION=motion");
-+      if (ret)
-+              return ret;
-+
-+      ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
-+      if (ret)
-+              return ret;
-+      seen = s;
-+
-+      ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
-+
-+      return ret;
-+}
-+
-+static void motion_hotplug_work(struct work_struct *work)
-+{
-+      struct bh_event *event = container_of(work, struct bh_event, work);
-+      int ret = 0;
-+
-+      event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
-+      if (!event->skb)
-+              goto out_free_event;
-+
-+      ret = bh_event_add_var(event, 0, "%s@", "add");
-+      if (ret)
-+              goto out_free_skb;
-+
-+      ret = motion_hotplug_fill_event(event);
-+      if (ret)
-+              goto out_free_skb;
-+
-+      NETLINK_CB(event->skb).dst_group = 1;
-+      broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
-+
-+out_free_skb:
-+      if (ret) {
-+              BH_ERR("work error %d\n", ret);
-+              kfree_skb(event->skb);
-+      }
-+out_free_event:
-+      kfree(event);
-+}
-+
-+static int motion_hotplug_create_event(void)
-+{
-+      struct bh_event *event;
-+
-+      event = kzalloc(sizeof(*event), GFP_KERNEL);
-+      if (!event)
-+              return -ENOMEM;
-+
-+      event->name = "motion";
-+
-+      INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
-+      schedule_work(&event->work);
-+
-+      return 0;
-+}
-+
-+#define MOTION_FLAG_OFFSET    4
- static void uvc_video_decode_end(struct uvc_streaming *stream,
-               struct uvc_buffer *buf, const u8 *data, int len)
- {
-+      if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
-+                      (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
-+              u8 *mem;
-+              buf->state = UVC_BUF_STATE_READY;
-+              mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
-+              if ( stream->dev->motion ) {
-+                      stream->dev->motion = 0;
-+                      motion_hotplug_create_event();
-+              } else {
-+                      *mem &= 0x7f;
-+              }
-+      }
-+
-       /* 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");
-@@ -1715,6 +1860,8 @@ static int uvc_init_video_isoc(struct uv
-       if (npackets == 0)
-               return -ENOMEM;
-+      if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
-+              npackets = 1;
-       size = npackets * psize;
-       for_each_uvc_urb(uvc_urb, stream) {
---- a/drivers/media/usb/uvc/uvcvideo.h
-+++ b/drivers/media/usb/uvc/uvcvideo.h
-@@ -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
-+ 
- /* Format flags */
- #define UVC_FMT_FLAG_COMPRESSED               0x00000001
- #define UVC_FMT_FLAG_STREAM           0x00000002
-@@ -666,6 +668,7 @@ struct uvc_device {
-       u8 *status;
-       struct input_dev *input;
-       char input_phys[64];
-+      int motion;
-       struct uvc_ctrl_work {
-               struct work_struct work;
diff --git a/target/linux/ramips/patches-5.10/0037-mtd-cfi-cmdset-0002-force-word-write.patch b/target/linux/ramips/patches-5.10/0037-mtd-cfi-cmdset-0002-force-word-write.patch
deleted file mode 100644 (file)
index 7011bbe..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 15 Jul 2013 00:39:21 +0200
-Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
-
----
- drivers/mtd/chips/cfi_cmdset_0002.c |    9 +++++++--
- 1 file changed, 7 insertions(+), 2 deletions(-)
-
---- a/drivers/mtd/chips/cfi_cmdset_0002.c
-+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
-@@ -40,7 +40,7 @@
- #include <linux/mtd/xip.h>
- #define AMD_BOOTLOC_BUG
--#define FORCE_WORD_WRITE 0
-+#define FORCE_WORD_WRITE 1
- #define MAX_RETRIES 3
diff --git a/target/linux/ramips/patches-5.10/0041-DT-Add-documentation-for-spi-rt2880.patch b/target/linux/ramips/patches-5.10/0041-DT-Add-documentation-for-spi-rt2880.patch
deleted file mode 100644 (file)
index e2643e3..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Fri, 9 Aug 2013 20:12:59 +0200
-Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880
-
-Describe the SPI master found on the MIPS based Ralink RT2880 SoC.
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- .../devicetree/bindings/spi/spi-rt2880.txt         |   28 ++++++++++++++++++++
- 1 file changed, 28 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt
-@@ -0,0 +1,28 @@
-+Ralink SoC RT2880 SPI master controller.
-+
-+This SPI controller is found on most wireless SoCs made by ralink.
-+
-+Required properties:
-+- compatible : "ralink,rt2880-spi"
-+- reg : The register base for the controller.
-+- #address-cells : <1>, as required by generic SPI binding.
-+- #size-cells : <0>, also as required by generic SPI binding.
-+
-+Child nodes as per the generic SPI binding.
-+
-+Example:
-+
-+      spi@b00 {
-+              compatible = "ralink,rt2880-spi";
-+              reg = <0xb00 0x100>;
-+
-+              #address-cells = <1>;
-+              #size-cells = <0>;
-+
-+              m25p80@0 {
-+                      compatible = "m25p80";
-+                      reg = <0>;
-+                      spi-max-frequency = <10000000>;
-+              };
-+      };
-+
diff --git a/target/linux/ramips/patches-5.10/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-5.10/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch
deleted file mode 100644 (file)
index 6523716..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 27 Jul 2014 11:15:12 +0100
-Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver
-
-Add the driver needed to make SPI work on Ralink SoC.
-
-Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
-Acked-by: John Crispin <blogic@openwrt.org>
----
- drivers/spi/Kconfig      |    6 +
- drivers/spi/Makefile     |    1 +
- drivers/spi/spi-rt2880.c |  530 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 537 insertions(+)
- create mode 100644 drivers/spi/spi-rt2880.c
-
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -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-geni-qcom.
-+config SPI_RT2880
-+      tristate "Ralink RT288x SPI Controller"
-+      depends on RALINK
-+      help
-+        This selects a driver for the Ralink RT288x/RT305x SPI Controller.
-+
- config SPI_S3C24XX
-       tristate "Samsung S3C24XX series SPI"
-       depends on ARCH_S3C24XX
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -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
-+obj-$(CONFIG_SPI_RT2880)              += spi-rt2880.o
- obj-$(CONFIG_SPI_S3C24XX)             += spi-s3c24xx-hw.o
- spi-s3c24xx-hw-y                      := spi-s3c24xx.o
- spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
---- /dev/null
-+++ b/drivers/spi/spi-rt2880.c
-@@ -0,0 +1,530 @@
-+/*
-+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
-+ *
-+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
-+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
-+ *
-+ * Some parts are based on spi-orion.c:
-+ *   Author: Shadi Ammouri <shadi@marvell.com>
-+ *   Copyright (C) 2007-2008 Marvell Ltd.
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/reset.h>
-+#include <linux/spi/spi.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+
-+#define DRIVER_NAME                   "spi-rt2880"
-+
-+#define RAMIPS_SPI_STAT                       0x00
-+#define RAMIPS_SPI_CFG                        0x10
-+#define RAMIPS_SPI_CTL                        0x14
-+#define RAMIPS_SPI_DATA                       0x20
-+#define RAMIPS_SPI_ADDR                       0x24
-+#define RAMIPS_SPI_BS                 0x28
-+#define RAMIPS_SPI_USER                       0x2C
-+#define RAMIPS_SPI_TXFIFO             0x30
-+#define RAMIPS_SPI_RXFIFO             0x34
-+#define RAMIPS_SPI_FIFO_STAT          0x38
-+#define RAMIPS_SPI_MODE                       0x3C
-+#define RAMIPS_SPI_DEV_OFFSET         0x40
-+#define RAMIPS_SPI_DMA                        0x80
-+#define RAMIPS_SPI_DMASTAT            0x84
-+#define RAMIPS_SPI_ARBITER            0xF0
-+
-+/* SPISTAT register bit field */
-+#define SPISTAT_BUSY                  BIT(0)
-+
-+/* SPICFG register bit field */
-+#define SPICFG_ADDRMODE                       BIT(12)
-+#define SPICFG_RXENVDIS                       BIT(11)
-+#define SPICFG_RXCAP                  BIT(10)
-+#define SPICFG_SPIENMODE              BIT(9)
-+#define SPICFG_MSBFIRST                       BIT(8)
-+#define SPICFG_SPICLKPOL              BIT(6)
-+#define SPICFG_RXCLKEDGE_FALLING      BIT(5)
-+#define SPICFG_TXCLKEDGE_FALLING      BIT(4)
-+#define SPICFG_HIZSPI                 BIT(3)
-+#define SPICFG_SPICLK_PRESCALE_MASK   0x7
-+#define SPICFG_SPICLK_DIV2            0
-+#define SPICFG_SPICLK_DIV4            1
-+#define SPICFG_SPICLK_DIV8            2
-+#define SPICFG_SPICLK_DIV16           3
-+#define SPICFG_SPICLK_DIV32           4
-+#define SPICFG_SPICLK_DIV64           5
-+#define SPICFG_SPICLK_DIV128          6
-+#define SPICFG_SPICLK_DISABLE         7
-+
-+/* SPICTL register bit field */
-+#define SPICTL_START                  BIT(4)
-+#define SPICTL_HIZSDO                 BIT(3)
-+#define SPICTL_STARTWR                        BIT(2)
-+#define SPICTL_STARTRD                        BIT(1)
-+#define SPICTL_SPIENA                 BIT(0)
-+
-+/* SPIUSER register bit field */
-+#define SPIUSER_USERMODE              BIT(21)
-+#define SPIUSER_INSTR_PHASE           BIT(20)
-+#define SPIUSER_ADDR_PHASE_MASK               0x7
-+#define SPIUSER_ADDR_PHASE_OFFSET     17
-+#define SPIUSER_MODE_PHASE            BIT(16)
-+#define SPIUSER_DUMMY_PHASE_MASK      0x3
-+#define SPIUSER_DUMMY_PHASE_OFFSET    14
-+#define SPIUSER_DATA_PHASE_MASK               0x3
-+#define SPIUSER_DATA_PHASE_OFFSET     12
-+#define SPIUSER_DATA_READ             (BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
-+#define SPIUSER_DATA_WRITE            (BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
-+#define SPIUSER_ADDR_TYPE_OFFSET      9
-+#define SPIUSER_MODE_TYPE_OFFSET      6
-+#define SPIUSER_DUMMY_TYPE_OFFSET     3
-+#define SPIUSER_DATA_TYPE_OFFSET      0
-+#define SPIUSER_TRANSFER_MASK         0x7
-+#define SPIUSER_TRANSFER_SINGLE               BIT(0)
-+#define SPIUSER_TRANSFER_DUAL         BIT(1)
-+#define SPIUSER_TRANSFER_QUAD         BIT(2)
-+
-+#define SPIUSER_TRANSFER_TYPE(type) ( \
-+      (type << SPIUSER_ADDR_TYPE_OFFSET) | \
-+      (type << SPIUSER_MODE_TYPE_OFFSET) | \
-+      (type << SPIUSER_DUMMY_TYPE_OFFSET) | \
-+      (type << SPIUSER_DATA_TYPE_OFFSET) \
-+)
-+
-+/* SPIFIFOSTAT register bit field */
-+#define SPIFIFOSTAT_TXEMPTY           BIT(19)
-+#define SPIFIFOSTAT_RXEMPTY           BIT(18)
-+#define SPIFIFOSTAT_TXFULL            BIT(17)
-+#define SPIFIFOSTAT_RXFULL            BIT(16)
-+#define SPIFIFOSTAT_FIFO_MASK         0xff
-+#define SPIFIFOSTAT_TX_OFFSET         8
-+#define SPIFIFOSTAT_RX_OFFSET         0
-+
-+#define SPI_FIFO_DEPTH                        16
-+
-+/* SPIMODE register bit field */
-+#define SPIMODE_MODE_OFFSET           24
-+#define SPIMODE_DUMMY_OFFSET          0
-+
-+/* SPIARB register bit field */
-+#define SPICTL_ARB_EN                 BIT(31)
-+#define SPICTL_CSCTL1                 BIT(16)
-+#define SPI1_POR                      BIT(1)
-+#define SPI0_POR                      BIT(0)
-+
-+#define RT2880_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
-+              SPI_CS_HIGH)
-+
-+static atomic_t hw_reset_count = ATOMIC_INIT(0);
-+
-+struct rt2880_spi {
-+      struct spi_master       *master;
-+      void __iomem            *base;
-+      u32                     speed;
-+      u16                     wait_loops;
-+      u16                     mode;
-+      struct clk              *clk;
-+};
-+
-+static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
-+{
-+      return spi_master_get_devdata(spi->master);
-+}
-+
-+static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg)
-+{
-+      return ioread32(rs->base + reg);
-+}
-+
-+static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
-+              const u32 val)
-+{
-+      iowrite32(val, rs->base + reg);
-+}
-+
-+static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask)
-+{
-+      void __iomem *addr = rs->base + reg;
-+
-+      iowrite32((ioread32(addr) | mask), addr);
-+}
-+
-+static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask)
-+{
-+      void __iomem *addr = rs->base + reg;
-+
-+      iowrite32((ioread32(addr) & ~mask), addr);
-+}
-+
-+static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
-+{
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+      u32 rate;
-+      u32 prescale;
-+
-+      /*
-+       * the supported rates are: 2, 4, 8, ... 128
-+       * round up as we look for equal or less speed
-+       */
-+      rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
-+      rate = roundup_pow_of_two(rate);
-+
-+      /* Convert the rate to SPI clock divisor value. */
-+      prescale = ilog2(rate / 2);
-+
-+      /* some tolerance. double and add 100 */
-+      rs->wait_loops = (8 * HZ * loops_per_jiffy) /
-+              (clk_get_rate(rs->clk) / rate);
-+      rs->wait_loops = (rs->wait_loops << 1) + 100;
-+      rs->speed = speed;
-+
-+      dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
-+                      clk_get_rate(rs->clk) / rate, speed, rate, prescale,
-+                      rs->wait_loops);
-+
-+      return prescale;
-+}
-+
-+static u32 get_arbiter_offset(struct spi_master *master)
-+{
-+      u32 offset;
-+
-+      offset = RAMIPS_SPI_ARBITER;
-+      if (master->bus_num == 1)
-+              offset -= RAMIPS_SPI_DEV_OFFSET;
-+
-+      return offset;
-+}
-+
-+static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
-+{
-+      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+
-+      if (enable)
-+              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
-+      else
-+              rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
-+}
-+
-+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
-+{
-+      int loop = rs->wait_loops * len;
-+
-+      while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
-+              cpu_relax();
-+
-+      if (loop)
-+              return 0;
-+
-+      return -ETIMEDOUT;
-+}
-+
-+static void rt2880_dump_reg(struct spi_master *master)
-+{
-+      struct rt2880_spi *rs = spi_master_get_devdata(master);
-+
-+      dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
-+                      "data: %08x, arb: %08x\n",
-+                      rt2880_spi_read(rs, RAMIPS_SPI_STAT),
-+                      rt2880_spi_read(rs, RAMIPS_SPI_CFG),
-+                      rt2880_spi_read(rs, RAMIPS_SPI_CTL),
-+                      rt2880_spi_read(rs, RAMIPS_SPI_DATA),
-+                      rt2880_spi_read(rs, get_arbiter_offset(master)));
-+}
-+
-+static int rt2880_spi_transfer_one(struct spi_master *master,
-+              struct spi_device *spi, struct spi_transfer *xfer)
-+{
-+      struct rt2880_spi *rs = spi_master_get_devdata(master);
-+      unsigned len;
-+      const u8 *tx = xfer->tx_buf;
-+      u8 *rx = xfer->rx_buf;
-+      int err = 0;
-+
-+      /* change clock speed  */
-+      if (unlikely(rs->speed != xfer->speed_hz)) {
-+              u32 reg;
-+              reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
-+              reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
-+              reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
-+              rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
-+      }
-+
-+      if (tx) {
-+              len = xfer->len;
-+              while (len-- > 0) {
-+                      rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
-+                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
-+                      err = rt2880_spi_wait_ready(rs, 1);
-+                      if (err) {
-+                              dev_err(&spi->dev, "TX failed, err=%d\n", err);
-+                              goto out;
-+                      }
-+              }
-+      }
-+
-+      if (rx) {
-+              len = xfer->len;
-+              while (len-- > 0) {
-+                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
-+                      err = rt2880_spi_wait_ready(rs, 1);
-+                      if (err) {
-+                              dev_err(&spi->dev, "RX failed, err=%d\n", err);
-+                              goto out;
-+                      }
-+                      *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
-+              }
-+      }
-+
-+out:
-+      return err;
-+}
-+
-+/* copy from spi.c */
-+static void spi_set_cs(struct spi_device *spi, bool enable)
-+{
-+      if (spi->mode & SPI_CS_HIGH)
-+              enable = !enable;
-+
-+      if (spi->cs_gpio >= 0)
-+              gpio_set_value(spi->cs_gpio, !enable);
-+      else if (spi->master->set_cs)
-+              spi->master->set_cs(spi, !enable);
-+}
-+
-+static int rt2880_spi_setup(struct spi_device *spi)
-+{
-+      struct spi_master *master = spi->master;
-+      struct rt2880_spi *rs = spi_master_get_devdata(master);
-+      u32 reg, old_reg, arbit_off;
-+
-+      if ((spi->max_speed_hz > master->max_speed_hz) ||
-+                      (spi->max_speed_hz < master->min_speed_hz)) {
-+              dev_err(&spi->dev, "invalide requested speed %d Hz\n",
-+                              spi->max_speed_hz);
-+              return -EINVAL;
-+      }
-+
-+      if (!(master->bits_per_word_mask &
-+                              BIT(spi->bits_per_word - 1))) {
-+              dev_err(&spi->dev, "invalide bits_per_word %d\n",
-+                              spi->bits_per_word);
-+              return -EINVAL;
-+      }
-+
-+      /* the hardware seems can't work on mode0 force it to mode3 */
-+      if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
-+              dev_warn(&spi->dev, "force spi mode3\n");
-+              spi->mode |= SPI_MODE_3;
-+      }
-+
-+      /* chip polarity */
-+      arbit_off = get_arbiter_offset(master);
-+      reg = old_reg = rt2880_spi_read(rs, arbit_off);
-+      if (spi->mode & SPI_CS_HIGH) {
-+              switch (master->bus_num) {
-+              case 1:
-+                      reg |= SPI1_POR;
-+                      break;
-+              default:
-+                      reg |= SPI0_POR;
-+                      break;
-+              }
-+      } else {
-+              switch (master->bus_num) {
-+              case 1:
-+                      reg &= ~SPI1_POR;
-+                      break;
-+              default:
-+                      reg &= ~SPI0_POR;
-+                      break;
-+              }
-+      }
-+
-+      /* enable spi1 */
-+      if (master->bus_num == 1)
-+              reg |= SPICTL_ARB_EN;
-+
-+      if (reg != old_reg)
-+              rt2880_spi_write(rs, arbit_off, reg);
-+
-+      /* deselected the spi device */
-+      spi_set_cs(spi, false);
-+
-+      rt2880_dump_reg(master);
-+
-+      return 0;
-+}
-+
-+static int rt2880_spi_prepare_message(struct spi_master *master,
-+              struct spi_message *msg)
-+{
-+      struct rt2880_spi *rs = spi_master_get_devdata(master);
-+      struct spi_device *spi = msg->spi;
-+      u32 reg;
-+
-+      if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
-+              return 0;
-+
-+#if 0
-+      /* set spido to tri-state */
-+      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
-+#endif
-+
-+      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
-+
-+      reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
-+                      SPICFG_RXCLKEDGE_FALLING |
-+                      SPICFG_TXCLKEDGE_FALLING |
-+                      SPICFG_SPICLK_PRESCALE_MASK);
-+
-+      /* MSB */
-+      if (!(spi->mode & SPI_LSB_FIRST))
-+              reg |= SPICFG_MSBFIRST;
-+
-+      /* spi mode */
-+      switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
-+      case SPI_MODE_0:
-+              reg |= SPICFG_TXCLKEDGE_FALLING;
-+              break;
-+      case SPI_MODE_1:
-+              reg |= SPICFG_RXCLKEDGE_FALLING;
-+              break;
-+      case SPI_MODE_2:
-+              reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
-+              break;
-+      case SPI_MODE_3:
-+              reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
-+              break;
-+      }
-+      rs->mode = spi->mode;
-+
-+#if 0
-+      /* set spiclk and spiena to tri-state */
-+      reg |= SPICFG_HIZSPI;
-+#endif
-+
-+      /* clock divide */
-+      reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
-+
-+      rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
-+
-+      return 0;
-+}
-+
-+static int rt2880_spi_probe(struct platform_device *pdev)
-+{
-+      struct spi_master *master;
-+      struct rt2880_spi *rs;
-+      void __iomem *base;
-+      struct resource *r;
-+      struct clk *clk;
-+      int ret;
-+
-+      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\n");
-+              return PTR_ERR(clk);
-+      }
-+
-+      ret = clk_prepare_enable(clk);
-+      if (ret)
-+              goto err_clk;
-+
-+      master = spi_alloc_master(&pdev->dev, sizeof(*rs));
-+      if (master == NULL) {
-+              dev_dbg(&pdev->dev, "master allocation failed\n");
-+              ret = -ENOMEM;
-+              goto err_clk;
-+      }
-+
-+      master->dev.of_node = pdev->dev.of_node;
-+      master->mode_bits = RT2880_SPI_MODE_BITS;
-+      master->bits_per_word_mask = SPI_BPW_MASK(8);
-+      master->min_speed_hz = clk_get_rate(clk) / 128;
-+      master->max_speed_hz = clk_get_rate(clk) / 2;
-+      master->flags = SPI_MASTER_HALF_DUPLEX;
-+      master->setup = rt2880_spi_setup;
-+      master->prepare_message = rt2880_spi_prepare_message;
-+      master->set_cs = rt2880_spi_set_cs;
-+      master->transfer_one = rt2880_spi_transfer_one,
-+
-+      dev_set_drvdata(&pdev->dev, master);
-+
-+      rs = spi_master_get_devdata(master);
-+      rs->master = master;
-+      rs->base = base;
-+      rs->clk = clk;
-+
-+      if (atomic_inc_return(&hw_reset_count) == 1)
-+              device_reset(&pdev->dev);
-+
-+      ret = devm_spi_register_master(&pdev->dev, master);
-+      if (ret < 0) {
-+              dev_err(&pdev->dev, "devm_spi_register_master error.\n");
-+              goto err_master;
-+      }
-+
-+      return ret;
-+
-+err_master:
-+      spi_master_put(master);
-+      kfree(master);
-+err_clk:
-+      clk_disable_unprepare(clk);
-+
-+      return ret;
-+}
-+
-+static int rt2880_spi_remove(struct platform_device *pdev)
-+{
-+      struct spi_master *master;
-+      struct rt2880_spi *rs;
-+
-+      master = dev_get_drvdata(&pdev->dev);
-+      rs = spi_master_get_devdata(master);
-+
-+      clk_disable_unprepare(rs->clk);
-+      atomic_dec(&hw_reset_count);
-+
-+      return 0;
-+}
-+
-+MODULE_ALIAS("platform:" DRIVER_NAME);
-+
-+static const struct of_device_id rt2880_spi_match[] = {
-+      { .compatible = "ralink,rt2880-spi" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, rt2880_spi_match);
-+
-+static struct platform_driver rt2880_spi_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+              .of_match_table = rt2880_spi_match,
-+      },
-+      .probe = rt2880_spi_probe,
-+      .remove = rt2880_spi_remove,
-+};
-+
-+module_platform_driver(rt2880_spi_driver);
-+
-+MODULE_DESCRIPTION("Ralink SPI driver");
-+MODULE_AUTHOR("Sergiy <piratfm@gmail.com>");
-+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
-+MODULE_LICENSE("GPL");
diff --git a/target/linux/ramips/patches-5.10/0044-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-5.10/0044-i2c-MIPS-adds-ralink-I2C-driver.patch
deleted file mode 100644 (file)
index e3bb7f2..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 27 Jul 2014 09:52:56 +0100
-Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- .../devicetree/bindings/i2c/i2c-ralink.txt         |   27 ++
- drivers/i2c/busses/Kconfig                         |    4 +
- drivers/i2c/busses/Makefile                        |    1 +
- drivers/i2c/busses/i2c-ralink.c                    |  327 ++++++++++++++++++++
- 4 files changed, 359 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
- create mode 100644 drivers/i2c/busses/i2c-ralink.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
-@@ -0,0 +1,27 @@
-+I2C for Ralink platforms
-+
-+Required properties :
-+- compatible : Must be "link,rt3052-i2c"
-+- reg: physical base address of the controller and length of memory mapped
-+     region.
-+- #address-cells = <1>;
-+- #size-cells = <0>;
-+
-+Optional properties:
-+- Child nodes conforming to i2c bus binding
-+
-+Example :
-+
-+palmbus@10000000 {
-+      i2c@900 {
-+              compatible = "link,rt3052-i2c";
-+              reg = <0x900 0x100>;
-+              #address-cells = <1>;
-+              #size-cells = <0>;
-+
-+              hwmon@4b {
-+                      compatible = "national,lm92";
-+                      reg = <0x4b>;
-+              };
-+      };
-+};
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -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.
-+config I2C_RALINK
-+      tristate "Ralink I2C Controller"
-+      depends on RALINK && !SOC_MT7621
-+      select OF_I2C
-+
- config HAVE_S3C2410_I2C
-       bool
-       help
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -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
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-ralink.c
-@@ -0,0 +1,435 @@
-+/*
-+ * drivers/i2c/busses/i2c-ralink.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_CONFIG_REG                0x00
-+#define REG_CLKDIV_REG                0x04
-+#define REG_DEVADDR_REG               0x08
-+#define REG_ADDR_REG          0x0C
-+#define REG_DATAOUT_REG               0x10
-+#define REG_DATAIN_REG                0x14
-+#define REG_STATUS_REG                0x18
-+#define REG_STARTXFR_REG      0x1C
-+#define REG_BYTECNT_REG               0x20
-+
-+/* REG_CONFIG_REG */
-+#define I2C_ADDRLEN_OFFSET    5
-+#define I2C_DEVADLEN_OFFSET   2
-+#define I2C_ADDRLEN_MASK      0x3
-+#define I2C_ADDR_DIS          BIT(1)
-+#define I2C_DEVADDR_DIS               BIT(0)
-+#define I2C_ADDRLEN_8         (7 << I2C_ADDRLEN_OFFSET)
-+#define I2C_DEVADLEN_7                (6 << I2C_DEVADLEN_OFFSET)
-+#define I2C_CONF_DEFAULT      (I2C_ADDRLEN_8 | I2C_DEVADLEN_7)
-+
-+/* REG_CLKDIV_REG */
-+#define I2C_CLKDIV_MASK               0xffff
-+
-+/* REG_DEVADDR_REG */
-+#define I2C_DEVADDR_MASK      0x7f
-+
-+/* REG_ADDR_REG */
-+#define I2C_ADDR_MASK         0xff
-+
-+/* REG_STATUS_REG */
-+#define I2C_STARTERR          BIT(4)
-+#define I2C_ACKERR            BIT(3)
-+#define I2C_DATARDY           BIT(2)
-+#define I2C_SDOEMPTY          BIT(1)
-+#define I2C_BUSY              BIT(0)
-+
-+/* REG_STARTXFR_REG */
-+#define NOSTOP_CMD            BIT(2)
-+#define NODATA_CMD            BIT(1)
-+#define READ_CMD              BIT(0)
-+
-+/* REG_BYTECNT_REG */
-+#define BYTECNT_MAX           64
-+#define SET_BYTECNT(x)                (x - 1)
-+
-+/* timeout waiting for I2C devices to respond (clock streching) */
-+#define TIMEOUT_MS              1000
-+#define DELAY_INTERVAL_US       100
-+
-+struct rt_i2c {
-+      void __iomem *base;
-+      struct clk *clk;
-+      struct device *dev;
-+      struct i2c_adapter adap;
-+      u32 cur_clk;
-+      u32 clk_div;
-+      u32 flags;
-+};
-+
-+static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg)
-+{
-+      iowrite32(val, i2c->base + reg);
-+}
-+
-+static u32 rt_i2c_r32(struct rt_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 rt_i2c_wait_idle(struct rt_i2c *i2c)
-+{
-+      int ret;
-+
-+      ret = poll_down_timeout(i2c->base + REG_STATUS_REG, 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);
-+
-+              /* check error status */
-+              if (status & I2C_STARTERR)
-+                      return -EAGAIN;
-+              else if (status & I2C_ACKERR)
-+                      return -ENXIO;
-+              else if (status & mask)
-+                      return 0;
-+
-+              usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
-+      } while (time_before(jiffies, timeout));
-+
-+      return -ETIMEDOUT;
-+}
-+
-+static int rt_i2c_wait_rx_done(struct rt_i2c *i2c)
-+{
-+      int ret;
-+
-+      ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY);
-+      if (ret < 0)
-+              dev_dbg(i2c->dev, "rx err(%d)\n", ret);
-+
-+      return ret;
-+}
-+
-+static int rt_i2c_wait_tx_done(struct rt_i2c *i2c)
-+{
-+      int ret;
-+
-+      ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY);
-+      if (ret < 0)
-+              dev_dbg(i2c->dev, "tx err(%d)\n", ret);
-+
-+      return ret;
-+}
-+
-+static void rt_i2c_reset(struct rt_i2c *i2c)
-+{
-+      device_reset(i2c->adap.dev.parent);
-+      barrier();
-+      rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG);
-+}
-+
-+static void rt_i2c_dump_reg(struct rt_i2c *i2c)
-+{
-+      dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \
-+                      "addr %08x, dataout %08x, datain %08x, " \
-+                      "status %08x, startxfr %08x, bytecnt %08x\n",
-+                      rt_i2c_r32(i2c, REG_CONFIG_REG),
-+                      rt_i2c_r32(i2c, REG_CLKDIV_REG),
-+                      rt_i2c_r32(i2c, REG_DEVADDR_REG),
-+                      rt_i2c_r32(i2c, REG_ADDR_REG),
-+                      rt_i2c_r32(i2c, REG_DATAOUT_REG),
-+                      rt_i2c_r32(i2c, REG_DATAIN_REG),
-+                      rt_i2c_r32(i2c, REG_STATUS_REG),
-+                      rt_i2c_r32(i2c, REG_STARTXFR_REG),
-+                      rt_i2c_r32(i2c, REG_BYTECNT_REG));
-+}
-+
-+static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
-+              int num)
-+{
-+      struct rt_i2c *i2c;
-+      struct i2c_msg *pmsg;
-+      unsigned char addr;
-+      int i, j, ret;
-+      u32 cmd;
-+
-+      i2c = i2c_get_adapdata(adap);
-+
-+      for (i = 0; i < num; i++) {
-+              pmsg = &msgs[i];
-+              if (i == (num - 1))
-+                      cmd = 0;
-+              else
-+                      cmd = NOSTOP_CMD;
-+
-+              dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n",
-+                              pmsg->addr, pmsg->len, pmsg->flags,
-+                              (cmd == 0)? 1 : 0);
-+
-+              /* wait hardware idle */
-+              if ((ret = rt_i2c_wait_idle(i2c)))
-+                      goto err_timeout;
-+
-+              if (pmsg->flags & I2C_M_TEN) {
-+                      rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG);
-+                      /* 10 bits address */
-+                      addr = 0x78 | ((pmsg->addr >> 8) & 0x03);
-+                      rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK,
-+                                      REG_DEVADDR_REG);
-+                      rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK,
-+                                      REG_ADDR_REG);
-+              } else {
-+                      rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS,
-+                                      REG_CONFIG_REG);
-+                      /* 7 bits address */
-+                      rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
-+                                      REG_DEVADDR_REG);
-+              }
-+
-+              /* buffer length */
-+              if (pmsg->len == 0)
-+                      cmd |= NODATA_CMD;
-+              else
-+                      rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
-+                                      REG_BYTECNT_REG);
-+
-+              j = 0;
-+              if (pmsg->flags & I2C_M_RD) {
-+                      cmd |= READ_CMD;
-+                      /* start transfer */
-+                      barrier();
-+                      rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
-+                      do {
-+                              /* wait */
-+                              if ((ret = rt_i2c_wait_rx_done(i2c)))
-+                                      goto err_timeout;
-+                              /* read data */
-+                              if (pmsg->len)
-+                                      pmsg->buf[j] = rt_i2c_r32(i2c,
-+                                                      REG_DATAIN_REG);
-+                              j++;
-+                      } while (j < pmsg->len);
-+              } else {
-+                      do {
-+                              /* write data */
-+                              if (pmsg->len)
-+                                      rt_i2c_w32(i2c, pmsg->buf[j],
-+                                                      REG_DATAOUT_REG);
-+                              /* start transfer */
-+                              if (j == 0) {
-+                                      barrier();
-+                                      rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
-+                              }
-+                              /* wait */
-+                              if ((ret = rt_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:
-+      rt_i2c_dump_reg(i2c);
-+      rt_i2c_reset(i2c);
-+      return ret;
-+}
-+
-+static u32 rt_i2c_func(struct i2c_adapter *a)
-+{
-+      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-+}
-+
-+static const struct i2c_algorithm rt_i2c_algo = {
-+      .master_xfer    = rt_i2c_master_xfer,
-+      .functionality  = rt_i2c_func,
-+};
-+
-+static const struct of_device_id i2c_rt_dt_ids[] = {
-+      { .compatible = "ralink,rt2880-i2c" },
-+      { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
-+
-+static struct i2c_adapter_quirks rt_i2c_quirks = {
-+        .max_write_len = BYTECNT_MAX,
-+        .max_read_len = BYTECNT_MAX,
-+};
-+
-+static int rt_i2c_init(struct rt_i2c *i2c)
-+{
-+      u32 reg;
-+
-+      /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */
-+      i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) /
-+              (2 * i2c->cur_clk);
-+      if (i2c->clk_div < 8)
-+              i2c->clk_div = 8;
-+      if (i2c->clk_div > I2C_CLKDIV_MASK)
-+              i2c->clk_div = I2C_CLKDIV_MASK;
-+
-+      /* check support combinde/repeated start message */
-+      rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG);
-+      reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD;
-+
-+      rt_i2c_reset(i2c);
-+
-+      return reg;
-+}
-+
-+static int rt_i2c_probe(struct platform_device *pdev)
-+{
-+      struct resource *res;
-+      struct rt_i2c *i2c;
-+      struct i2c_adapter *adap;
-+      const struct of_device_id *match;
-+      int ret, restart;
-+
-+      match = of_match_device(i2c_rt_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 rt_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 = &rt_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 = &rt_i2c_quirks;
-+
-+      platform_set_drvdata(pdev, i2c);
-+
-+      restart = rt_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 %ssupport\n",
-+                      i2c->cur_clk/1000, restart ? "" : "not ");
-+
-+      return ret;
-+}
-+
-+static int rt_i2c_remove(struct platform_device *pdev)
-+{
-+      struct rt_i2c *i2c = platform_get_drvdata(pdev);
-+
-+      i2c_del_adapter(&i2c->adap);
-+      clk_disable_unprepare(i2c->clk);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver rt_i2c_driver = {
-+      .probe          = rt_i2c_probe,
-+      .remove         = rt_i2c_remove,
-+      .driver         = {
-+              .owner  = THIS_MODULE,
-+              .name   = "i2c-ralink",
-+              .of_match_table = i2c_rt_dt_ids,
-+      },
-+};
-+
-+static int __init i2c_rt_init (void)
-+{
-+      return platform_driver_register(&rt_i2c_driver);
-+}
-+subsys_initcall(i2c_rt_init);
-+
-+static void __exit i2c_rt_exit (void)
-+{
-+      platform_driver_unregister(&rt_i2c_driver);
-+}
-+module_exit(i2c_rt_exit);
-+
-+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
-+MODULE_DESCRIPTION("Ralink I2c host driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:Ralink-I2C");
diff --git a/target/linux/ramips/patches-5.10/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch b/target/linux/ramips/patches-5.10/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
deleted file mode 100644 (file)
index f3912a1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-From 23147af14531cbdada194b94120ef8774f46292d Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Thu, 13 Nov 2014 19:08:40 +0100
-Subject: [PATCH 46/53] mmc: MIPS: ralink: add sdhci for mt7620a SoC
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/mmc/host/Kconfig             |    2 +
- drivers/mmc/host/Makefile            |    1 +
- drivers/mmc/host/mtk-mmc/Kconfig     |   16 +
- drivers/mmc/host/mtk-mmc/Makefile    |   42 +
- drivers/mmc/host/mtk-mmc/board.h     |  137 ++
- drivers/mmc/host/mtk-mmc/dbg.c       |  347 ++++
- drivers/mmc/host/mtk-mmc/dbg.h       |  156 ++
- drivers/mmc/host/mtk-mmc/mt6575_sd.h | 1001 +++++++++++
- drivers/mmc/host/mtk-mmc/sd.c        | 3060 ++++++++++++++++++++++++++++++++++
- 9 files changed, 4762 insertions(+)
- create mode 100644 drivers/mmc/host/mtk-mmc/Kconfig
- create mode 100644 drivers/mmc/host/mtk-mmc/Makefile
- create mode 100644 drivers/mmc/host/mtk-mmc/board.h
- create mode 100644 drivers/mmc/host/mtk-mmc/dbg.c
- create mode 100644 drivers/mmc/host/mtk-mmc/dbg.h
- create mode 100644 drivers/mmc/host/mtk-mmc/mt6575_sd.h
- create mode 100644 drivers/mmc/host/mtk-mmc/sd.c
-
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -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"
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -3,6 +3,7 @@
- # Makefile for MMC/SD host controller drivers
- #
-+obj-$(CONFIG_MTK_MMC)                 += mtk-mmc/
- obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
- armmmci-y := mmci.o
- armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
diff --git a/target/linux/ramips/patches-5.10/0048-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-5.10/0048-asoc-add-mt7620-support.patch
deleted file mode 100644 (file)
index d0d4141..0000000
+++ /dev/null
@@ -1,1046 +0,0 @@
-From 7f29222b1731e8182ba94a331531dec18865a1e4 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Sun, 27 Jul 2014 09:31:47 +0100
-Subject: [PATCH 48/53] asoc: add mt7620 support
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- arch/mips/ralink/of.c            |    2 +
- sound/soc/Kconfig                |    1 +
- sound/soc/Makefile               |    1 +
- sound/soc/ralink/Kconfig         |   15 ++
- sound/soc/ralink/Makefile        |   11 +
- sound/soc/ralink/mt7620-i2s.c    |  436 ++++++++++++++++++++++++++++++++++++++
- sound/soc/ralink/mt7620-wm8960.c |  233 ++++++++++++++++++++
- 7 files changed, 699 insertions(+)
- create mode 100644 sound/soc/ralink/Kconfig
- create mode 100644 sound/soc/ralink/Makefile
- create mode 100644 sound/soc/ralink/mt7620-i2s.c
- create mode 100644 sound/soc/ralink/mt7620-wm8960.c
-
---- a/arch/mips/ralink/of.c
-+++ b/arch/mips/ralink/of.c
-@@ -13,6 +13,7 @@
- #include <linux/of_fdt.h>
- #include <linux/kernel.h>
- #include <linux/memblock.h>
-+#include <linux/module.h>
- #include <linux/of_platform.h>
- #include <linux/of_address.h>
-@@ -24,6 +25,7 @@
- #include "common.h"
- __iomem void *rt_sysc_membase;
-+EXPORT_SYMBOL(rt_sysc_membase);
- __iomem void *rt_memc_membase;
- __iomem void *plat_of_remap_node(const char *node)
---- a/sound/soc/Kconfig
-+++ b/sound/soc/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"
-+source "sound/soc/ralink/Kconfig"
- source "sound/soc/samsung/Kconfig"
- source "sound/soc/sh/Kconfig"
- source "sound/soc/sirf/Kconfig"
---- a/sound/soc/Makefile
-+++ b/sound/soc/Makefile
-@@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC)        += kirkwood/
- obj-$(CONFIG_SND_SOC) += pxa/
- obj-$(CONFIG_SND_SOC) += qcom/
- obj-$(CONFIG_SND_SOC) += rockchip/
-+obj-$(CONFIG_SND_SOC) += ralink/
- obj-$(CONFIG_SND_SOC) += samsung/
- obj-$(CONFIG_SND_SOC) += sh/
- obj-$(CONFIG_SND_SOC) += sirf/
---- /dev/null
-+++ b/sound/soc/ralink/Kconfig
-@@ -0,0 +1,8 @@
-+config SND_RALINK_SOC_I2S
-+      depends on RALINK && SND_SOC && !SOC_RT288X
-+      select SND_SOC_GENERIC_DMAENGINE_PCM
-+      select REGMAP_MMIO
-+      tristate "SoC Audio (I2S protocol) for Ralink SoC"
-+      help
-+        Say Y if you want to use I2S protocol and I2S codec on Ralink/MediaTek
-+        based boards.
---- /dev/null
-+++ b/sound/soc/ralink/Makefile
-@@ -0,0 +1,6 @@
-+#
-+# Ralink/MediaTek Platform Support
-+#
-+snd-soc-ralink-i2s-objs := ralink-i2s.o
-+
-+obj-$(CONFIG_SND_RALINK_SOC_I2S) += snd-soc-ralink-i2s.o
---- /dev/null
-+++ b/sound/soc/ralink/ralink-i2s.c
-@@ -0,0 +1,965 @@
-+/*
-+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
-+ *  Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
-+ *
-+ *  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.
-+ *
-+ *  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.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/clk.h>
-+#include <linux/regmap.h>
-+#include <linux/reset.h>
-+#include <linux/debugfs.h>
-+#include <linux/of_device.h>
-+#include <sound/pcm_params.h>
-+#include <sound/dmaengine_pcm.h>
-+
-+#include <asm/mach-ralink/ralink_regs.h>
-+
-+#define DRV_NAME "ralink-i2s"
-+
-+#define I2S_REG_CFG0          0x00
-+#define I2S_REG_INT_STATUS    0x04
-+#define I2S_REG_INT_EN                0x08
-+#define I2S_REG_FF_STATUS     0x0c
-+#define I2S_REG_WREG          0x10
-+#define I2S_REG_RREG          0x14
-+#define I2S_REG_CFG1          0x18
-+#define I2S_REG_DIVCMP                0x20
-+#define I2S_REG_DIVINT                0x24
-+
-+/* I2S_REG_CFG0 */
-+#define I2S_REG_CFG0_EN               BIT(31)
-+#define I2S_REG_CFG0_DMA_EN   BIT(30)
-+#define I2S_REG_CFG0_BYTE_SWAP        BIT(28)
-+#define I2S_REG_CFG0_TX_EN    BIT(24)
-+#define I2S_REG_CFG0_RX_EN    BIT(20)
-+#define I2S_REG_CFG0_SLAVE    BIT(16)
-+#define I2S_REG_CFG0_RX_THRES 12
-+#define I2S_REG_CFG0_TX_THRES 4
-+#define I2S_REG_CFG0_THRES_MASK       (0xf << I2S_REG_CFG0_RX_THRES) | \
-+      (4 << I2S_REG_CFG0_TX_THRES)
-+#define I2S_REG_CFG0_DFT_THRES        (4 << I2S_REG_CFG0_RX_THRES) | \
-+      (4 << I2S_REG_CFG0_TX_THRES)
-+/* RT305x */
-+#define I2S_REG_CFG0_CLK_DIS  BIT(8)
-+#define I2S_REG_CFG0_TXCH_SWAP        BIT(3)
-+#define I2S_REG_CFG0_TXCH1_OFF        BIT(2)
-+#define I2S_REG_CFG0_TXCH0_OFF        BIT(1)
-+#define I2S_REG_CFG0_SLAVE_EN BIT(0)
-+/* RT3883 */
-+#define I2S_REG_CFG0_RXCH_SWAP        BIT(11)
-+#define I2S_REG_CFG0_RXCH1_OFF        BIT(10)
-+#define I2S_REG_CFG0_RXCH0_OFF        BIT(9)
-+#define I2S_REG_CFG0_WS_INV   BIT(0)
-+/* MT7628 */
-+#define I2S_REG_CFG0_FMT_LE   BIT(29)
-+#define I2S_REG_CFG0_SYS_BE   BIT(28)
-+#define I2S_REG_CFG0_NORM_24  BIT(18)
-+#define I2S_REG_CFG0_DATA_24  BIT(17)
-+
-+/* I2S_REG_INT_STATUS */
-+#define I2S_REG_INT_RX_FAULT  BIT(7)
-+#define I2S_REG_INT_RX_OVRUN  BIT(6)
-+#define I2S_REG_INT_RX_UNRUN  BIT(5)
-+#define I2S_REG_INT_RX_THRES  BIT(4)
-+#define I2S_REG_INT_TX_FAULT  BIT(3)
-+#define I2S_REG_INT_TX_OVRUN  BIT(2)
-+#define I2S_REG_INT_TX_UNRUN  BIT(1)
-+#define I2S_REG_INT_TX_THRES  BIT(0)
-+#define I2S_REG_INT_TX_MASK   0xf
-+#define I2S_REG_INT_RX_MASK   0xf0
-+
-+/* I2S_REG_INT_STATUS */
-+#define I2S_RX_AVCNT(x)               ((x >> 4) & 0xf)
-+#define I2S_TX_AVCNT(x)               (x & 0xf)
-+/* MT7628 */
-+#define MT7628_I2S_RX_AVCNT(x)        ((x >> 8) & 0x1f)
-+#define MT7628_I2S_TX_AVCNT(x)        (x & 0x1f)
-+
-+/* I2S_REG_CFG1 */
-+#define I2S_REG_CFG1_LBK      BIT(31)
-+#define I2S_REG_CFG1_EXTLBK   BIT(30)
-+/* RT3883 */
-+#define I2S_REG_CFG1_LEFT_J   BIT(0)
-+#define I2S_REG_CFG1_RIGHT_J  BIT(1)
-+#define I2S_REG_CFG1_FMT_MASK 0x3
-+
-+/* I2S_REG_DIVCMP */
-+#define I2S_REG_DIVCMP_CLKEN  BIT(31)
-+#define I2S_REG_DIVCMP_DIVCOMP_MASK   0x1ff
-+
-+/* I2S_REG_DIVINT */
-+#define I2S_REG_DIVINT_MASK   0x3ff
-+
-+/* BCLK dividers */
-+#define RALINK_I2S_DIVCMP     0
-+#define RALINK_I2S_DIVINT     1
-+
-+/* FIFO */
-+#define RALINK_I2S_FIFO_SIZE  32
-+
-+/* feature flags */
-+#define RALINK_FLAGS_TXONLY   BIT(0)
-+#define RALINK_FLAGS_LEFT_J   BIT(1)
-+#define RALINK_FLAGS_RIGHT_J  BIT(2)
-+#define RALINK_FLAGS_ENDIAN   BIT(3)
-+#define RALINK_FLAGS_24BIT    BIT(4)
-+
-+#define RALINK_I2S_INT_EN     0
-+
-+struct ralink_i2s_stats {
-+      u32 dmafault;
-+      u32 overrun;
-+      u32 underrun;
-+      u32 belowthres;
-+};
-+
-+struct ralink_i2s {
-+      struct device *dev;
-+      void __iomem *regs;
-+      struct clk *clk;
-+      struct regmap *regmap;
-+      u32 flags;
-+      unsigned int fmt;
-+      u16 txdma_req;
-+      u16 rxdma_req;
-+
-+      struct snd_dmaengine_dai_dma_data playback_dma_data;
-+      struct snd_dmaengine_dai_dma_data capture_dma_data;
-+
-+      struct dentry *dbg_dir;
-+        struct dentry *dbg_stats;
-+      struct ralink_i2s_stats txstats;
-+      struct ralink_i2s_stats rxstats;
-+};
-+
-+static void ralink_i2s_dump_regs(struct ralink_i2s *i2s)
-+{
-+      u32 buf[10];
-+      int ret;
-+
-+      ret = regmap_bulk_read(i2s->regmap, I2S_REG_CFG0,
-+                      buf, ARRAY_SIZE(buf));
-+
-+      dev_dbg(i2s->dev, "CFG0: %08x, INTSTAT: %08x, INTEN: %08x, " \
-+                      "FFSTAT: %08x, WREG: %08x, RREG: %08x, " \
-+                      "CFG1: %08x, DIVCMP: %08x, DIVINT: %08x\n",
-+                      buf[0], buf[1], buf[2], buf[3], buf[4],
-+                      buf[5], buf[6], buf[8], buf[9]);
-+}
-+
-+static int ralink_i2s_set_sysclk(struct snd_soc_dai *dai,
-+                              int clk_id, unsigned int freq, int dir)
-+{
-+      return 0;
-+}
-+
-+static int ralink_i2s_set_sys_bclk(struct snd_soc_dai *dai, int width, int rate)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+      unsigned long clk = clk_get_rate(i2s->clk);
-+      int div;
-+      uint32_t data;
-+
-+      /* disable clock at slave mode */
-+      if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
-+                      SND_SOC_DAIFMT_CBM_CFM) {
-+              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                              I2S_REG_CFG0_CLK_DIS,
-+                              I2S_REG_CFG0_CLK_DIS);
-+              return 0;
-+      }
-+
-+      /* FREQOUT = FREQIN / (I2S_CLK_DIV + 1) */
-+      div = (clk / rate ) - 1;
-+
-+      data = rt_sysc_r32(0x30);
-+      data &= (0xff << 8);
-+      data |= (0x1 << 15) | (div << 8);
-+      rt_sysc_w32(data, 0x30);
-+
-+      /* enable clock */
-+      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_CLK_DIS, 0);
-+
-+      dev_dbg(i2s->dev, "clk: %lu, rate: %u, div: %d\n",
-+                      clk, rate, div);
-+
-+      return 0;
-+}
-+
-+static int ralink_i2s_set_bclk(struct snd_soc_dai *dai, int width, int rate)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+      unsigned long clk = clk_get_rate(i2s->clk);
-+      int divint, divcomp;
-+
-+      /* disable clock at slave mode */
-+      if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
-+                      SND_SOC_DAIFMT_CBM_CFM) {
-+              regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
-+                              I2S_REG_DIVCMP_CLKEN, 0);
-+              return 0;
-+      }
-+
-+      /* FREQOUT = FREQIN * (1/2) * (1/(DIVINT + DIVCOMP/512)) */
-+      clk = clk / (2 * 2 * width);
-+      divint = clk / rate;
-+      divcomp = ((clk % rate) * 512) / rate;
-+
-+      if ((divint > I2S_REG_DIVINT_MASK) ||
-+                      (divcomp > I2S_REG_DIVCMP_DIVCOMP_MASK))
-+              return -EINVAL;
-+
-+      regmap_update_bits(i2s->regmap, I2S_REG_DIVINT,
-+                      I2S_REG_DIVINT_MASK, divint);
-+      regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
-+                      I2S_REG_DIVCMP_DIVCOMP_MASK, divcomp);
-+
-+      /* enable clock */
-+      regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, I2S_REG_DIVCMP_CLKEN,
-+                      I2S_REG_DIVCMP_CLKEN);
-+
-+      dev_dbg(i2s->dev, "clk: %lu, rate: %u, int: %d, comp: %d\n",
-+                      clk_get_rate(i2s->clk), rate, divint, divcomp);
-+
-+      return 0;
-+}
-+
-+static int ralink_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+      unsigned int cfg0 = 0, cfg1 = 0;
-+
-+      /* set master/slave audio interface */
-+      switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-+      case SND_SOC_DAIFMT_CBM_CFM:
-+              if (i2s->flags & RALINK_FLAGS_TXONLY)
-+                      cfg0 |= I2S_REG_CFG0_SLAVE_EN;
-+              else
-+                      cfg0 |= I2S_REG_CFG0_SLAVE;
-+              break;
-+      case SND_SOC_DAIFMT_CBS_CFS:
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      /* interface format */
-+      switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-+      case SND_SOC_DAIFMT_I2S:
-+              break;
-+      case SND_SOC_DAIFMT_RIGHT_J:
-+              if (i2s->flags & RALINK_FLAGS_RIGHT_J) {
-+                      cfg1 |= I2S_REG_CFG1_RIGHT_J;
-+                      break;
-+              }
-+              return -EINVAL;
-+      case SND_SOC_DAIFMT_LEFT_J:
-+              if (i2s->flags & RALINK_FLAGS_LEFT_J) {
-+                      cfg1 |= I2S_REG_CFG1_LEFT_J;
-+                      break;
-+              }
-+              return -EINVAL;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      /* clock inversion */
-+      switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-+      case SND_SOC_DAIFMT_NB_NF:
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      if (i2s->flags & RALINK_FLAGS_TXONLY) {
-+              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                              I2S_REG_CFG0_SLAVE_EN, cfg0);
-+      } else {
-+              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                              I2S_REG_CFG0_SLAVE, cfg0);
-+      }
-+      regmap_update_bits(i2s->regmap, I2S_REG_CFG1,
-+                      I2S_REG_CFG1_FMT_MASK, cfg1);
-+      i2s->fmt = fmt;
-+
-+      return 0;
-+}
-+
-+static int ralink_i2s_startup(struct snd_pcm_substream *substream,
-+              struct snd_soc_dai *dai)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+
-+      if (dai->active)
-+              return 0;
-+
-+      /* setup status interrupt */
-+#if (RALINK_I2S_INT_EN)
-+      regmap_write(i2s->regmap, I2S_REG_INT_EN, 0xff);
-+#else
-+      regmap_write(i2s->regmap, I2S_REG_INT_EN, 0x0);
-+#endif
-+
-+      /* enable */
-+      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                      I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
-+                      I2S_REG_CFG0_THRES_MASK,
-+                      I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
-+                      I2S_REG_CFG0_DFT_THRES);
-+
-+      return 0;
-+}
-+
-+static void ralink_i2s_shutdown(struct snd_pcm_substream *substream,
-+              struct snd_soc_dai *dai)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+
-+      /* If both streams are stopped, disable module and clock */
-+      if (dai->active)
-+              return;
-+
-+      /*
-+       * datasheet mention when disable all control regs are cleared
-+       * to initial values. need reinit at startup.
-+       */
-+      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_EN, 0);
-+}
-+
-+static int ralink_i2s_hw_params(struct snd_pcm_substream *substream,
-+              struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+      int width;
-+      int ret;
-+
-+      width = params_width(params);
-+      switch (width) {
-+      case 16:
-+              if (i2s->flags & RALINK_FLAGS_24BIT)
-+                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                                      I2S_REG_CFG0_DATA_24, 0);
-+              break;
-+      case 24:
-+              if (i2s->flags & RALINK_FLAGS_24BIT) {
-+                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                                      I2S_REG_CFG0_DATA_24,
-+                                      I2S_REG_CFG0_DATA_24);
-+                      break;
-+              }
-+              return -EINVAL;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      switch (params_channels(params)) {
-+      case 2:
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      if (i2s->flags & RALINK_FLAGS_ENDIAN) {
-+              /* system endian */
-+#ifdef SNDRV_LITTLE_ENDIAN
-+              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                              I2S_REG_CFG0_SYS_BE, 0);
-+#else
-+              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                              I2S_REG_CFG0_SYS_BE,
-+                              I2S_REG_CFG0_SYS_BE);
-+#endif
-+
-+              /* data endian */
-+              switch (params_format(params)) {
-+              case SNDRV_PCM_FORMAT_S16_LE:
-+              case SNDRV_PCM_FORMAT_S24_LE:
-+                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                                      I2S_REG_CFG0_FMT_LE,
-+                                      I2S_REG_CFG0_FMT_LE);
-+                      break;
-+              case SNDRV_PCM_FORMAT_S16_BE:
-+              case SNDRV_PCM_FORMAT_S24_BE:
-+                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
-+                                      I2S_REG_CFG0_FMT_LE, 0);
-+                      break;
-+              default:
-+                      return -EINVAL;
-+              }
-+      }
-+
-+      /* setup bclk rate */
-+      if (i2s->flags & RALINK_FLAGS_TXONLY)
-+              ret = ralink_i2s_set_sys_bclk(dai, width, params_rate(params));
-+      else
-+              ret = ralink_i2s_set_bclk(dai, width, params_rate(params));
-+
-+      return ret;
-+}
-+
-+static int ralink_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-+              struct snd_soc_dai *dai)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+      unsigned int mask, val;
-+
-+      if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-+              mask = I2S_REG_CFG0_TX_EN;
-+      else
-+              mask = I2S_REG_CFG0_RX_EN;
-+
-+      switch (cmd) {
-+      case SNDRV_PCM_TRIGGER_START:
-+      case SNDRV_PCM_TRIGGER_RESUME:
-+      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+              val = mask;
-+              break;
-+      case SNDRV_PCM_TRIGGER_STOP:
-+      case SNDRV_PCM_TRIGGER_SUSPEND:
-+      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-+              val = 0;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, mask, val);
-+
-+      return 0;
-+}
-+
-+static void ralink_i2s_init_dma_data(struct ralink_i2s *i2s,
-+              struct resource *res)
-+{
-+      struct snd_dmaengine_dai_dma_data *dma_data;
-+
-+      /* Playback */
-+      dma_data = &i2s->playback_dma_data;
-+      dma_data->addr = res->start + I2S_REG_WREG;
-+      dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+      dma_data->maxburst = 1;
-+      dma_data->slave_id = i2s->txdma_req;
-+
-+      if (i2s->flags & RALINK_FLAGS_TXONLY)
-+              return;
-+
-+      /* Capture */
-+      dma_data = &i2s->capture_dma_data;
-+      dma_data->addr = res->start + I2S_REG_RREG;
-+      dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+      dma_data->maxburst = 1;
-+      dma_data->slave_id = i2s->rxdma_req;
-+}
-+
-+static int ralink_i2s_dai_probe(struct snd_soc_dai *dai)
-+{
-+      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-+
-+      snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
-+                      &i2s->capture_dma_data);
-+
-+      return 0;
-+}
-+
-+static int ralink_i2s_dai_remove(struct snd_soc_dai *dai)
-+{
-+      return 0;
-+}
-+
-+static const struct snd_soc_dai_ops ralink_i2s_dai_ops = {
-+      .set_sysclk = ralink_i2s_set_sysclk,
-+      .set_fmt = ralink_i2s_set_fmt,
-+      .startup = ralink_i2s_startup,
-+      .shutdown = ralink_i2s_shutdown,
-+      .hw_params = ralink_i2s_hw_params,
-+      .trigger = ralink_i2s_trigger,
-+};
-+
-+static struct snd_soc_dai_driver ralink_i2s_dai = {
-+      .name = DRV_NAME,
-+      .probe = ralink_i2s_dai_probe,
-+      .remove = ralink_i2s_dai_remove,
-+      .ops = &ralink_i2s_dai_ops,
-+      .capture = {
-+              .stream_name = "I2S Capture",
-+              .channels_min = 2,
-+              .channels_max = 2,
-+              .rate_min = 5512,
-+              .rate_max = 192000,
-+              .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+              .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+      },
-+      .playback = {
-+              .stream_name = "I2S Playback",
-+              .channels_min = 2,
-+              .channels_max = 2,
-+              .rate_min = 5512,
-+              .rate_max = 192000,
-+              .rates = SNDRV_PCM_RATE_CONTINUOUS,
-+              .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+      },
-+      .symmetric_rates = 1,
-+};
-+
-+static struct snd_pcm_hardware ralink_pcm_hardware = {
-+      .info = SNDRV_PCM_INFO_MMAP |
-+              SNDRV_PCM_INFO_MMAP_VALID |
-+              SNDRV_PCM_INFO_INTERLEAVED |
-+              SNDRV_PCM_INFO_BLOCK_TRANSFER,
-+      .formats = SNDRV_PCM_FMTBIT_S16_LE,
-+      .channels_min           = 2,
-+      .channels_max           = 2,
-+      .period_bytes_min       = PAGE_SIZE,
-+      .period_bytes_max       = PAGE_SIZE * 2,
-+      .periods_min            = 2,
-+      .periods_max            = 128,
-+      .buffer_bytes_max       = 128 * 1024,
-+      .fifo_size              = RALINK_I2S_FIFO_SIZE,
-+};
-+
-+static const struct snd_dmaengine_pcm_config ralink_dmaengine_pcm_config = {
-+      .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
-+      .pcm_hardware = &ralink_pcm_hardware,
-+      .prealloc_buffer_size = 256 * PAGE_SIZE,
-+};
-+
-+static const struct snd_soc_component_driver ralink_i2s_component = {
-+      .name = DRV_NAME,
-+};
-+
-+static bool ralink_i2s_readable_reg(struct device *dev, unsigned int reg)
-+{
-+      return true;
-+}
-+
-+static bool ralink_i2s_volatile_reg(struct device *dev, unsigned int reg)
-+{
-+      switch (reg) {
-+      case I2S_REG_INT_STATUS:
-+      case I2S_REG_FF_STATUS:
-+              return true;
-+      }
-+      return false;
-+}
-+
-+static bool ralink_i2s_writeable_reg(struct device *dev, unsigned int reg)
-+{
-+      switch (reg) {
-+      case I2S_REG_FF_STATUS:
-+      case I2S_REG_RREG:
-+              return false;
-+      }
-+      return true;
-+}
-+
-+static const struct regmap_config ralink_i2s_regmap_config = {
-+      .reg_bits = 32,
-+      .reg_stride = 4,
-+      .val_bits = 32,
-+      .writeable_reg = ralink_i2s_writeable_reg,
-+      .readable_reg = ralink_i2s_readable_reg,
-+      .volatile_reg = ralink_i2s_volatile_reg,
-+      .max_register = I2S_REG_DIVINT,
-+};
-+
-+#if (RALINK_I2S_INT_EN)
-+static irqreturn_t ralink_i2s_irq(int irq, void *devid)
-+{
-+      struct ralink_i2s *i2s = devid;
-+      u32 status;
-+
-+      regmap_read(i2s->regmap, I2S_REG_INT_STATUS, &status);
-+      if (unlikely(!status))
-+              return IRQ_NONE;
-+
-+      /* tx stats */
-+      if (status & I2S_REG_INT_TX_MASK) {
-+              if (status & I2S_REG_INT_TX_THRES)
-+                      i2s->txstats.belowthres++;
-+              if (status & I2S_REG_INT_TX_UNRUN)
-+                      i2s->txstats.underrun++;
-+              if (status & I2S_REG_INT_TX_OVRUN)
-+                      i2s->txstats.overrun++;
-+              if (status & I2S_REG_INT_TX_FAULT)
-+                      i2s->txstats.dmafault++;
-+      }
-+
-+      /* rx stats */
-+      if (status & I2S_REG_INT_RX_MASK) {
-+              if (status & I2S_REG_INT_RX_THRES)
-+                      i2s->rxstats.belowthres++;
-+              if (status & I2S_REG_INT_RX_UNRUN)
-+                      i2s->rxstats.underrun++;
-+              if (status & I2S_REG_INT_RX_OVRUN)
-+                      i2s->rxstats.overrun++;
-+              if (status & I2S_REG_INT_RX_FAULT)
-+                      i2s->rxstats.dmafault++;
-+      }
-+
-+      /* clean status bits */
-+      regmap_write(i2s->regmap, I2S_REG_INT_STATUS, status);
-+
-+      return IRQ_HANDLED;
-+}
-+#endif
-+
-+#if IS_ENABLED(CONFIG_DEBUG_FS)
-+static int ralink_i2s_stats_show(struct seq_file *s, void *unused)
-+{
-+        struct ralink_i2s *i2s = s->private;
-+
-+      seq_printf(s, "tx stats\n");
-+      seq_printf(s, "\tbelow threshold\t%u\n", i2s->txstats.belowthres);
-+      seq_printf(s, "\tunder run\t%u\n", i2s->txstats.underrun);
-+      seq_printf(s, "\tover run\t%u\n", i2s->txstats.overrun);
-+      seq_printf(s, "\tdma fault\t%u\n", i2s->txstats.dmafault);
-+
-+      seq_printf(s, "rx stats\n");
-+      seq_printf(s, "\tbelow threshold\t%u\n", i2s->rxstats.belowthres);
-+      seq_printf(s, "\tunder run\t%u\n", i2s->rxstats.underrun);
-+      seq_printf(s, "\tover run\t%u\n", i2s->rxstats.overrun);
-+      seq_printf(s, "\tdma fault\t%u\n", i2s->rxstats.dmafault);
-+
-+      ralink_i2s_dump_regs(i2s);
-+
-+      return 0;
-+}
-+
-+static int ralink_i2s_stats_open(struct inode *inode, struct file *file)
-+{
-+        return single_open(file, ralink_i2s_stats_show, inode->i_private);
-+}
-+
-+static const struct file_operations ralink_i2s_stats_ops = {
-+        .open = ralink_i2s_stats_open,
-+        .read = seq_read,
-+        .llseek = seq_lseek,
-+        .release = single_release,
-+};
-+
-+static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
-+{
-+        i2s->dbg_dir = debugfs_create_dir(dev_name(i2s->dev), NULL);
-+        if (!i2s->dbg_dir)
-+                return -ENOMEM;
-+
-+        i2s->dbg_stats = debugfs_create_file("stats", S_IRUGO,
-+                        i2s->dbg_dir, i2s, &ralink_i2s_stats_ops);
-+        if (!i2s->dbg_stats) {
-+                debugfs_remove(i2s->dbg_dir);
-+                return -ENOMEM;
-+        }
-+
-+        return 0;
-+}
-+
-+static inline void ralink_i2s_debugfs_remove(struct ralink_i2s *i2s)
-+{
-+      debugfs_remove(i2s->dbg_stats);
-+      debugfs_remove(i2s->dbg_dir);
-+}
-+#else
-+static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
-+{
-+      return 0;
-+}
-+
-+static inline void ralink_i2s_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg)
-+{
-+}
-+#endif
-+
-+/*
-+ * TODO: these refclk setup functions should use
-+ * clock framework instead. hardcode it now.
-+ */
-+static void rt3350_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data |= (0x1 << 8);
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+static void rt3883_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data &= ~(0x3 << 13);
-+      data |= (0x1 << 13);
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+static void rt3552_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data &= ~(0xf << 8);
-+      data |= (0x3 << 8);
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+static void mt7620_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data &= ~(0x7 << 9);
-+      data |= 0x1 << 9;
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+static void mt7621_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data &= ~(0x1f << 18);
-+      data |= (0x19 << 18);
-+      data &= ~(0x1f << 12);
-+      data |= (0x1 << 12);
-+      data &= ~(0x7 << 9);
-+      data |= (0x5 << 9);
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+static void mt7628_refclk_setup(void)
-+{
-+      uint32_t data;
-+
-+      /* set i2s and refclk digital pad */
-+      data = rt_sysc_r32(0x3c);
-+      data |= 0x1f;
-+      rt_sysc_w32(data, 0x3c);
-+
-+      /* Adjust REFCLK0's driving strength */
-+      data = rt_sysc_r32(0x1354);
-+      data &= ~(0x1 << 5);
-+      rt_sysc_w32(data, 0x1354);
-+      data = rt_sysc_r32(0x1364);
-+      data |= ~(0x1 << 5);
-+      rt_sysc_w32(data, 0x1364);
-+
-+      /* set refclk output 12Mhz clock */
-+      data = rt_sysc_r32(0x2c);
-+      data &= ~(0x7 << 9);
-+      data |= 0x1 << 9;
-+      rt_sysc_w32(data, 0x2c);
-+}
-+
-+struct rt_i2s_data {
-+      u32 flags;
-+      void (*refclk_setup)(void);
-+};
-+
-+struct rt_i2s_data rt3050_i2s_data = { .flags = RALINK_FLAGS_TXONLY };
-+struct rt_i2s_data rt3350_i2s_data = { .flags = RALINK_FLAGS_TXONLY,
-+      .refclk_setup = rt3350_refclk_setup };
-+struct rt_i2s_data rt3883_i2s_data = {
-+      .flags = (RALINK_FLAGS_LEFT_J | RALINK_FLAGS_RIGHT_J),
-+      .refclk_setup = rt3883_refclk_setup };
-+struct rt_i2s_data rt3352_i2s_data = { .refclk_setup = rt3552_refclk_setup};
-+struct rt_i2s_data mt7620_i2s_data = { .refclk_setup = mt7620_refclk_setup};
-+struct rt_i2s_data mt7621_i2s_data = { .refclk_setup = mt7621_refclk_setup};
-+struct rt_i2s_data mt7628_i2s_data = {
-+      .flags = (RALINK_FLAGS_ENDIAN | RALINK_FLAGS_24BIT |
-+                      RALINK_FLAGS_LEFT_J),
-+      .refclk_setup = mt7628_refclk_setup};
-+
-+static const struct of_device_id ralink_i2s_match_table[] = {
-+      { .compatible = "ralink,rt3050-i2s",
-+              .data = (void *)&rt3050_i2s_data },
-+      { .compatible = "ralink,rt3350-i2s",
-+              .data = (void *)&rt3350_i2s_data },
-+      { .compatible = "ralink,rt3883-i2s",
-+              .data = (void *)&rt3883_i2s_data },
-+      { .compatible = "ralink,rt3352-i2s",
-+              .data = (void *)&rt3352_i2s_data },
-+      { .compatible = "mediatek,mt7620-i2s",
-+              .data = (void *)&mt7620_i2s_data },
-+      { .compatible = "mediatek,mt7621-i2s",
-+              .data = (void *)&mt7621_i2s_data },
-+      { .compatible = "mediatek,mt7628-i2s",
-+              .data = (void *)&mt7628_i2s_data },
-+};
-+MODULE_DEVICE_TABLE(of, ralink_i2s_match_table);
-+
-+static int ralink_i2s_probe(struct platform_device *pdev)
-+{
-+      const struct of_device_id *match;
-+      struct device_node *np = pdev->dev.of_node;
-+      struct ralink_i2s *i2s;
-+      struct resource *res;
-+      int irq, ret;
-+      u32 dma_req;
-+      struct rt_i2s_data *data;
-+
-+      i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
-+      if (!i2s)
-+              return -ENOMEM;
-+
-+      platform_set_drvdata(pdev, i2s);
-+      i2s->dev = &pdev->dev;
-+
-+      match = of_match_device(ralink_i2s_match_table, &pdev->dev);
-+      if (!match)
-+              return -EINVAL;
-+      data = (struct rt_i2s_data *)match->data;
-+      i2s->flags = data->flags;
-+      /* setup out 12Mhz refclk to codec as mclk */
-+      if (data->refclk_setup)
-+              data->refclk_setup();
-+
-+      if (of_property_read_u32(np, "txdma-req", &dma_req)) {
-+              dev_err(&pdev->dev, "no txdma-req define\n");
-+              return -EINVAL;
-+      }
-+      i2s->txdma_req = (u16)dma_req;
-+      if (!(i2s->flags & RALINK_FLAGS_TXONLY)) {
-+              if (of_property_read_u32(np, "rxdma-req", &dma_req)) {
-+                      dev_err(&pdev->dev, "no rxdma-req define\n");
-+                      return -EINVAL;
-+              }
-+              i2s->rxdma_req = (u16)dma_req;
-+      }
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      i2s->regs = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(i2s->regs))
-+              return PTR_ERR(i2s->regs);
-+
-+      i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
-+                      &ralink_i2s_regmap_config);
-+      if (IS_ERR(i2s->regmap)) {
-+              dev_err(&pdev->dev, "regmap init failed\n");
-+              return PTR_ERR(i2s->regmap);
-+      }
-+
-+        irq = platform_get_irq(pdev, 0);
-+        if (irq < 0) {
-+                dev_err(&pdev->dev, "failed to get irq\n");
-+                return -EINVAL;
-+        }
-+
-+#if (RALINK_I2S_INT_EN)
-+      ret = devm_request_irq(&pdev->dev, irq, ralink_i2s_irq,
-+                      0, dev_name(&pdev->dev), i2s);
-+      if (ret) {
-+              dev_err(&pdev->dev, "failed to request irq\n");
-+              return ret;
-+      }
-+#endif
-+
-+      i2s->clk = devm_clk_get(&pdev->dev, NULL);
-+      if (IS_ERR(i2s->clk)) {
-+              dev_err(&pdev->dev, "no clock defined\n");
-+              return PTR_ERR(i2s->clk);
-+      }
-+
-+      ret = clk_prepare_enable(i2s->clk);
-+      if (ret)
-+              return ret;
-+
-+      ralink_i2s_init_dma_data(i2s, res);
-+
-+      device_reset(&pdev->dev);
-+
-+      ret = ralink_i2s_debugfs_create(i2s);
-+      if (ret) {
-+              dev_err(&pdev->dev, "create debugfs failed\n");
-+              goto err_clk_disable;
-+      }
-+
-+      /* enable 24bits support */
-+      if (i2s->flags & RALINK_FLAGS_24BIT) {
-+              ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S24_LE;
-+              ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S24_LE;
-+      }
-+
-+      /* enable big endian support */
-+      if (i2s->flags & RALINK_FLAGS_ENDIAN) {
-+              ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S16_BE;
-+              ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S16_BE;
-+              ralink_pcm_hardware.formats |= SNDRV_PCM_FMTBIT_S16_BE;
-+              if (i2s->flags & RALINK_FLAGS_24BIT) {
-+                      ralink_i2s_dai.capture.formats |=
-+                              SNDRV_PCM_FMTBIT_S24_BE;
-+                      ralink_i2s_dai.playback.formats |=
-+                              SNDRV_PCM_FMTBIT_S24_BE;
-+                      ralink_pcm_hardware.formats |=
-+                              SNDRV_PCM_FMTBIT_S24_BE;
-+              }
-+      }
-+
-+      /* disable capture support */
-+      if (i2s->flags & RALINK_FLAGS_TXONLY)
-+              memset(&ralink_i2s_dai.capture, sizeof(ralink_i2s_dai.capture),
-+                              0);
-+
-+      ret = devm_snd_soc_register_component(&pdev->dev, &ralink_i2s_component,
-+                      &ralink_i2s_dai, 1);
-+      if (ret)
-+              goto err_debugfs;
-+
-+      ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
-+                      &ralink_dmaengine_pcm_config,
-+                      SND_DMAENGINE_PCM_FLAG_COMPAT);
-+      if (ret)
-+              goto err_debugfs;
-+
-+      dev_info(i2s->dev, "mclk %luMHz\n", clk_get_rate(i2s->clk) / 1000000);
-+
-+      return 0;
-+
-+err_debugfs:
-+      ralink_i2s_debugfs_remove(i2s);
-+
-+err_clk_disable:
-+      clk_disable_unprepare(i2s->clk);
-+
-+      return ret;
-+}
-+
-+static int ralink_i2s_remove(struct platform_device *pdev)
-+{
-+      struct ralink_i2s *i2s = platform_get_drvdata(pdev);
-+
-+      ralink_i2s_debugfs_remove(i2s);
-+      clk_disable_unprepare(i2s->clk);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ralink_i2s_driver = {
-+      .probe = ralink_i2s_probe,
-+      .remove = ralink_i2s_remove,
-+      .driver = {
-+              .name = DRV_NAME,
-+              .of_match_table = ralink_i2s_match_table,
-+      },
-+};
-+module_platform_driver(ralink_i2s_driver);
-+
-+MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
-+MODULE_DESCRIPTION("Ralink/MediaTek I2S driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/target/linux/ramips/patches-5.10/0051-serial-add-ugly-custom-baud-rate-hack.patch b/target/linux/ramips/patches-5.10/0051-serial-add-ugly-custom-baud-rate-hack.patch
deleted file mode 100644 (file)
index 4822226..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 7 Dec 2015 17:31:08 +0100
-Subject: [PATCH 51/53] serial: add ugly custom baud rate hack
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/tty/serial/serial_core.c |    3 +++
- 1 file changed, 3 insertions(+)
-
---- a/drivers/tty/serial/serial_core.c
-+++ b/drivers/tty/serial/serial_core.c
-@@ -416,6 +416,9 @@ uart_get_baud_rate(struct uart_port *por
-               break;
-       }
-+      if (tty_termios_baud_rate(termios) == 2500000)
-+              return 250000;
-+
-       for (try = 0; try < 2; try++) {
-               baud = tty_termios_baud_rate(termios);
diff --git a/target/linux/ramips/patches-5.10/0052-pwm-add-mediatek-support.patch b/target/linux/ramips/patches-5.10/0052-pwm-add-mediatek-support.patch
deleted file mode 100644 (file)
index d2c5724..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001
-From: John Crispin <blogic@openwrt.org>
-Date: Mon, 7 Dec 2015 17:16:50 +0100
-Subject: [PATCH 52/53] pwm: add mediatek support
-
-Signed-off-by: John Crispin <blogic@openwrt.org>
----
- drivers/pwm/Kconfig        |    9 +++
- drivers/pwm/Makefile       |    1 +
- drivers/pwm/pwm-mediatek.c |  173 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 183 insertions(+)
- create mode 100644 drivers/pwm/pwm-mediatek.c
-
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -316,6 +316,15 @@ config PWM_MEDIATEK
-         To compile this driver as a module, choose M here: the module
-         will be called pwm-mediatek.
-+config PWM_MEDIATEK_RAMIPS
-+      tristate "Mediatek PWM support"
-+      depends on RALINK && OF
-+      help
-+        Generic PWM framework driver for Mediatek ARM SoC.
-+
-+        To compile this driver as a module, choose M here: the module
-+        will be called pwm-mxs.
-+
- config PWM_MXS
-       tristate "Freescale MXS PWM support"
-       depends on ARCH_MXS && OF
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -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
-+obj-$(CONFIG_PWM_MEDIATEK_RAMIPS)     += pwm-mediatek-ramips.o
- obj-$(CONFIG_PWM_MTK_DISP)    += pwm-mtk-disp.o
- obj-$(CONFIG_PWM_MXS)         += pwm-mxs.o
- obj-$(CONFIG_PWM_OMAP_DMTIMER)        += pwm-omap-dmtimer.o
---- /dev/null
-+++ b/drivers/pwm/pwm-mediatek-ramips.c
-@@ -0,0 +1,173 @@
-+/*
-+ * Mediatek Pulse Width Modulator driver
-+ *
-+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pwm.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#define NUM_PWM               4
-+
-+/* PWM registers and bits definitions */
-+#define PWMCON                        0x00
-+#define PWMHDUR                       0x04
-+#define PWMLDUR                       0x08
-+#define PWMGDUR                       0x0c
-+#define PWMWAVENUM            0x28
-+#define PWMDWIDTH             0x2c
-+#define PWMTHRES              0x30
-+
-+/**
-+ * struct mtk_pwm_chip - struct representing pwm chip
-+ *
-+ * @mmio_base: base address of pwm chip
-+ * @chip: linux pwm chip representation
-+ */
-+struct mtk_pwm_chip {
-+      void __iomem *mmio_base;
-+      struct pwm_chip chip;
-+};
-+
-+static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
-+{
-+      return container_of(chip, struct mtk_pwm_chip, chip);
-+}
-+
-+static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
-+                                unsigned long offset)
-+{
-+      return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
-+}
-+
-+static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
-+                                  unsigned int num, unsigned long offset,
-+                                  unsigned long val)
-+{
-+      iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
-+}
-+
-+static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-+                          int duty_ns, int period_ns)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 resolution = 100 / 4;
-+      u32 clkdiv = 0;
-+
-+      while (period_ns / resolution  > 8191) {
-+              clkdiv++;
-+              resolution *= 2;
-+      }
-+
-+      if (clkdiv > 7)
-+              return -1;
-+
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
-+      mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
-+      return 0;
-+}
-+
-+static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 val;
-+
-+      val = ioread32(pc->mmio_base);
-+      val |= BIT(pwm->hwpwm);
-+      iowrite32(val, pc->mmio_base);
-+
-+      return 0;
-+}
-+
-+static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
-+      u32 val;
-+
-+      val = ioread32(pc->mmio_base);
-+      val &= ~BIT(pwm->hwpwm);
-+      iowrite32(val, pc->mmio_base);
-+}
-+
-+static const struct pwm_ops mtk_pwm_ops = {
-+      .config = mtk_pwm_config,
-+      .enable = mtk_pwm_enable,
-+      .disable = mtk_pwm_disable,
-+      .owner = THIS_MODULE,
-+};
-+
-+static int mtk_pwm_probe(struct platform_device *pdev)
-+{
-+      struct mtk_pwm_chip *pc;
-+      struct resource *r;
-+      int ret;
-+
-+      pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-+      if (!pc)
-+              return -ENOMEM;
-+
-+      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
-+      if (IS_ERR(pc->mmio_base))
-+              return PTR_ERR(pc->mmio_base);
-+
-+      platform_set_drvdata(pdev, pc);
-+
-+      pc->chip.dev = &pdev->dev;
-+      pc->chip.ops = &mtk_pwm_ops;
-+      pc->chip.base = -1;
-+      pc->chip.npwm = NUM_PWM;
-+
-+      ret = pwmchip_add(&pc->chip);
-+      if (ret < 0)
-+              dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
-+
-+      return ret;
-+}
-+
-+static int mtk_pwm_remove(struct platform_device *pdev)
-+{
-+      struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
-+      int i;
-+
-+      for (i = 0; i < NUM_PWM; i++)
-+              pwm_disable(&pc->chip.pwms[i]);
-+
-+      return pwmchip_remove(&pc->chip);
-+}
-+
-+static const struct of_device_id mtk_pwm_of_match[] = {
-+      { .compatible = "mediatek,mt7628-pwm" },
-+      { }
-+};
-+
-+MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
-+
-+static struct platform_driver mtk_pwm_driver = {
-+      .driver = {
-+              .name = "mtk-pwm",
-+              .owner = THIS_MODULE,
-+              .of_match_table = mtk_pwm_of_match,
-+      },
-+      .probe = mtk_pwm_probe,
-+      .remove = mtk_pwm_remove,
-+};
-+
-+module_platform_driver(mtk_pwm_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
-+MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/ramips/patches-5.10/0069-awake-rt305x-dwc2-controller.patch b/target/linux/ramips/patches-5.10/0069-awake-rt305x-dwc2-controller.patch
deleted file mode 100644 (file)
index 7110a5b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/drivers/usb/dwc2/platform.c
-+++ b/drivers/usb/dwc2/platform.c
-@@ -431,6 +431,12 @@ static int dwc2_driver_probe(struct plat
-       if (retval)
-               return retval;
-+      /* Enable USB port before any regs access */
-+      if (readl(hsotg->regs + PCGCTL) & 0x0f) {
-+              writel(0x00, hsotg->regs + PCGCTL);
-+              /* TODO: mdelay(25) here? vendor driver don't use it */
-+      }
-+
-       hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
-       retval = dwc2_get_dr_mode(hsotg);
diff --git a/target/linux/ramips/patches-5.10/0070-weak_reordering.patch b/target/linux/ramips/patches-5.10/0070-weak_reordering.patch
deleted file mode 100644 (file)
index fe3fdec..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/arch/mips/ralink/Kconfig
-+++ b/arch/mips/ralink/Kconfig
-@@ -57,6 +57,7 @@ choice
-               select COMMON_CLK
-               select CLKSRC_MIPS_GIC
-               select HAVE_PCI if PCI_MT7621
-+              select WEAK_REORDERING_BEYOND_LLSC
- endchoice
- choice
diff --git a/target/linux/ramips/patches-5.10/0123-mips-ralink-manage-low-reset-lines.patch b/target/linux/ramips/patches-5.10/0123-mips-ralink-manage-low-reset-lines.patch
deleted file mode 100644 (file)
index bdf98f2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-From 3f9ef7785a9cd69cb75f5e2ea4ca79a24752e496 Mon Sep 17 00:00:00 2001
-From: Sander Vanheule <sander@svanheule.net>
-Date: Wed, 3 Feb 2021 10:21:41 +0100
-Subject: MIPS: ralink: manage low reset lines
-
-Reset lines with indices smaller than 8 are currently considered invalid
-by the rt2880-reset reset controller.
-
-The MT7621 SoC uses a number of these low reset lines. The DTS defines
-reset lines "hsdma", "fe", and "mcm" with respective values 5, 6, and 2.
-As a result of the above restriction, these resets cannot be asserted or
-de-asserted by the reset controller. In cases where the bootloader does
-not de-assert these lines, this results in e.g. the MT7621's internal
-switch staying in reset.
-
-Change the reset controller to only ignore the system reset, so all
-reset lines with index greater than 0 are considered valid.
-
-Signed-off-by: Sander Vanheule <sander@svanheule.net>
-Acked-by: John Crispin <john@phrozen.org>
-Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
----
- arch/mips/ralink/reset.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
---- a/arch/mips/ralink/reset.c
-+++ b/arch/mips/ralink/reset.c
-@@ -27,7 +27,7 @@ static int ralink_assert_device(struct r
- {
-       u32 val;
--      if (id < 8)
-+      if (id == 0)
-               return -1;
-       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
-@@ -42,7 +42,7 @@ static int ralink_deassert_device(struct
- {
-       u32 val;
--      if (id < 8)
-+      if (id == 0)
-               return -1;
-       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
diff --git a/target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch b/target/linux/ramips/patches-5.10/020-mips-ralink-manage-low-reset-lines.patch
new file mode 100644 (file)
index 0000000..bdf98f2
--- /dev/null
@@ -0,0 +1,45 @@
+From 3f9ef7785a9cd69cb75f5e2ea4ca79a24752e496 Mon Sep 17 00:00:00 2001
+From: Sander Vanheule <sander@svanheule.net>
+Date: Wed, 3 Feb 2021 10:21:41 +0100
+Subject: MIPS: ralink: manage low reset lines
+
+Reset lines with indices smaller than 8 are currently considered invalid
+by the rt2880-reset reset controller.
+
+The MT7621 SoC uses a number of these low reset lines. The DTS defines
+reset lines "hsdma", "fe", and "mcm" with respective values 5, 6, and 2.
+As a result of the above restriction, these resets cannot be asserted or
+de-asserted by the reset controller. In cases where the bootloader does
+not de-assert these lines, this results in e.g. the MT7621's internal
+switch staying in reset.
+
+Change the reset controller to only ignore the system reset, so all
+reset lines with index greater than 0 are considered valid.
+
+Signed-off-by: Sander Vanheule <sander@svanheule.net>
+Acked-by: John Crispin <john@phrozen.org>
+Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+---
+ arch/mips/ralink/reset.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ralink/reset.c
++++ b/arch/mips/ralink/reset.c
+@@ -27,7 +27,7 @@ static int ralink_assert_device(struct r
+ {
+       u32 val;
+-      if (id < 8)
++      if (id == 0)
+               return -1;
+       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+@@ -42,7 +42,7 @@ static int ralink_deassert_device(struct
+ {
+       u32 val;
+-      if (id < 8)
++      if (id == 0)
+               return -1;
+       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
diff --git a/target/linux/ramips/patches-5.10/0200-linkit_bootstrap.patch b/target/linux/ramips/patches-5.10/0200-linkit_bootstrap.patch
deleted file mode 100644 (file)
index 9142faa..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
---- a/drivers/misc/Makefile
-+++ b/drivers/misc/Makefile
-@@ -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
- obj-$(CONFIG_OCXL)            += ocxl/
- obj-y                         += cardreader/
- obj-$(CONFIG_PVPANIC)         += pvpanic.o
---- /dev/null
-+++ b/drivers/misc/linkit.c
-@@ -0,0 +1,84 @@
-+/*
-+ *  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) 2015 John Crispin <blogic@openwrt.org>
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/of.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/gpio.h>
-+
-+#define LINKIT_LATCH_GPIO     11
-+
-+struct linkit_hw_data {
-+      char board[16];
-+      char rev[16];
-+};
-+
-+static void sanify_string(char *s)
-+{
-+      int i;
-+
-+      for (i = 0; i < 15; i++)
-+              if (s[i] <= 0x20)
-+                      s[i] = '\0';
-+      s[15] = '\0';
-+}
-+
-+static int linkit_probe(struct platform_device *pdev)
-+{
-+      struct linkit_hw_data hw;
-+      struct mtd_info *mtd;
-+      size_t retlen;
-+      int ret;
-+
-+      mtd = get_mtd_device_nm("factory");
-+      if (IS_ERR(mtd))
-+              return PTR_ERR(mtd);
-+
-+      ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw);
-+      put_mtd_device(mtd);
-+
-+      sanify_string(hw.board);
-+      sanify_string(hw.rev);
-+
-+      dev_info(&pdev->dev, "Version  : %s\n", hw.board);
-+      dev_info(&pdev->dev, "Revision : %s\n", hw.rev);
-+
-+      if (!strcmp(hw.board, "LINKITS7688")) {
-+              dev_info(&pdev->dev, "setting up bootstrap latch\n");
-+
-+              if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) {
-+                      dev_err(&pdev->dev, "failed to setup bootstrap gpio\n");
-+                      return -1;
-+              }
-+              gpio_direction_output(LINKIT_LATCH_GPIO, 0);
-+      }
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id linkit_match[] = {
-+      { .compatible = "mediatek,linkit" },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, linkit_match);
-+
-+static struct platform_driver linkit_driver = {
-+      .probe = linkit_probe,
-+      .driver = {
-+              .name = "mtk-linkit",
-+              .owner = THIS_MODULE,
-+              .of_match_table = linkit_match,
-+      },
-+};
-+
-+int __init linkit_init(void)
-+{
-+      return platform_driver_register(&linkit_driver);
-+}
-+late_initcall_sync(linkit_init);
diff --git a/target/linux/ramips/patches-5.10/0300-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch b/target/linux/ramips/patches-5.10/0300-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch
deleted file mode 100644 (file)
index ba844fe..0000000
+++ /dev/null
@@ -1,1400 +0,0 @@
-From e84e2430ee0e483842b4ff013ae8a6e7e2fa2734 Mon Sep 17 00:00:00 2001
-From: Weijie Gao <weijie.gao@mediatek.com>
-Date: Wed, 1 Apr 2020 02:07:58 +0800
-Subject: [PATCH 1/2] mtd: rawnand: add driver support for MT7621 nand
- flash controller
-
-This patch adds NAND flash controller driver for MediaTek MT7621 SoC.
-
-The NAND flash controller is similar with controllers described in
-mtk_nand.c, except that the controller from MT7621 doesn't support DMA
-transmission, and some registers' offset and fields are different.
-
-Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
----
- drivers/mtd/nand/raw/Kconfig       |    8 +
- drivers/mtd/nand/raw/Makefile      |    1 +
- drivers/mtd/nand/raw/mt7621_nand.c | 1348 ++++++++++++++++++++++++++++++++++++
- 3 files changed, 1357 insertions(+)
- create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c
-
---- a/drivers/mtd/nand/raw/Kconfig
-+++ b/drivers/mtd/nand/raw/Kconfig
-@@ -391,6 +391,14 @@ config MTD_NAND_QCOM
-         Enables support for NAND flash chips on SoCs containing the EBI2 NAND
-         controller. This controller is found on IPQ806x SoC.
-+config MTD_NAND_MT7621
-+      tristate "MT7621 NAND controller"
-+      depends on SOC_MT7621 || COMPILE_TEST
-+      depends on HAS_IOMEM
-+      help
-+        Enables support for NAND controller on MT7621 SoC.
-+        This driver uses PIO mode for data transmission instead of DMA mode.
-+
- config MTD_NAND_MTK
-       tristate "MTK NAND controller"
-       depends on ARCH_MEDIATEK || COMPILE_TEST
---- a/drivers/mtd/nand/raw/Makefile
-+++ b/drivers/mtd/nand/raw/Makefile
-@@ -52,6 +52,7 @@ obj-$(CONFIG_MTD_NAND_SUNXI)         += sunxi_n
- obj-$(CONFIG_MTD_NAND_HISI504)                += hisi504_nand.o
- obj-$(CONFIG_MTD_NAND_BRCMNAND)               += brcmnand/
- obj-$(CONFIG_MTD_NAND_QCOM)           += qcom_nandc.o
-+obj-$(CONFIG_MTD_NAND_MT7621)         += mt7621_nand.o
- obj-$(CONFIG_MTD_NAND_MTK)            += mtk_ecc.o mtk_nand.o
- obj-$(CONFIG_MTD_NAND_MXIC)           += mxic_nand.o
- obj-$(CONFIG_MTD_NAND_TEGRA)          += tegra_nand.o
---- /dev/null
-+++ b/drivers/mtd/nand/raw/mt7621_nand.c
-@@ -0,0 +1,1350 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * MediaTek MT7621 NAND Flash Controller driver
-+ *
-+ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
-+ *
-+ * Author: Weijie Gao <weijie.gao@mediatek.com>
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/clk.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/sizes.h>
-+#include <linux/iopoll.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/rawnand.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/platform_device.h>
-+#include <asm/addrspace.h>
-+
-+/* NFI core registers */
-+#define NFI_CNFG                      0x000
-+#define   CNFG_OP_MODE_S              12
-+#define   CNFG_OP_MODE_M              GENMASK(14, 12)
-+#define     CNFG_OP_CUSTOM            6
-+#define   CNFG_AUTO_FMT_EN            BIT(9)
-+#define   CNFG_HW_ECC_EN              BIT(8)
-+#define   CNFG_BYTE_RW                        BIT(6)
-+#define   CNFG_READ_MODE              BIT(1)
-+
-+#define NFI_PAGEFMT                   0x004
-+#define   PAGEFMT_FDM_ECC_S           12
-+#define   PAGEFMT_FDM_ECC_M           GENMASK(15, 12)
-+#define   PAGEFMT_FDM_S                       8
-+#define   PAGEFMT_FDM_M                       GENMASK(11, 8)
-+#define   PAGEFMT_SPARE_S             4
-+#define   PAGEFMT_SPARE_M             GENMASK(5, 4)
-+#define   PAGEFMT_PAGE_S              0
-+#define   PAGEFMT_PAGE_M              GENMASK(1, 0)
-+
-+#define NFI_CON                               0x008
-+#define   CON_NFI_SEC_S                       12
-+#define   CON_NFI_SEC_M                       GENMASK(15, 12)
-+#define   CON_NFI_BWR                 BIT(9)
-+#define   CON_NFI_BRD                 BIT(8)
-+#define   CON_NFI_RST                 BIT(1)
-+#define   CON_FIFO_FLUSH              BIT(0)
-+
-+#define NFI_ACCCON                    0x00c
-+#define   ACCCON_POECS_S              28
-+#define   ACCCON_POECS_MAX            0x0f
-+#define   ACCCON_POECS_DEF            3
-+#define   ACCCON_PRECS_S              22
-+#define   ACCCON_PRECS_MAX            0x3f
-+#define   ACCCON_PRECS_DEF            3
-+#define   ACCCON_C2R_S                        16
-+#define   ACCCON_C2R_MAX              0x3f
-+#define   ACCCON_C2R_DEF              7
-+#define   ACCCON_W2R_S                        12
-+#define   ACCCON_W2R_MAX              0x0f
-+#define   ACCCON_W2R_DEF              7
-+#define   ACCCON_WH_S                 8
-+#define   ACCCON_WH_MAX                       0x0f
-+#define   ACCCON_WH_DEF                       15
-+#define   ACCCON_WST_S                        4
-+#define   ACCCON_WST_MAX              0x0f
-+#define   ACCCON_WST_DEF              15
-+#define   ACCCON_WST_MIN              3
-+#define   ACCCON_RLT_S                        0
-+#define   ACCCON_RLT_MAX              0x0f
-+#define   ACCCON_RLT_DEF              15
-+#define   ACCCON_RLT_MIN              3
-+
-+#define NFI_CMD                               0x020
-+
-+#define NFI_ADDRNOB                   0x030
-+#define   ADDR_ROW_NOB_S              4
-+#define   ADDR_ROW_NOB_M              GENMASK(6, 4)
-+#define   ADDR_COL_NOB_S              0
-+#define   ADDR_COL_NOB_M              GENMASK(2, 0)
-+
-+#define NFI_COLADDR                   0x034
-+#define NFI_ROWADDR                   0x038
-+
-+#define NFI_STRDATA                   0x040
-+#define   STR_DATA                    BIT(0)
-+
-+#define NFI_CNRNB                     0x044
-+#define   CB2R_TIME_S                 4
-+#define   CB2R_TIME_M                 GENMASK(7, 4)
-+#define   STR_CNRNB                   BIT(0)
-+
-+#define NFI_DATAW                     0x050
-+#define NFI_DATAR                     0x054
-+
-+#define NFI_PIO_DIRDY                 0x058
-+#define   PIO_DIRDY                   BIT(0)
-+
-+#define NFI_STA                               0x060
-+#define   STA_NFI_FSM_S                       16
-+#define   STA_NFI_FSM_M                       GENMASK(19, 16)
-+#define     STA_FSM_CUSTOM_DATA               14
-+#define   STA_BUSY                    BIT(8)
-+#define   STA_ADDR                    BIT(1)
-+#define   STA_CMD                     BIT(0)
-+
-+#define NFI_ADDRCNTR                  0x070
-+#define   SEC_CNTR_S                  12
-+#define   SEC_CNTR_M                  GENMASK(15, 12)
-+#define   SEC_ADDR_S                  0
-+#define   SEC_ADDR_M                  GENMASK(9, 0)
-+
-+#define NFI_CSEL                      0x090
-+#define   CSEL_S                      0
-+#define   CSEL_M                      GENMASK(1, 0)
-+
-+#define NFI_FDM0L                     0x0a0
-+#define NFI_FDML(n)                   (0x0a0 + ((n) << 3))
-+
-+#define NFI_FDM0M                     0x0a4
-+#define NFI_FDMM(n)                   (0x0a4 + ((n) << 3))
-+
-+#define NFI_MASTER_STA                        0x210
-+#define   MAS_ADDR                    GENMASK(11, 9)
-+#define   MAS_RD                      GENMASK(8, 6)
-+#define   MAS_WR                      GENMASK(5, 3)
-+#define   MAS_RDDLY                   GENMASK(2, 0)
-+
-+/* ECC engine registers */
-+#define ECC_ENCCON                    0x000
-+#define   ENC_EN                      BIT(0)
-+
-+#define ECC_ENCCNFG                   0x004
-+#define   ENC_CNFG_MSG_S              16
-+#define   ENC_CNFG_MSG_M              GENMASK(28, 16)
-+#define   ENC_MODE_S                  4
-+#define   ENC_MODE_M                  GENMASK(5, 4)
-+#define     ENC_MODE_NFI              1
-+#define   ENC_TNUM_S                  0
-+#define   ENC_TNUM_M                  GENMASK(2, 0)
-+
-+#define ECC_ENCIDLE                   0x00c
-+#define   ENC_IDLE                    BIT(0)
-+
-+#define ECC_DECCON                    0x100
-+#define   DEC_EN                      BIT(0)
-+
-+#define ECC_DECCNFG                   0x104
-+#define   DEC_EMPTY_EN                        BIT(31)
-+#define   DEC_CS_S                    16
-+#define   DEC_CS_M                    GENMASK(28, 16)
-+#define   DEC_CON_S                   12
-+#define   DEC_CON_M                   GENMASK(13, 12)
-+#define     DEC_CON_EL                        2
-+#define   DEC_MODE_S                  4
-+#define   DEC_MODE_M                  GENMASK(5, 4)
-+#define     DEC_MODE_NFI              1
-+#define   DEC_TNUM_S                  0
-+#define   DEC_TNUM_M                  GENMASK(2, 0)
-+
-+#define ECC_DECIDLE                   0x10c
-+#define   DEC_IDLE                    BIT(1)
-+
-+#define ECC_DECENUM                   0x114
-+#define   ERRNUM_S                    2
-+#define   ERRNUM_M                    GENMASK(3, 0)
-+
-+#define ECC_DECDONE                   0x118
-+#define   DEC_DONE7                   BIT(7)
-+#define   DEC_DONE6                   BIT(6)
-+#define   DEC_DONE5                   BIT(5)
-+#define   DEC_DONE4                   BIT(4)
-+#define   DEC_DONE3                   BIT(3)
-+#define   DEC_DONE2                   BIT(2)
-+#define   DEC_DONE1                   BIT(1)
-+#define   DEC_DONE0                   BIT(0)
-+
-+#define ECC_DECEL(n)                  (0x11c + (n) * 4)
-+#define   DEC_EL_ODD_S                        16
-+#define   DEC_EL_EVEN_S                       0
-+#define   DEC_EL_M                    0x1fff
-+#define   DEC_EL_BYTE_POS_S           3
-+#define   DEC_EL_BIT_POS_M            GENMASK(3, 0)
-+
-+#define ECC_FDMADDR                   0x13c
-+
-+/* ENCIDLE and DECIDLE */
-+#define   ECC_IDLE                    BIT(0)
-+
-+#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
-+      ((tpoecs) << ACCCON_POECS_S | (tprecs) << ACCCON_PRECS_S | \
-+      (tc2r) << ACCCON_C2R_S | (tw2r) << ACCCON_W2R_S | \
-+      (twh) << ACCCON_WH_S | (twst) << ACCCON_WST_S | (trlt))
-+
-+#define MASTER_STA_MASK                       (MAS_ADDR | MAS_RD | MAS_WR | \
-+                                       MAS_RDDLY)
-+#define NFI_RESET_TIMEOUT             1000000
-+#define NFI_CORE_TIMEOUT              500000
-+#define ECC_ENGINE_TIMEOUT            500000
-+
-+#define ECC_SECTOR_SIZE                       512
-+#define ECC_PARITY_BITS                       13
-+
-+#define NFI_FDM_SIZE          8
-+
-+#define MT7621_NFC_NAME                       "mt7621-nand"
-+
-+struct mt7621_nfc {
-+      struct nand_controller controller;
-+      struct nand_chip nand;
-+      struct clk *nfi_clk;
-+      struct device *dev;
-+
-+      void __iomem *nfi_regs;
-+      void __iomem *ecc_regs;
-+
-+      u32 spare_per_sector;
-+};
-+
-+static const u16 mt7621_nfi_page_size[] = { SZ_512, SZ_2K, SZ_4K };
-+static const u8 mt7621_nfi_spare_size[] = { 16, 26, 27, 28 };
-+static const u8 mt7621_ecc_strength[] = { 4, 6, 8, 10, 12 };
-+
-+static inline u32 nfi_read32(struct mt7621_nfc *nfc, u32 reg)
-+{
-+      return readl(nfc->nfi_regs + reg);
-+}
-+
-+static inline void nfi_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
-+{
-+      writel(val, nfc->nfi_regs + reg);
-+}
-+
-+static inline u16 nfi_read16(struct mt7621_nfc *nfc, u32 reg)
-+{
-+      return readw(nfc->nfi_regs + reg);
-+}
-+
-+static inline void nfi_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
-+{
-+      writew(val, nfc->nfi_regs + reg);
-+}
-+
-+static inline void ecc_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
-+{
-+      writew(val, nfc->ecc_regs + reg);
-+}
-+
-+static inline u32 ecc_read32(struct mt7621_nfc *nfc, u32 reg)
-+{
-+      return readl(nfc->ecc_regs + reg);
-+}
-+
-+static inline void ecc_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
-+{
-+      return writel(val, nfc->ecc_regs + reg);
-+}
-+
-+static inline u8 *oob_fdm_ptr(struct nand_chip *nand, int sect)
-+{
-+      return nand->oob_poi + sect * NFI_FDM_SIZE;
-+}
-+
-+static inline u8 *oob_ecc_ptr(struct mt7621_nfc *nfc, int sect)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+
-+      return nand->oob_poi + nand->ecc.steps * NFI_FDM_SIZE +
-+              sect * (nfc->spare_per_sector - NFI_FDM_SIZE);
-+}
-+
-+static inline u8 *page_data_ptr(struct nand_chip *nand, const u8 *buf,
-+                              int sect)
-+{
-+      return (u8 *)buf + sect * nand->ecc.size;
-+}
-+
-+static int mt7621_ecc_wait_idle(struct mt7621_nfc *nfc, u32 reg)
-+{
-+      struct device *dev = nfc->dev;
-+      u32 val;
-+      int ret;
-+
-+      ret = readw_poll_timeout_atomic(nfc->ecc_regs + reg, val,
-+                                      val & ECC_IDLE, 10,
-+                                      ECC_ENGINE_TIMEOUT);
-+      if (ret) {
-+              dev_warn(dev, "ECC engine timed out entering idle mode\n");
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt7621_ecc_decoder_wait_done(struct mt7621_nfc *nfc, u32 sect)
-+{
-+      struct device *dev = nfc->dev;
-+      u32 val;
-+      int ret;
-+
-+      ret = readw_poll_timeout_atomic(nfc->ecc_regs + ECC_DECDONE, val,
-+                                      val & (1 << sect), 10,
-+                                      ECC_ENGINE_TIMEOUT);
-+
-+      if (ret) {
-+              dev_warn(dev, "ECC decoder for sector %d timed out\n",
-+                       sect);
-+              return -ETIMEDOUT;
-+      }
-+
-+      return 0;
-+}
-+
-+static void mt7621_ecc_encoder_op(struct mt7621_nfc *nfc, bool enable)
-+{
-+      mt7621_ecc_wait_idle(nfc, ECC_ENCIDLE);
-+      ecc_write16(nfc, ECC_ENCCON, enable ? ENC_EN : 0);
-+}
-+
-+static void mt7621_ecc_decoder_op(struct mt7621_nfc *nfc, bool enable)
-+{
-+      mt7621_ecc_wait_idle(nfc, ECC_DECIDLE);
-+      ecc_write16(nfc, ECC_DECCON, enable ? DEC_EN : 0);
-+}
-+
-+static int mt7621_ecc_correct_check(struct mt7621_nfc *nfc, u8 *sector_buf,
-+                                 u8 *fdm_buf, u32 sect)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      u32 decnum, num_error_bits, fdm_end_bits;
-+      u32 error_locations, error_bit_loc;
-+      u32 error_byte_pos, error_bit_pos;
-+      int bitflips = 0;
-+      u32 i;
-+
-+      decnum = ecc_read32(nfc, ECC_DECENUM);
-+      num_error_bits = (decnum >> (sect << ERRNUM_S)) & ERRNUM_M;
-+      fdm_end_bits = (nand->ecc.size + NFI_FDM_SIZE) << 3;
-+
-+      if (!num_error_bits)
-+              return 0;
-+
-+      if (num_error_bits == ERRNUM_M)
-+              return -1;
-+
-+      for (i = 0; i < num_error_bits; i++) {
-+              error_locations = ecc_read32(nfc, ECC_DECEL(i / 2));
-+              error_bit_loc = (error_locations >> ((i % 2) * DEC_EL_ODD_S)) &
-+                              DEC_EL_M;
-+              error_byte_pos = error_bit_loc >> DEC_EL_BYTE_POS_S;
-+              error_bit_pos = error_bit_loc & DEC_EL_BIT_POS_M;
-+
-+              if (error_bit_loc < (nand->ecc.size << 3)) {
-+                      if (sector_buf) {
-+                              sector_buf[error_byte_pos] ^=
-+                                      (1 << error_bit_pos);
-+                      }
-+              } else if (error_bit_loc < fdm_end_bits) {
-+                      if (fdm_buf) {
-+                              fdm_buf[error_byte_pos - nand->ecc.size] ^=
-+                                      (1 << error_bit_pos);
-+                      }
-+              }
-+
-+              bitflips++;
-+      }
-+
-+      return bitflips;
-+}
-+
-+static int mt7621_nfc_wait_write_completion(struct mt7621_nfc *nfc,
-+                                          struct nand_chip *nand)
-+{
-+      struct device *dev = nfc->dev;
-+      u16 val;
-+      int ret;
-+
-+      ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_ADDRCNTR, val,
-+              ((val & SEC_CNTR_M) >> SEC_CNTR_S) >= nand->ecc.steps, 10,
-+              NFI_CORE_TIMEOUT);
-+
-+      if (ret) {
-+              dev_warn(dev, "NFI core write operation timed out\n");
-+              return -ETIMEDOUT;
-+      }
-+
-+      return ret;
-+}
-+
-+static void mt7621_nfc_hw_reset(struct mt7621_nfc *nfc)
-+{
-+      u32 val;
-+      int ret;
-+
-+      /* reset all registers and force the NFI master to terminate */
-+      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
-+
-+      /* wait for the master to finish the last transaction */
-+      ret = readw_poll_timeout(nfc->nfi_regs + NFI_MASTER_STA, val,
-+                               !(val & MASTER_STA_MASK), 50,
-+                               NFI_RESET_TIMEOUT);
-+      if (ret) {
-+              dev_warn(nfc->dev, "Failed to reset NFI master in %dms\n",
-+                       NFI_RESET_TIMEOUT);
-+      }
-+
-+      /* ensure any status register affected by the NFI master is reset */
-+      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
-+      nfi_write16(nfc, NFI_STRDATA, 0);
-+}
-+
-+static inline void mt7621_nfc_hw_init(struct mt7621_nfc *nfc)
-+{
-+      u32 acccon;
-+
-+      /*
-+       * CNRNB: nand ready/busy register
-+       * -------------------------------
-+       * 7:4: timeout register for polling the NAND busy/ready signal
-+       * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
-+       */
-+      nfi_write16(nfc, NFI_CNRNB, CB2R_TIME_M | STR_CNRNB);
-+
-+      mt7621_nfc_hw_reset(nfc);
-+
-+      /* Apply default access timing */
-+      acccon = ACCTIMING(ACCCON_POECS_DEF, ACCCON_PRECS_DEF, ACCCON_C2R_DEF,
-+                         ACCCON_W2R_DEF, ACCCON_WH_DEF, ACCCON_WST_DEF,
-+                         ACCCON_RLT_DEF);
-+
-+      nfi_write32(nfc, NFI_ACCCON, acccon);
-+}
-+
-+static int mt7621_nfc_send_command(struct mt7621_nfc *nfc, u8 command)
-+{
-+      struct device *dev = nfc->dev;
-+      u32 val;
-+      int ret;
-+
-+      nfi_write32(nfc, NFI_CMD, command);
-+
-+      ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
-+                                      !(val & STA_CMD), 10,
-+                                      NFI_CORE_TIMEOUT);
-+      if (ret) {
-+              dev_warn(dev, "NFI core timed out entering command mode\n");
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_send_address_byte(struct mt7621_nfc *nfc, int addr)
-+{
-+      struct device *dev = nfc->dev;
-+      u32 val;
-+      int ret;
-+
-+      nfi_write32(nfc, NFI_COLADDR, addr);
-+      nfi_write32(nfc, NFI_ROWADDR, 0);
-+      nfi_write16(nfc, NFI_ADDRNOB, 1);
-+
-+      ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
-+                                      !(val & STA_ADDR), 10,
-+                                      NFI_CORE_TIMEOUT);
-+      if (ret) {
-+              dev_warn(dev, "NFI core timed out entering address mode\n");
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_send_address(struct mt7621_nfc *nfc, const u8 *addr,
-+                                 unsigned int naddrs)
-+{
-+      int ret;
-+
-+      while (naddrs) {
-+              ret = mt7621_nfc_send_address_byte(nfc, *addr);
-+              if (ret)
-+                      return ret;
-+
-+              addr++;
-+              naddrs--;
-+      }
-+
-+      return 0;
-+}
-+
-+static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc)
-+{
-+      struct device *dev = nfc->dev;
-+      int ret;
-+      u16 val;
-+
-+      ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_PIO_DIRDY, val,
-+                                      val & PIO_DIRDY, 10,
-+                                      NFI_CORE_TIMEOUT);
-+      if (ret < 0)
-+              dev_err(dev, "NFI core PIO mode not ready\n");
-+}
-+
-+static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br)
-+{
-+      u32 reg;
-+
-+      /* after each byte read, the NFI_STA reg is reset by the hardware */
-+      reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
-+      if (reg != STA_FSM_CUSTOM_DATA) {
-+              reg = nfi_read16(nfc, NFI_CNFG);
-+              reg |= CNFG_READ_MODE | CNFG_BYTE_RW;
-+              if (!br)
-+                      reg &= ~CNFG_BYTE_RW;
-+              nfi_write16(nfc, NFI_CNFG, reg);
-+
-+              /*
-+               * set to max sector to allow the HW to continue reading over
-+               * unaligned accesses
-+               */
-+              nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BRD);
-+
-+              /* trigger to fetch data */
-+              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
-+      }
-+
-+      mt7621_nfc_wait_pio_ready(nfc);
-+
-+      return nfi_read32(nfc, NFI_DATAR);
-+}
-+
-+static void mt7621_nfc_read_data(struct mt7621_nfc *nfc, u8 *buf, u32 len)
-+{
-+      while (((uintptr_t)buf & 3) && len) {
-+              *buf = mt7621_nfc_pio_read(nfc, true);
-+              buf++;
-+              len--;
-+      }
-+
-+      while (len >= 4) {
-+              *(u32 *)buf = mt7621_nfc_pio_read(nfc, false);
-+              buf += 4;
-+              len -= 4;
-+      }
-+
-+      while (len) {
-+              *buf = mt7621_nfc_pio_read(nfc, true);
-+              buf++;
-+              len--;
-+      }
-+}
-+
-+static void mt7621_nfc_read_data_discard(struct mt7621_nfc *nfc, u32 len)
-+{
-+      while (len >= 4) {
-+              mt7621_nfc_pio_read(nfc, false);
-+              len -= 4;
-+      }
-+
-+      while (len) {
-+              mt7621_nfc_pio_read(nfc, true);
-+              len--;
-+      }
-+}
-+
-+static void mt7621_nfc_pio_write(struct mt7621_nfc *nfc, u32 val, bool bw)
-+{
-+      u32 reg;
-+
-+      reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
-+      if (reg != STA_FSM_CUSTOM_DATA) {
-+              reg = nfi_read16(nfc, NFI_CNFG);
-+              reg &= ~(CNFG_READ_MODE | CNFG_BYTE_RW);
-+              if (bw)
-+                      reg |= CNFG_BYTE_RW;
-+              nfi_write16(nfc, NFI_CNFG, reg);
-+
-+              nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BWR);
-+              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
-+      }
-+
-+      mt7621_nfc_wait_pio_ready(nfc);
-+      nfi_write32(nfc, NFI_DATAW, val);
-+}
-+
-+static void mt7621_nfc_write_data(struct mt7621_nfc *nfc, const u8 *buf,
-+                                u32 len)
-+{
-+      while (((uintptr_t)buf & 3) && len) {
-+              mt7621_nfc_pio_write(nfc, *buf, true);
-+              buf++;
-+              len--;
-+      }
-+
-+      while (len >= 4) {
-+              mt7621_nfc_pio_write(nfc, *(const u32 *)buf, false);
-+              buf += 4;
-+              len -= 4;
-+      }
-+
-+      while (len) {
-+              mt7621_nfc_pio_write(nfc, *buf, true);
-+              buf++;
-+              len--;
-+      }
-+}
-+
-+static void mt7621_nfc_write_data_empty(struct mt7621_nfc *nfc, u32 len)
-+{
-+      while (len >= 4) {
-+              mt7621_nfc_pio_write(nfc, 0xffffffff, false);
-+              len -= 4;
-+      }
-+
-+      while (len) {
-+              mt7621_nfc_pio_write(nfc, 0xff, true);
-+              len--;
-+      }
-+}
-+
-+static int mt7621_nfc_dev_ready(struct mt7621_nfc *nfc,
-+                              unsigned int timeout_ms)
-+{
-+      u32 val;
-+
-+      return readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
-+                                       !(val & STA_BUSY), 10,
-+                                       timeout_ms * 1000);
-+}
-+
-+static int mt7621_nfc_exec_instr(struct nand_chip *nand,
-+                               const struct nand_op_instr *instr)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+
-+      switch (instr->type) {
-+      case NAND_OP_CMD_INSTR:
-+              mt7621_nfc_hw_reset(nfc);
-+              nfi_write16(nfc, NFI_CNFG, CNFG_OP_CUSTOM << CNFG_OP_MODE_S);
-+              return mt7621_nfc_send_command(nfc, instr->ctx.cmd.opcode);
-+      case NAND_OP_ADDR_INSTR:
-+              return mt7621_nfc_send_address(nfc, instr->ctx.addr.addrs,
-+                                             instr->ctx.addr.naddrs);
-+      case NAND_OP_DATA_IN_INSTR:
-+              mt7621_nfc_read_data(nfc, instr->ctx.data.buf.in,
-+                                   instr->ctx.data.len);
-+              return 0;
-+      case NAND_OP_DATA_OUT_INSTR:
-+              mt7621_nfc_write_data(nfc, instr->ctx.data.buf.out,
-+                                    instr->ctx.data.len);
-+              return 0;
-+      case NAND_OP_WAITRDY_INSTR:
-+              return mt7621_nfc_dev_ready(nfc,
-+                                          instr->ctx.waitrdy.timeout_ms);
-+      default:
-+              WARN_ONCE(1, "unsupported NAND instruction type: %d\n",
-+                        instr->type);
-+
-+              return -EINVAL;
-+      }
-+}
-+
-+static int mt7621_nfc_exec_op(struct nand_chip *nand,
-+                            const struct nand_operation *op, bool check_only)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      int i, ret;
-+
-+      if (check_only)
-+              return 0;
-+
-+      /* Only CS0 available */
-+      nfi_write16(nfc, NFI_CSEL, 0);
-+
-+      for (i = 0; i < op->ninstrs; i++) {
-+              ret = mt7621_nfc_exec_instr(nand, &op->instrs[i]);
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_setup_data_interface(struct nand_chip *nand, int csline,
-+                                         const struct nand_data_interface *conf)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      const struct nand_sdr_timings *timings;
-+      u32 acccon, temp, rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
-+
-+      if (!nfc->nfi_clk)
-+              return -ENOTSUPP;
-+
-+      timings = nand_get_sdr_timings(conf);
-+      if (IS_ERR(timings))
-+              return -ENOTSUPP;
-+
-+      rate = clk_get_rate(nfc->nfi_clk);
-+
-+      /* turn clock rate into KHZ */
-+      rate /= 1000;
-+
-+      tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
-+      tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
-+      tpoecs = min_t(u32, tpoecs, ACCCON_POECS_MAX);
-+
-+      tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
-+      tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
-+      tprecs = min_t(u32, tprecs, ACCCON_PRECS_MAX);
-+
-+      /* sdr interface has no tCR which means CE# low to RE# low */
-+      tc2r = 0;
-+
-+      tw2r = timings->tWHR_min / 1000;
-+      tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
-+      tw2r = DIV_ROUND_UP(tw2r - 1, 2);
-+      tw2r = min_t(u32, tw2r, ACCCON_W2R_MAX);
-+
-+      twh = max(timings->tREH_min, timings->tWH_min) / 1000;
-+      twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
-+      twh = min_t(u32, twh, ACCCON_WH_MAX);
-+
-+      /* Calculate real WE#/RE# hold time in nanosecond */
-+      temp = (twh + 1) * 1000000 / rate;
-+      /* nanosecond to picosecond */
-+      temp *= 1000;
-+
-+      /*
-+       * WE# low level time should be expaned to meet WE# pulse time
-+       * and WE# cycle time at the same time.
-+       */
-+      if (temp < timings->tWC_min)
-+              twst = timings->tWC_min - temp;
-+      else
-+              twst = 0;
-+      twst = max(timings->tWP_min, twst) / 1000;
-+      twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
-+      twst = min_t(u32, twst, ACCCON_WST_MAX);
-+
-+      /*
-+       * RE# low level time should be expaned to meet RE# pulse time
-+       * and RE# cycle time at the same time.
-+       */
-+      if (temp < timings->tRC_min)
-+              trlt = timings->tRC_min - temp;
-+      else
-+              trlt = 0;
-+      trlt = max(trlt, timings->tRP_min) / 1000;
-+      trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
-+      trlt = min_t(u32, trlt, ACCCON_RLT_MAX);
-+
-+      if (csline == NAND_DATA_IFACE_CHECK_ONLY) {
-+              if (twst < ACCCON_WST_MIN || trlt < ACCCON_RLT_MIN)
-+                      return -ENOTSUPP;
-+      }
-+
-+      acccon = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
-+
-+      dev_info(nfc->dev, "Using programmed access timing: %08x\n", acccon);
-+
-+      nfi_write32(nfc, NFI_ACCCON, acccon);
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_calc_ecc_strength(struct mt7621_nfc *nfc,
-+                                      u32 avail_ecc_bytes)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      u32 strength;
-+      int i;
-+
-+      strength = avail_ecc_bytes * 8 / ECC_PARITY_BITS;
-+
-+      /* Find the closest supported ecc strength */
-+      for (i = ARRAY_SIZE(mt7621_ecc_strength) - 1; i >= 0; i--) {
-+              if (mt7621_ecc_strength[i] <= strength)
-+                      break;
-+      }
-+
-+      if (unlikely(i < 0)) {
-+              dev_err(nfc->dev, "OOB size (%u) is not supported\n",
-+                      mtd->oobsize);
-+              return -EINVAL;
-+      }
-+
-+      nand->ecc.strength = mt7621_ecc_strength[i];
-+      nand->ecc.bytes =
-+              DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
-+
-+      dev_info(nfc->dev, "ECC strength adjusted to %u bits\n",
-+               nand->ecc.strength);
-+
-+      return i;
-+}
-+
-+static int mt7621_nfc_set_spare_per_sector(struct mt7621_nfc *nfc)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      u32 size;
-+      int i;
-+
-+      size = nand->ecc.bytes + NFI_FDM_SIZE;
-+
-+      /* Find the closest supported spare size */
-+      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_spare_size); i++) {
-+              if (mt7621_nfi_spare_size[i] >= size)
-+                      break;
-+      }
-+
-+      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_spare_size))) {
-+              dev_err(nfc->dev, "OOB size (%u) is not supported\n",
-+                      mtd->oobsize);
-+              return -EINVAL;
-+      }
-+
-+      nfc->spare_per_sector = mt7621_nfi_spare_size[i];
-+
-+      return i;
-+}
-+
-+static int mt7621_nfc_ecc_init(struct mt7621_nfc *nfc)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      u32 spare_per_sector, encode_block_size, decode_block_size;
-+      u32 ecc_enccfg, ecc_deccfg;
-+      int ecc_cap;
-+
-+      /* Only hardware ECC mode is supported */
-+      if (nand->ecc.mode != NAND_ECC_HW_SYNDROME) {
-+              dev_err(nfc->dev, "Only hardware ECC mode is supported\n");
-+              return -EINVAL;
-+      }
-+
-+      nand->ecc.size = ECC_SECTOR_SIZE;
-+      nand->ecc.steps = mtd->writesize / nand->ecc.size;
-+
-+      spare_per_sector = mtd->oobsize / nand->ecc.steps;
-+
-+      ecc_cap = mt7621_nfc_calc_ecc_strength(nfc,
-+              spare_per_sector - NFI_FDM_SIZE);
-+      if (ecc_cap < 0)
-+              return ecc_cap;
-+
-+      /* Sector + FDM */
-+      encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8;
-+      ecc_enccfg = ecc_cap | (ENC_MODE_NFI << ENC_MODE_S) |
-+                   (encode_block_size << ENC_CNFG_MSG_S);
-+
-+      /* Sector + FDM + ECC parity bits */
-+      decode_block_size = ((nand->ecc.size + NFI_FDM_SIZE) * 8) +
-+                          nand->ecc.strength * ECC_PARITY_BITS;
-+      ecc_deccfg = ecc_cap | (DEC_MODE_NFI << DEC_MODE_S) |
-+                   (decode_block_size << DEC_CS_S) |
-+                   (DEC_CON_EL << DEC_CON_S) | DEC_EMPTY_EN;
-+
-+      mt7621_ecc_encoder_op(nfc, false);
-+      ecc_write32(nfc, ECC_ENCCNFG, ecc_enccfg);
-+
-+      mt7621_ecc_decoder_op(nfc, false);
-+      ecc_write32(nfc, ECC_DECCNFG, ecc_deccfg);
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_set_page_format(struct mt7621_nfc *nfc)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      int i, spare_size;
-+      u32 pagefmt;
-+
-+      spare_size = mt7621_nfc_set_spare_per_sector(nfc);
-+      if (spare_size < 0)
-+              return spare_size;
-+
-+      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_page_size); i++) {
-+              if (mt7621_nfi_page_size[i] == mtd->writesize)
-+                      break;
-+      }
-+
-+      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_page_size))) {
-+              dev_err(nfc->dev, "Page size (%u) is not supported\n",
-+                      mtd->writesize);
-+              return -EINVAL;
-+      }
-+
-+      pagefmt = i | (spare_size << PAGEFMT_SPARE_S) |
-+                (NFI_FDM_SIZE << PAGEFMT_FDM_S) |
-+                (NFI_FDM_SIZE << PAGEFMT_FDM_ECC_S);
-+
-+      nfi_write16(nfc, NFI_PAGEFMT, pagefmt);
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_attach_chip(struct nand_chip *nand)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      int ret;
-+
-+      if (nand->options & NAND_BUSWIDTH_16) {
-+              dev_err(nfc->dev, "16-bit buswidth is not supported");
-+              return -EINVAL;
-+      }
-+
-+      ret = mt7621_nfc_ecc_init(nfc);
-+      if (ret)
-+              return ret;
-+
-+      return mt7621_nfc_set_page_format(nfc);
-+}
-+
-+static const struct nand_controller_ops mt7621_nfc_controller_ops = {
-+      .attach_chip = mt7621_nfc_attach_chip,
-+      .exec_op = mt7621_nfc_exec_op,
-+      .setup_data_interface = mt7621_nfc_setup_data_interface,
-+};
-+
-+static int mt7621_nfc_ooblayout_free(struct mtd_info *mtd, int section,
-+                                   struct mtd_oob_region *oob_region)
-+{
-+      struct nand_chip *nand = mtd_to_nand(mtd);
-+
-+      if (section >= nand->ecc.steps)
-+              return -ERANGE;
-+
-+      oob_region->length = NFI_FDM_SIZE - 1;
-+      oob_region->offset = section * NFI_FDM_SIZE + 1;
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
-+                                  struct mtd_oob_region *oob_region)
-+{
-+      struct nand_chip *nand = mtd_to_nand(mtd);
-+
-+      if (section)
-+              return -ERANGE;
-+
-+      oob_region->offset = NFI_FDM_SIZE * nand->ecc.steps;
-+      oob_region->length = mtd->oobsize - oob_region->offset;
-+
-+      return 0;
-+}
-+
-+static const struct mtd_ooblayout_ops mt7621_nfc_ooblayout_ops = {
-+      .free = mt7621_nfc_ooblayout_free,
-+      .ecc = mt7621_nfc_ooblayout_ecc,
-+};
-+
-+static void mt7621_nfc_write_fdm(struct mt7621_nfc *nfc)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      u32 vall, valm;
-+      u8 *oobptr;
-+      int i, j;
-+
-+      for (i = 0; i < nand->ecc.steps; i++) {
-+              vall = 0;
-+              valm = 0;
-+              oobptr = oob_fdm_ptr(nand, i);
-+
-+              for (j = 0; j < 4; j++)
-+                      vall |= (u32)oobptr[j] << (j * 8);
-+
-+              for (j = 0; j < 4; j++)
-+                      valm |= (u32)oobptr[j + 4] << ((j - 4) * 8);
-+
-+              nfi_write32(nfc, NFI_FDML(i), vall);
-+              nfi_write32(nfc, NFI_FDMM(i), valm);
-+      }
-+}
-+
-+static void mt7621_nfc_read_sector_fdm(struct mt7621_nfc *nfc, u32 sect)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      u32 vall, valm;
-+      u8 *oobptr;
-+      int i;
-+
-+      vall = nfi_read32(nfc, NFI_FDML(sect));
-+      valm = nfi_read32(nfc, NFI_FDMM(sect));
-+      oobptr = oob_fdm_ptr(nand, sect);
-+
-+      for (i = 0; i < 4; i++)
-+              oobptr[i] = (vall >> (i * 8)) & 0xff;
-+
-+      for (i = 0; i < 4; i++)
-+              oobptr[i + 4] = (valm >> (i * 8)) & 0xff;
-+}
-+
-+static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf,
-+                                    int oob_required, int page)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      int bitflips = 0;
-+      int rc, i;
-+
-+      nand_read_page_op(nand, page, 0, NULL, 0);
-+
-+      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
-+                  CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
-+
-+      mt7621_ecc_decoder_op(nfc, true);
-+
-+      nfi_write16(nfc, NFI_CON,
-+                  CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
-+
-+      for (i = 0; i < nand->ecc.steps; i++) {
-+              if (buf)
-+                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
-+                                           nand->ecc.size);
-+              else
-+                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
-+
-+              rc = mt7621_ecc_decoder_wait_done(nfc, i);
-+
-+              mt7621_nfc_read_sector_fdm(nfc, i);
-+
-+              if (rc < 0) {
-+                      bitflips = -EIO;
-+                      continue;
-+              }
-+
-+              rc = mt7621_ecc_correct_check(nfc,
-+                      buf ? page_data_ptr(nand, buf, i) : NULL,
-+                      oob_fdm_ptr(nand, i), i);
-+
-+              if (rc < 0) {
-+                      dev_warn(nfc->dev,
-+                               "Uncorrectable ECC error at page %d.%d\n",
-+                               page, i);
-+                      bitflips = -EBADMSG;
-+                      mtd->ecc_stats.failed++;
-+              } else if (bitflips >= 0) {
-+                      bitflips += rc;
-+                      mtd->ecc_stats.corrected += rc;
-+              }
-+      }
-+
-+      mt7621_ecc_decoder_op(nfc, false);
-+
-+      nfi_write16(nfc, NFI_CON, 0);
-+
-+      return bitflips;
-+}
-+
-+static int mt7621_nfc_read_page_raw(struct nand_chip *nand, uint8_t *buf,
-+                                  int oob_required, int page)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      int i;
-+
-+      nand_read_page_op(nand, page, 0, NULL, 0);
-+
-+      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
-+                  CNFG_READ_MODE);
-+
-+      nfi_write16(nfc, NFI_CON,
-+                  CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
-+
-+      for (i = 0; i < nand->ecc.steps; i++) {
-+              /* Read data */
-+              if (buf)
-+                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
-+                                           nand->ecc.size);
-+              else
-+                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
-+
-+              /* Read FDM */
-+              mt7621_nfc_read_data(nfc, oob_fdm_ptr(nand, i), NFI_FDM_SIZE);
-+
-+              /* Read ECC parity data */
-+              mt7621_nfc_read_data(nfc, oob_ecc_ptr(nfc, i),
-+                                   nfc->spare_per_sector - NFI_FDM_SIZE);
-+      }
-+
-+      nfi_write16(nfc, NFI_CON, 0);
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_read_oob_hwecc(struct nand_chip *nand, int page)
-+{
-+      return mt7621_nfc_read_page_hwecc(nand, NULL, 1, page);
-+}
-+
-+static int mt7621_nfc_read_oob_raw(struct nand_chip *nand, int page)
-+{
-+      return mt7621_nfc_read_page_raw(nand, NULL, 1, page);
-+}
-+
-+static int mt7621_nfc_check_empty_page(struct nand_chip *nand, const u8 *buf)
-+{
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+      uint32_t i, j;
-+      u8 *oobptr;
-+
-+      if (buf) {
-+              for (i = 0; i < mtd->writesize; i++)
-+                      if (buf[i] != 0xff)
-+                              return 0;
-+      }
-+
-+      for (i = 0; i < nand->ecc.steps; i++) {
-+              oobptr = oob_fdm_ptr(nand, i);
-+              for (j = 0; j < NFI_FDM_SIZE; j++)
-+                      if (oobptr[j] != 0xff)
-+                              return 0;
-+      }
-+
-+      return 1;
-+}
-+
-+static int mt7621_nfc_write_page_hwecc(struct nand_chip *nand,
-+                                     const uint8_t *buf, int oob_required,
-+                                     int page)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      struct mtd_info *mtd = nand_to_mtd(nand);
-+
-+      if (mt7621_nfc_check_empty_page(nand, buf)) {
-+              /*
-+               * MT7621 ECC engine always generates parity code for input
-+               * pages, even for empty pages. Doing so will write back ECC
-+               * parity code to the oob region, which means such pages will
-+               * no longer be empty pages.
-+               *
-+               * To avoid this, stop write operation if current page is an
-+               * empty page.
-+               */
-+              return 0;
-+      }
-+
-+      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-+
-+      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
-+                 CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
-+
-+      mt7621_ecc_encoder_op(nfc, true);
-+
-+      mt7621_nfc_write_fdm(nfc);
-+
-+      nfi_write16(nfc, NFI_CON,
-+                  CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
-+
-+      if (buf)
-+              mt7621_nfc_write_data(nfc, buf, mtd->writesize);
-+      else
-+              mt7621_nfc_write_data_empty(nfc, mtd->writesize);
-+
-+      mt7621_nfc_wait_write_completion(nfc, nand);
-+
-+      mt7621_ecc_encoder_op(nfc, false);
-+
-+      nfi_write16(nfc, NFI_CON, 0);
-+
-+      return nand_prog_page_end_op(nand);
-+}
-+
-+static int mt7621_nfc_write_page_raw(struct nand_chip *nand,
-+                                   const uint8_t *buf, int oob_required,
-+                                   int page)
-+{
-+      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
-+      int i;
-+
-+      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
-+
-+      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S));
-+
-+      nfi_write16(nfc, NFI_CON,
-+                  CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
-+
-+      for (i = 0; i < nand->ecc.steps; i++) {
-+              /* Write data */
-+              if (buf)
-+                      mt7621_nfc_write_data(nfc, page_data_ptr(nand, buf, i),
-+                                            nand->ecc.size);
-+              else
-+                      mt7621_nfc_write_data_empty(nfc, nand->ecc.size);
-+
-+              /* Write FDM */
-+              mt7621_nfc_write_data(nfc, oob_fdm_ptr(nand, i),
-+                                    NFI_FDM_SIZE);
-+
-+              /* Write dummy ECC parity data */
-+              mt7621_nfc_write_data_empty(nfc, nfc->spare_per_sector -
-+                                          NFI_FDM_SIZE);
-+      }
-+
-+      mt7621_nfc_wait_write_completion(nfc, nand);
-+
-+      nfi_write16(nfc, NFI_CON, 0);
-+
-+      return nand_prog_page_end_op(nand);
-+}
-+
-+static int mt7621_nfc_write_oob_hwecc(struct nand_chip *nand, int page)
-+{
-+      return mt7621_nfc_write_page_hwecc(nand, NULL, 1, page);
-+}
-+
-+static int mt7621_nfc_write_oob_raw(struct nand_chip *nand, int page)
-+{
-+      return mt7621_nfc_write_page_raw(nand, NULL, 1, page);
-+}
-+
-+static int mt7621_nfc_init_chip(struct mt7621_nfc *nfc)
-+{
-+      struct nand_chip *nand = &nfc->nand;
-+      struct mtd_info *mtd;
-+      int ret;
-+
-+      nand->controller = &nfc->controller;
-+      nand_set_controller_data(nand, (void *)nfc);
-+      nand_set_flash_node(nand, nfc->dev->of_node);
-+
-+      nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_NO_SUBPAGE_WRITE;
-+      if (!nfc->nfi_clk)
-+              nand->options |= NAND_KEEP_TIMINGS;
-+
-+      nand->ecc.mode = NAND_ECC_HW_SYNDROME;
-+      nand->ecc.read_page = mt7621_nfc_read_page_hwecc;
-+      nand->ecc.read_page_raw = mt7621_nfc_read_page_raw;
-+      nand->ecc.write_page = mt7621_nfc_write_page_hwecc;
-+      nand->ecc.write_page_raw = mt7621_nfc_write_page_raw;
-+      nand->ecc.read_oob = mt7621_nfc_read_oob_hwecc;
-+      nand->ecc.read_oob_raw = mt7621_nfc_read_oob_raw;
-+      nand->ecc.write_oob = mt7621_nfc_write_oob_hwecc;
-+      nand->ecc.write_oob_raw = mt7621_nfc_write_oob_raw;
-+
-+      mtd = nand_to_mtd(nand);
-+      mtd->owner = THIS_MODULE;
-+      mtd->dev.parent = nfc->dev;
-+      mtd->name = MT7621_NFC_NAME;
-+      mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops);
-+
-+      mt7621_nfc_hw_init(nfc);
-+
-+      ret = nand_scan(nand, 1);
-+      if (ret)
-+              return ret;
-+
-+      ret = mtd_device_register(mtd, NULL, 0);
-+      if (ret) {
-+              dev_err(nfc->dev, "Failed to register MTD: %d\n", ret);
-+              nand_release(nand);
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static int mt7621_nfc_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct mt7621_nfc *nfc;
-+      struct resource *res;
-+      int ret;
-+
-+      nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
-+      if (!nfc)
-+              return -ENOMEM;
-+
-+      nand_controller_init(&nfc->controller);
-+      nfc->controller.ops = &mt7621_nfc_controller_ops;
-+      nfc->dev = dev;
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi");
-+      nfc->nfi_regs = devm_ioremap_resource(dev, res);
-+      if (IS_ERR(nfc->nfi_regs)) {
-+              ret = PTR_ERR(nfc->nfi_regs);
-+              return ret;
-+      }
-+
-+      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc");
-+      nfc->ecc_regs = devm_ioremap_resource(dev, res);
-+      if (IS_ERR(nfc->ecc_regs)) {
-+              ret = PTR_ERR(nfc->ecc_regs);
-+              return ret;
-+      }
-+
-+      nfc->nfi_clk = devm_clk_get(dev, "nfi_clk");
-+      if (IS_ERR(nfc->nfi_clk)) {
-+              dev_warn(dev, "nfi clk not provided\n");
-+              nfc->nfi_clk = NULL;
-+      } else {
-+              ret = clk_prepare_enable(nfc->nfi_clk);
-+              if (ret) {
-+                      dev_err(dev, "Failed to enable nfi core clock\n");
-+                      return ret;
-+              }
-+      }
-+
-+      platform_set_drvdata(pdev, nfc);
-+
-+      ret = mt7621_nfc_init_chip(nfc);
-+      if (ret) {
-+              dev_err(dev, "Failed to initialize nand chip\n");
-+              goto clk_disable;
-+      }
-+
-+      return 0;
-+
-+clk_disable:
-+      clk_disable_unprepare(nfc->nfi_clk);
-+
-+      return ret;
-+}
-+
-+static int mt7621_nfc_remove(struct platform_device *pdev)
-+{
-+      struct mt7621_nfc *nfc = platform_get_drvdata(pdev);
-+
-+      nand_release(&nfc->nand);
-+      clk_disable_unprepare(nfc->nfi_clk);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id mt7621_nfc_id_table[] = {
-+      { .compatible = "mediatek,mt7621-nfc" },
-+      { },
-+};
-+MODULE_DEVICE_TABLE(of, match);
-+
-+static struct platform_driver mt7621_nfc_driver = {
-+      .probe = mt7621_nfc_probe,
-+      .remove = mt7621_nfc_remove,
-+      .driver = {
-+              .name = MT7621_NFC_NAME,
-+              .owner = THIS_MODULE,
-+              .of_match_table = mt7621_nfc_id_table,
-+      },
-+};
-+module_platform_driver(mt7621_nfc_driver);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
-+MODULE_DESCRIPTION("MediaTek MT7621 NAND Flash Controller driver");
diff --git a/target/linux/ramips/patches-5.10/0301-dt-bindings-add-documentation-for-mt7621-nand-driver.patch b/target/linux/ramips/patches-5.10/0301-dt-bindings-add-documentation-for-mt7621-nand-driver.patch
deleted file mode 100644 (file)
index 3d122c1..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-From 3d5f4da8296b23eb3abf8b13122b0d06a215e79c Mon Sep 17 00:00:00 2001
-From: Weijie Gao <weijie.gao@mediatek.com>
-Date: Wed, 1 Apr 2020 02:07:59 +0800
-Subject: [PATCH 2/2] dt-bindings: add documentation for mt7621-nand driver
-
-This patch adds documentation for MediaTek MT7621 NAND flash controller
-driver.
-
-Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
----
- .../bindings/mtd/mediatek,mt7621-nfc.yaml          | 68 ++++++++++++++++++++++
- 1 file changed, 68 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
-@@ -0,0 +1,68 @@
-+# SPDX-License-Identifier: GPL-2.0
-+%YAML 1.2
-+---
-+$id: http://devicetree.org/schemas/mtd/mediatek,mt7621-nfc.yaml#
-+$schema: http://devicetree.org/meta-schemas/core.yaml#
-+
-+title: MediaTek MT7621 SoC NAND Flash Controller (NFC) DT binding
-+
-+maintainers:
-+  - Weijie Gao <weijie.gao@mediatek.com>
-+
-+description: |
-+  This driver uses a single node to describe both NAND Flash controller
-+  interface (NFI) and ECC engine for MT7621 SoC.
-+  MT7621 supports only one chip select.
-+
-+properties:
-+  "#address-cells": false
-+  "#size-cells": false
-+
-+  compatible:
-+    enum:
-+      - mediatek,mt7621-nfc
-+
-+  reg:
-+    items:
-+      - description: Register base of NFI core
-+      - description: Register base of ECC engine
-+
-+  reg-names:
-+    items:
-+      - const: nfi
-+      - const: ecc
-+
-+  clocks:
-+    items:
-+      - description: Source clock for NFI core, fixed 125MHz
-+
-+  clock-names:
-+    items:
-+      - const: nfi_clk
-+
-+required:
-+  - compatible
-+  - reg
-+  - reg-names
-+  - clocks
-+  - clock-names
-+
-+examples:
-+  - |
-+    nficlock: nficlock {
-+      #clock-cells = <0>;
-+      compatible = "fixed-clock";
-+
-+      clock-frequency = <125000000>;
-+    };
-+
-+    nand@1e003000 {
-+      compatible = "mediatek,mt7621-nfc";
-+
-+      reg = <0x1e003000 0x800
-+             0x1e003800 0x800>;
-+      reg-names = "nfi", "ecc";
-+
-+      clocks = <&nficlock>;
-+      clock-names = "nfi_clk";
-+    };
diff --git a/target/linux/ramips/patches-5.10/100-mt7621-core-detect-hack.patch b/target/linux/ramips/patches-5.10/100-mt7621-core-detect-hack.patch
deleted file mode 100644 (file)
index 1c8b61f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-There is a variant of MT7621 which contains only one CPU core instead of 2.
-This is not reflected in the config register, so the kernel detects more
-physical cores, which leads to a hang on SMP bringup.
-Add a hack to detect missing cores.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-
---- a/arch/mips/kernel/smp-cps.c
-+++ b/arch/mips/kernel/smp-cps.c
-@@ -43,6 +43,11 @@ static unsigned core_vpe_count(unsigned
-       return mips_cps_numvps(cluster, core);
- }
-+bool __weak plat_cpu_core_present(int core)
-+{
-+      return true;
-+}
-+
- static void __init cps_smp_setup(void)
- {
-       unsigned int nclusters, ncores, nvpes, core_vpes;
-@@ -60,6 +65,8 @@ static void __init cps_smp_setup(void)
-               ncores = mips_cps_numcores(cl);
-               for (c = 0; c < ncores; c++) {
-+                      if (!plat_cpu_core_present(c))
-+                              continue;
-                       core_vpes = core_vpe_count(cl, c);
-                       if (c > 0)
---- a/arch/mips/ralink/mt7621.c
-+++ b/arch/mips/ralink/mt7621.c
-@@ -13,6 +13,7 @@
- #include <asm/mips-cps.h>
- #include <asm/mach-ralink/ralink_regs.h>
- #include <asm/mach-ralink/mt7621.h>
-+#include <asm/mips-boards/launch.h>
- #include <pinmux.h>
-@@ -160,6 +161,20 @@ void __init ralink_of_remap(void)
-               panic("Failed to remap core resources");
- }
-+bool plat_cpu_core_present(int core)
-+{
-+      struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
-+
-+      if (!core)
-+              return true;
-+      launch += core * 2; /* 2 VPEs per core */
-+      if (!(launch->flags & LAUNCH_FREADY))
-+              return false;
-+      if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
-+              return false;
-+      return true;
-+}
-+
- void prom_soc_init(struct ralink_soc_info *soc_info)
- {
-       void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
diff --git a/target/linux/ramips/patches-5.10/101-mt7621-timer.patch b/target/linux/ramips/patches-5.10/101-mt7621-timer.patch
deleted file mode 100644 (file)
index 8528b71..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
---- a/arch/mips/ralink/mt7621.c
-+++ b/arch/mips/ralink/mt7621.c
-@@ -7,6 +7,7 @@
- #include <linux/kernel.h>
- #include <linux/init.h>
-+#include <linux/jiffies.h>
- #include <asm/mipsregs.h>
- #include <asm/smp-ops.h>
-@@ -14,6 +15,7 @@
- #include <asm/mach-ralink/ralink_regs.h>
- #include <asm/mach-ralink/mt7621.h>
- #include <asm/mips-boards/launch.h>
-+#include <asm/delay.h>
- #include <pinmux.h>
-@@ -175,6 +177,58 @@ bool plat_cpu_core_present(int core)
-       return true;
- }
-+#define LPS_PREC 8
-+/*
-+*  Re-calibration lpj(loop-per-jiffy).
-+*  (derived from kernel/calibrate.c)
-+*/
-+static int udelay_recal(void)
-+{
-+      unsigned int i, lpj = 0;
-+      unsigned long ticks, loopbit;
-+      int lps_precision = LPS_PREC;
-+
-+      lpj = (1<<12);
-+
-+      while ((lpj <<= 1) != 0) {
-+              /* wait for "start of" clock tick */
-+              ticks = jiffies;
-+              while (ticks == jiffies)
-+                      /* nothing */;
-+
-+              /* Go .. */
-+              ticks = jiffies;
-+              __delay(lpj);
-+              ticks = jiffies - ticks;
-+              if (ticks)
-+                      break;
-+      }
-+
-+      /*
-+       * Do a binary approximation to get lpj set to
-+       * equal one clock (up to lps_precision bits)
-+       */
-+      lpj >>= 1;
-+      loopbit = lpj;
-+      while (lps_precision-- && (loopbit >>= 1)) {
-+              lpj |= loopbit;
-+              ticks = jiffies;
-+              while (ticks == jiffies)
-+                      /* nothing */;
-+              ticks = jiffies;
-+              __delay(lpj);
-+              if (jiffies != ticks)   /* longer than 1 tick */
-+                      lpj &= ~loopbit;
-+      }
-+      printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
-+
-+      for(i=0; i< NR_CPUS; i++)
-+              cpu_data[i].udelay_val = lpj;
-+
-+      return 0;
-+}
-+device_initcall(udelay_recal);
-+
- void prom_soc_init(struct ralink_soc_info *soc_info)
- {
-       void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
---- a/arch/mips/ralink/Kconfig
-+++ b/arch/mips/ralink/Kconfig
-@@ -58,6 +58,7 @@ choice
-               select CLKSRC_MIPS_GIC
-               select HAVE_PCI if PCI_MT7621
-               select WEAK_REORDERING_BEYOND_LLSC
-+              select GENERIC_CLOCKEVENTS_BROADCAST
- endchoice
- choice
diff --git a/target/linux/ramips/patches-5.10/102-mt7621-fix-cpu-clk-add-clkdev.patch b/target/linux/ramips/patches-5.10/102-mt7621-fix-cpu-clk-add-clkdev.patch
deleted file mode 100644 (file)
index 0c997a3..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
---- a/arch/mips/include/asm/mach-ralink/mt7621.h
-+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
-@@ -17,6 +17,10 @@
- #define SYSC_REG_CHIP_REV             0x0c
- #define SYSC_REG_SYSTEM_CONFIG0               0x10
- #define SYSC_REG_SYSTEM_CONFIG1               0x14
-+#define SYSC_REG_CLKCFG0              0x2c
-+#define SYSC_REG_CUR_CLK_STS          0x44
-+
-+#define MEMC_REG_CPU_PLL              0x648
- #define CHIP_REV_PKG_MASK             0x1
- #define CHIP_REV_PKG_SHIFT            16
-@@ -24,6 +28,22 @@
- #define CHIP_REV_VER_SHIFT            8
- #define CHIP_REV_ECO_MASK             0xf
-+#define XTAL_MODE_SEL_MASK            0x7
-+#define XTAL_MODE_SEL_SHIFT           6
-+
-+#define CPU_CLK_SEL_MASK              0x3
-+#define CPU_CLK_SEL_SHIFT             30
-+
-+#define CUR_CPU_FDIV_MASK             0x1f
-+#define CUR_CPU_FDIV_SHIFT            8
-+#define CUR_CPU_FFRAC_MASK            0x1f
-+#define CUR_CPU_FFRAC_SHIFT           0
-+
-+#define CPU_PLL_PREDIV_MASK           0x3
-+#define CPU_PLL_PREDIV_SHIFT          12
-+#define CPU_PLL_FBDIV_MASK            0x7f
-+#define CPU_PLL_FBDIV_SHIFT           4
-+
- #define MT7621_DRAM_BASE                0x0
- #define MT7621_DDR2_SIZE_MIN          32
- #define MT7621_DDR2_SIZE_MAX          256
---- a/arch/mips/ralink/mt7621.c
-+++ b/arch/mips/ralink/mt7621.c
-@@ -8,6 +8,10 @@
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/jiffies.h>
-+#include <linux/clk.h>
-+#include <linux/clkdev.h>
-+#include <linux/clk-provider.h>
-+#include <dt-bindings/clock/mt7621-clk.h>
- #include <asm/mipsregs.h>
- #include <asm/smp-ops.h>
-@@ -16,16 +20,12 @@
- #include <asm/mach-ralink/mt7621.h>
- #include <asm/mips-boards/launch.h>
- #include <asm/delay.h>
-+#include <asm/time.h>
- #include <pinmux.h>
- #include "common.h"
--#define SYSC_REG_SYSCFG               0x10
--#define SYSC_REG_CPLL_CLKCFG0 0x2c
--#define SYSC_REG_CUR_CLK_STS  0x44
--#define CPU_CLK_SEL           (BIT(30) | BIT(31))
--
- #define MT7621_GPIO_MODE_UART1                1
- #define MT7621_GPIO_MODE_I2C          2
- #define MT7621_GPIO_MODE_UART3_MASK   0x3
-@@ -111,49 +111,89 @@ static struct rt2880_pmx_group mt7621_pi
-       { 0 }
- };
-+static struct clk *clks[MT7621_CLK_MAX];
-+static struct clk_onecell_data clk_data = {
-+      .clks = clks,
-+      .clk_num = ARRAY_SIZE(clks),
-+};
-+
- phys_addr_t mips_cpc_default_phys_base(void)
- {
-       panic("Cannot detect cpc address");
- }
--void __init ralink_clk_init(void)
-+static struct clk *__init mt7621_add_sys_clkdev(
-+      const char *id, unsigned long rate)
- {
--      int cpu_fdiv = 0;
--      int cpu_ffrac = 0;
--      int fbdiv = 0;
--      u32 clk_sts, syscfg;
--      u8 clk_sel = 0, xtal_mode;
--      u32 cpu_clk;
-+      struct clk *clk;
-+      int err;
-+
-+      clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate);
-+      if (IS_ERR(clk))
-+              panic("failed to allocate %s clock structure", id);
-+
-+      err = clk_register_clkdev(clk, id, NULL);
-+      if (err)
-+              panic("unable to register %s clock device", id);
--      if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0)
--              clk_sel = 1;
-+      return clk;
-+}
-+
-+void __init ralink_clk_init(void)
-+{
-+      u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
-+      u32 pll, prediv, fbdiv;
-+      u32 xtal_clk, cpu_clk, bus_clk;
-+      const static u32 prediv_tbl[] = {0, 1, 2, 2};
-+
-+      syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
-+      xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
-+
-+      clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0);
-+      clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK;
-+
-+      curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
-+      ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK;
-+      ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK;
-+
-+      if (xtal_sel <= 2)
-+              xtal_clk = 20 * 1000 * 1000;
-+      else if (xtal_sel <= 5)
-+              xtal_clk = 40 * 1000 * 1000;
-+      else
-+              xtal_clk = 25 * 1000 * 1000;
-       switch (clk_sel) {
-       case 0:
--              clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
--              cpu_fdiv = ((clk_sts >> 8) & 0x1F);
--              cpu_ffrac = (clk_sts & 0x1F);
--              cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000;
-+              cpu_clk = 500 * 1000 * 1000;
-               break;
--
-       case 1:
--              fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1;
--              syscfg = rt_sysc_r32(SYSC_REG_SYSCFG);
--              xtal_mode = (syscfg >> 6) & 0x7;
--              if (xtal_mode >= 6) {
--                      /* 25Mhz Xtal */
--                      cpu_clk = 25 * fbdiv * 1000 * 1000;
--              } else if (xtal_mode >= 3) {
--                      /* 40Mhz Xtal */
--                      cpu_clk = 40 * fbdiv * 1000 * 1000;
--              } else {
--                      /* 20Mhz Xtal */
--                      cpu_clk = 20 * fbdiv * 1000 * 1000;
--              }
-+              pll = rt_memc_r32(MEMC_REG_CPU_PLL);
-+              fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK;
-+              prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK;
-+              cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv];
-               break;
-+      default:
-+              cpu_clk = xtal_clk;
-       }
-+
-+      cpu_clk = cpu_clk / ffiv * ffrac;
-+      bus_clk = cpu_clk / 4;
-+
-+      clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", cpu_clk);
-+      clks[MT7621_CLK_BUS] = mt7621_add_sys_clkdev("bus", bus_clk);
-+
-+      pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000);
-+      mips_hpt_frequency = cpu_clk / 2;
- }
-+static void __init mt7621_clocks_init_dt(struct device_node *np)
-+{
-+      of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
-+}
-+
-+CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt);
-+
- void __init ralink_of_remap(void)
- {
-       rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
---- a/arch/mips/ralink/timer-gic.c
-+++ b/arch/mips/ralink/timer-gic.c
-@@ -9,14 +9,14 @@
- #include <linux/of.h>
- #include <linux/clk-provider.h>
--#include <linux/clocksource.h>
-+#include <asm/time.h>
- #include "common.h"
- void __init plat_time_init(void)
- {
-       ralink_of_remap();
--
-+      ralink_clk_init();
-       of_clk_init(NULL);
-       timer_probe();
- }
---- /dev/null
-+++ b/include/dt-bindings/clock/mt7621-clk.h
-@@ -0,0 +1,18 @@
-+/*
-+ * Copyright (C) 2018 Weijie Gao <hackpascal@gmail.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#ifndef __DT_BINDINGS_MT7621_CLK_H
-+#define __DT_BINDINGS_MT7621_CLK_H
-+
-+#define MT7621_CLK_CPU                0
-+#define MT7621_CLK_BUS                1
-+
-+#define MT7621_CLK_MAX                2
-+
-+#endif /* __DT_BINDINGS_MT7621_CLK_H */
diff --git a/target/linux/ramips/patches-5.10/105-mt7621-memory-detect.patch b/target/linux/ramips/patches-5.10/105-mt7621-memory-detect.patch
deleted file mode 100644 (file)
index 08b4b0d..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-From b5a52351a66f3c2a7a207548aa87d78ff2d336c0 Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Wed, 10 Jul 2019 00:24:48 +0800
-Subject: [PATCH] MIPS: ralink: mt7621: add memory detection support
-
-mt7621 has the following memory map:
-0x0-0x1c000000: lower 448m memory
-0x1c000000-0x2000000: peripheral registers
-0x20000000-0x2400000: higher 64m memory
-
-detect_memory_region in arch/mips/kernel/setup.c only add the first
-memory region and isn't suitable for 512m memory detection because
-it may accidentally read the memory area for peripheral registers.
-
-This commit adds memory detection capability for mt7621:
-1. add the highmem area when 512m is detected.
-2. guard memcmp from accessing peripheral registers:
-     This only happens when some weird user decided to change
-     kernel load address to 256m or higher address. Since this
-     is a quite unusual case, we just skip 512m testing and return
-     256m as memory size.
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- arch/mips/include/asm/mach-ralink/mt7621.h |  7 ++---
- arch/mips/ralink/mt7621.c                  | 30 +++++++++++++++++++---
- 2 files changed, 30 insertions(+), 7 deletions(-)
-
---- a/arch/mips/include/asm/mach-ralink/mt7621.h
-+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
-@@ -44,9 +44,10 @@
- #define CPU_PLL_FBDIV_MASK            0x7f
- #define CPU_PLL_FBDIV_SHIFT           4
--#define MT7621_DRAM_BASE                0x0
--#define MT7621_DDR2_SIZE_MIN          32
--#define MT7621_DDR2_SIZE_MAX          256
-+#define MT7621_LOWMEM_BASE            0x0
-+#define MT7621_LOWMEM_MAX_SIZE                0x1C000000
-+#define MT7621_HIGHMEM_BASE           0x20000000
-+#define MT7621_HIGHMEM_SIZE           0x4000000
- #define MT7621_CHIP_NAME0             0x3637544D
- #define MT7621_CHIP_NAME1             0x20203132
---- a/arch/mips/ralink/mt7621.c
-+++ b/arch/mips/ralink/mt7621.c
-@@ -13,6 +13,7 @@
- #include <linux/clk-provider.h>
- #include <dt-bindings/clock/mt7621-clk.h>
-+#include <asm/bootinfo.h>
- #include <asm/mipsregs.h>
- #include <asm/smp-ops.h>
- #include <asm/mips-cps.h>
-@@ -55,6 +56,8 @@
- #define MT7621_GPIO_MODE_SDHCI_SHIFT  18
- #define MT7621_GPIO_MODE_SDHCI_GPIO   1
-+static void *detect_magic __initdata = detect_memory_region;
-+
- 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[] = {
-@@ -139,6 +142,28 @@ static struct clk *__init mt7621_add_sys
-       return clk;
- }
-+void __init mt7621_memory_detect(void)
-+{
-+      void *dm = &detect_magic;
-+      phys_addr_t size;
-+
-+      for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) {
-+              if (!memcmp(dm, dm + size, sizeof(detect_magic)))
-+                      break;
-+      }
-+
-+      if ((size == 256 * SZ_1M) &&
-+          (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) &&
-+          memcmp(dm, dm + size, sizeof(detect_magic))) {
-+              add_memory_region(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE,
-+                                BOOT_MEM_RAM);
-+              add_memory_region(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE,
-+                                BOOT_MEM_RAM);
-+      } else {
-+              add_memory_region(MT7621_LOWMEM_BASE, size, BOOT_MEM_RAM);
-+      }
-+}
-+
- void __init ralink_clk_init(void)
- {
-       u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
-@@ -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));
--      soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN;
--      soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX;
--      soc_info->mem_base = MT7621_DRAM_BASE;
--
-+      soc_info->mem_detect = mt7621_memory_detect;
-       rt2880_pinmux_data = mt7621_pinmux_data;
---- a/arch/mips/ralink/common.h
-+++ b/arch/mips/ralink/common.h
-@@ -17,6 +17,7 @@ struct ralink_soc_info {
-       unsigned long mem_size;
-       unsigned long mem_size_min;
-       unsigned long mem_size_max;
-+      void (*mem_detect)(void);
- };
- extern struct ralink_soc_info soc_info;
---- a/arch/mips/ralink/of.c
-+++ b/arch/mips/ralink/of.c
-@@ -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);
-+      else if (soc_info.mem_detect)
-+              soc_info.mem_detect();
-       else if (soc_info.mem_size)
-               add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M,
-                                 BOOT_MEM_RAM);
diff --git a/target/linux/ramips/patches-5.10/110-mt7621-perfctr-fix.patch b/target/linux/ramips/patches-5.10/110-mt7621-perfctr-fix.patch
deleted file mode 100644 (file)
index dfeac7e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/arch/mips/ralink/irq-gic.c
-+++ b/arch/mips/ralink/irq-gic.c
-@@ -13,6 +13,12 @@
- int get_c0_perfcount_int(void)
- {
-+      /*
-+       * Performance counter events are routed through GIC.
-+       * Prevent them from firing on CPU IRQ7 as well
-+       */
-+      clear_c0_status(IE_SW0 << 7);
-+
-       return gic_get_c0_perfcount_int();
- }
- EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
diff --git a/target/linux/ramips/patches-5.10/202-weak_reordering.patch b/target/linux/ramips/patches-5.10/202-weak_reordering.patch
new file mode 100644 (file)
index 0000000..fe3fdec
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -57,6 +57,7 @@ choice
+               select COMMON_CLK
+               select CLKSRC_MIPS_GIC
+               select HAVE_PCI if PCI_MT7621
++              select WEAK_REORDERING_BEYOND_LLSC
+ endchoice
+ choice
diff --git a/target/linux/ramips/patches-5.10/302-spi-nor-add-gd25q512.patch b/target/linux/ramips/patches-5.10/302-spi-nor-add-gd25q512.patch
deleted file mode 100644 (file)
index 7fcf0c5..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
---- a/drivers/mtd/spi-nor/spi-nor.c
-+++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -2303,6 +2303,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,
-+                      SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
-+                      SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES)
-+      },
-       /* Intel/Numonyx -- xxxs33b */
-       { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
diff --git a/target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch b/target/linux/ramips/patches-5.10/310-MIPS-Fix-memory-reservation-in-bootmem_init-for-cert.patch
new file mode 100644 (file)
index 0000000..63429f4
--- /dev/null
@@ -0,0 +1,45 @@
+From: Tobias Wolf <dev-NTEO@vplace.de>
+Subject: [v2] MIPS: Fix memory reservation in bootmem_init for certain non-usermem setups
+
+Commit 67a3ba25aa95 ("MIPS: Fix incorrect mem=X@Y handling") introduced a new
+issue for rt288x where "PHYS_OFFSET" is 0x0 but the calculated "ramstart" is
+not. As the prerequisite of custom memory map has been removed, this results
+in the full memory range of 0x0 - 0x8000000 to be marked as reserved for this
+platform.
+
+v2: Correctly compare that usermem is not null.
+
+This patch adds the originally intended prerequisite again.
+
+Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
+---
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -287,6 +287,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)
+@@ -325,7 +327,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)
+               memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
+       if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
+@@ -386,8 +388,6 @@ static void __init bootmem_init(void)
+ #endif        /* CONFIG_SGI_IP27 */
+-static int usermem __initdata;
+-
+ static int __init early_parse_mem(char *p)
+ {
+       phys_addr_t start, size;
diff --git a/target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch b/target/linux/ramips/patches-5.10/311-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch
new file mode 100644 (file)
index 0000000..773c74f
--- /dev/null
@@ -0,0 +1,82 @@
+From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 14 Jul 2013 23:08:11 +0200
+Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
+ irq
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -1,12 +1,17 @@
+ # SPDX-License-Identifier: GPL-2.0
+ if RALINK
++config CEVT_SYSTICK_QUIRK
++      bool
++      default n
++
+ config CLKEVT_RT3352
+       bool
+       depends on SOC_RT305X || SOC_MT7620
+       default y
+       select TIMER_OF
+       select CLKSRC_MMIO
++      select CEVT_SYSTICK_QUIRK
+ config RALINK_ILL_ACC
+       bool
+--- a/arch/mips/kernel/cevt-r4k.c
++++ b/arch/mips/kernel/cevt-r4k.c
+@@ -15,6 +15,26 @@
+ #include <asm/time.h>
+ #include <asm/cevt-r4k.h>
++static int mips_state_oneshot(struct clock_event_device *evt)
++{
++      if (!cp0_timer_irq_installed) {
++              cp0_timer_irq_installed = 1;
++              setup_irq(evt->irq, &c0_compare_irqaction);
++      }
++
++      return 0;
++}
++
++static int mips_state_shutdown(struct clock_event_device *evt)
++{
++      if (cp0_timer_irq_installed) {
++              cp0_timer_irq_installed = 0;
++              remove_irq(evt->irq, &c0_compare_irqaction);
++      }
++
++      return 0;
++}
++
+ static int mips_next_event(unsigned long delta,
+                          struct clock_event_device *evt)
+ {
+@@ -281,17 +301,21 @@ int r4k_clockevent_init(void)
+       cd->rating              = 300;
+       cd->irq                 = irq;
+       cd->cpumask             = cpumask_of(cpu);
++      cd->set_state_shutdown  = mips_state_shutdown;
++      cd->set_state_oneshot   = mips_state_oneshot;
+       cd->set_next_event      = mips_next_event;
+       cd->event_handler       = mips_event_handler;
+       clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
++#ifndef CONFIG_CEVT_SYSTICK_QUIRK
+       if (cp0_timer_irq_installed)
+               return 0;
+       cp0_timer_irq_installed = 1;
+       setup_irq(irq, &c0_compare_irqaction);
++#endif
+       return 0;
+ }
diff --git a/target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch b/target/linux/ramips/patches-5.10/312-MIPS-ralink-add-cpu-frequency-scaling.patch
new file mode 100644 (file)
index 0000000..a3b8e4d
--- /dev/null
@@ -0,0 +1,200 @@
+From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 28 Jul 2013 16:26:41 +0200
+Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
+
+This feature will break udelay() and cause the delay loop to have longer delays
+when the frequency is scaled causing a performance hit.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/cevt-rt3352.c |   38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/arch/mips/ralink/cevt-rt3352.c
++++ b/arch/mips/ralink/cevt-rt3352.c
+@@ -29,6 +29,10 @@
+ /* enable the counter */
+ #define CFG_CNT_EN            0x1
++/* mt7620 frequency scaling defines */
++#define CLK_LUT_CFG   0x40
++#define SLEEP_EN      BIT(31)
++
+ struct systick_device {
+       void __iomem *membase;
+       struct clock_event_device dev;
+@@ -36,21 +40,53 @@ struct systick_device {
+       int freq_scale;
+ };
++static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
++
+ static int systick_set_oneshot(struct clock_event_device *evt);
+ static int systick_shutdown(struct clock_event_device *evt);
++static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
++{
++      if (sdev->freq_scale == status)
++              return;
++
++      sdev->freq_scale = status;
++
++      pr_info("%s: %s autosleep mode\n", sdev->dev.name,
++                      (status) ? ("enable") : ("disable"));
++      if (status)
++              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
++      else
++              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
++}
++
++static inline unsigned int read_count(struct systick_device *sdev)
++{
++      return ioread32(sdev->membase + SYSTICK_COUNT);
++}
++
++static inline unsigned int read_compare(struct systick_device *sdev)
++{
++      return ioread32(sdev->membase + SYSTICK_COMPARE);
++}
++
++static inline void write_compare(struct systick_device *sdev, unsigned int val)
++{
++      iowrite32(val, sdev->membase + SYSTICK_COMPARE);
++}
++
+ static int systick_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+ {
+       struct systick_device *sdev;
+-      u32 count;
++      int res;
+       sdev = container_of(evt, struct systick_device, dev);
+-      count = ioread32(sdev->membase + SYSTICK_COUNT);
+-      count = (count + delta) % SYSTICK_FREQ;
+-      iowrite32(count, sdev->membase + SYSTICK_COMPARE);
++      delta += read_count(sdev);
++      write_compare(sdev, delta);
++      res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
+-      return 0;
++      return res;
+ }
+ static void systick_event_handler(struct clock_event_device *dev)
+@@ -60,20 +96,25 @@ static void systick_event_handler(struct
+ static irqreturn_t systick_interrupt(int irq, void *dev_id)
+ {
+-      struct clock_event_device *dev = (struct clock_event_device *) dev_id;
++      int ret = 0;
++      struct clock_event_device *cdev;
++      struct systick_device *sdev;
+-      dev->event_handler(dev);
++      if (read_c0_cause() & STATUSF_IP7) {
++              cdev = (struct clock_event_device *) dev_id;
++              sdev = container_of(cdev, struct systick_device, dev);
++
++              /* Clear Count/Compare Interrupt */
++              write_compare(sdev, read_compare(sdev));
++              cdev->event_handler(cdev);
++              ret = 1;
++      }
+-      return IRQ_HANDLED;
++      return IRQ_RETVAL(ret);
+ }
+ static struct systick_device systick = {
+       .dev = {
+-              /*
+-               * cevt-r4k uses 300, make sure systick
+-               * gets used if available
+-               */
+-              .rating                 = 310,
+               .features               = CLOCK_EVT_FEAT_ONESHOT,
+               .set_next_event         = systick_next_event,
+               .set_state_shutdown     = systick_shutdown,
+@@ -95,9 +136,15 @@ static int systick_shutdown(struct clock
+       sdev = container_of(evt, struct systick_device, dev);
+       if (sdev->irq_requested)
+-              free_irq(systick.dev.irq, &systick_irqaction);
++              remove_irq(systick.dev.irq, &systick_irqaction);
+       sdev->irq_requested = 0;
+-      iowrite32(0, systick.membase + SYSTICK_CONFIG);
++      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
++
++      if (systick_freq_scaling)
++              systick_freq_scaling(sdev, 0);
++
++      if (systick_freq_scaling)
++              systick_freq_scaling(sdev, 1);
+       return 0;
+ }
+@@ -117,34 +164,48 @@ static int systick_set_oneshot(struct cl
+       return 0;
+ }
++static const struct of_device_id systick_match[] = {
++      { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
++      {},
++};
++
+ static int __init ralink_systick_init(struct device_node *np)
+ {
++      const struct of_device_id *match;
++      int rating = 200;
+       int ret;
+       systick.membase = of_iomap(np, 0);
+       if (!systick.membase)
+               return -ENXIO;
+-      systick_irqaction.name = np->name;
+-      systick.dev.name = np->name;
+-      clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
+-      systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+-      systick.dev.max_delta_ticks = 0x7fff;
+-      systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+-      systick.dev.min_delta_ticks = 0x3;
++      match = of_match_node(systick_match, np);
++      if (match) {
++              systick_freq_scaling = match->data;
++              /*
++               * cevt-r4k uses 300, make sure systick
++               * gets used if available
++               */
++              rating = 310;
++      }
++
++      /* enable counter than register clock source */
++      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
++      clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
++                      SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
++
++      /* register clock event */
+       systick.dev.irq = irq_of_parse_and_map(np, 0);
+       if (!systick.dev.irq) {
+               pr_err("%pOFn: request_irq failed", np);
+               return -EINVAL;
+       }
+-      ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+-                                  SYSTICK_FREQ, 301, 16,
+-                                  clocksource_mmio_readl_up);
+-      if (ret)
+-              return ret;
+-
+-      clockevents_register_device(&systick.dev);
++      systick_irqaction.name = np->name;
++      systick.dev.name = np->name;
++      systick.dev.rating = rating;
++      systick.dev.cpumask = cpumask_of(0);
++      clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
+       pr_info("%pOFn: running - mult: %d, shift: %d\n",
+                       np, systick.dev.mult, systick.dev.shift);
diff --git a/target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-5.10/313-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
new file mode 100644 (file)
index 0000000..54af571
--- /dev/null
@@ -0,0 +1,21 @@
+From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Aug 2014 18:46:02 +0200
+Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/of.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -80,6 +80,8 @@ void __init plat_mem_setup(void)
+       __dt_setup_arch(dtb);
++      strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
++
+       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.10/314-MIPS-add-bootargs-override-property.patch b/target/linux/ramips/patches-5.10/314-MIPS-add-bootargs-override-property.patch
new file mode 100644 (file)
index 0000000..c19a0fb
--- /dev/null
@@ -0,0 +1,63 @@
+From f15d27f9c90ede4b16eb37f9ae573ef81c2b6996 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Thu, 31 Dec 2020 18:49:12 +0100
+Subject: [PATCH] MIPS: add bootargs-override property
+
+Add support for the bootargs-override property to the chosen node
+similar to the one used on ipq806x or mpc85xx.
+
+This is necessary, as the U-Boot used on some boards, notably the
+Ubiquiti UniFi 6 Lite, overwrite the bootargs property of the chosen
+node leading to a kernel panic when loading OpenWrt.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ arch/mips/kernel/setup.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -571,8 +571,28 @@ static int __init bootcmdline_scan_chose
+       return 1;
+ }
++static int __init bootcmdline_scan_chosen_override(unsigned long node, const char *uname,
++                                                 int depth, void *data)
++{
++      bool *dt_bootargs = data;
++      const char *p;
++      int l;
++
++      if (depth != 1 || !data || strcmp(uname, "chosen") != 0)
++              return 0;
++
++      p = of_get_flat_dt_prop(node, "bootargs-override", &l);
++      if (p != NULL && l > 0) {
++              strlcpy(boot_command_line, p, COMMAND_LINE_SIZE);
++              *dt_bootargs = true;
++      }
++
++      return 1;
++}
++
+ static void __init bootcmdline_init(char **cmdline_p)
+ {
++      bool dt_bootargs_override = false;
+       bool dt_bootargs = false;
+       /*
+@@ -586,6 +606,14 @@ static void __init bootcmdline_init(char
+       }
+       /*
++       * If bootargs-override in the chosen node is set, use this as the
++       * command line
++       */
++      of_scan_flat_dt(bootcmdline_scan_chosen_override, &dt_bootargs_override);
++      if (dt_bootargs_override)
++              return;
++
++      /*
+        * If the user specified a built-in command line &
+        * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
+        * prepended to arguments from the bootloader or DT so we'll copy them
diff --git a/target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-5.10/315-owrt-hack-fix-mt7688-cache-issue.patch
new file mode 100644 (file)
index 0000000..bedea14
--- /dev/null
@@ -0,0 +1,29 @@
+From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:15:32 +0100
+Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/kernel/setup.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -723,8 +723,6 @@ static void __init arch_mem_init(char **
+               memblock_reserve(crashk_res.start,
+                                crashk_res.end - crashk_res.start + 1);
+ #endif
+-      device_tree_init();
+-
+       /*
+        * In order to reduce the possibility of kernel panic when failed to
+        * get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
+@@ -841,6 +839,7 @@ void __init setup_arch(char **cmdline_p)
+       cpu_cache_init();
+       paging_init();
++      device_tree_init();
+ }
+ unsigned long kernelsp[NR_CPUS];
diff --git a/target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch b/target/linux/ramips/patches-5.10/316-arch-mips-do-not-select-illegal-access-driver-by-def.patch
new file mode 100644 (file)
index 0000000..1dc54cc
--- /dev/null
@@ -0,0 +1,25 @@
+From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:18:05 +0100
+Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
+ default
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -14,9 +14,9 @@ config CLKEVT_RT3352
+       select CEVT_SYSTICK_QUIRK
+ config RALINK_ILL_ACC
+-      bool
++      bool "illegal access irq"
+       depends on SOC_RT305X
+-      default y
++      default n
+ config IRQ_INTC
+       bool
diff --git a/target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch b/target/linux/ramips/patches-5.10/320-mt7621-core-detect-hack.patch
new file mode 100644 (file)
index 0000000..1c8b61f
--- /dev/null
@@ -0,0 +1,61 @@
+There is a variant of MT7621 which contains only one CPU core instead of 2.
+This is not reflected in the config register, so the kernel detects more
+physical cores, which leads to a hang on SMP bringup.
+Add a hack to detect missing cores.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/arch/mips/kernel/smp-cps.c
++++ b/arch/mips/kernel/smp-cps.c
+@@ -43,6 +43,11 @@ static unsigned core_vpe_count(unsigned
+       return mips_cps_numvps(cluster, core);
+ }
++bool __weak plat_cpu_core_present(int core)
++{
++      return true;
++}
++
+ static void __init cps_smp_setup(void)
+ {
+       unsigned int nclusters, ncores, nvpes, core_vpes;
+@@ -60,6 +65,8 @@ static void __init cps_smp_setup(void)
+               ncores = mips_cps_numcores(cl);
+               for (c = 0; c < ncores; c++) {
++                      if (!plat_cpu_core_present(c))
++                              continue;
+                       core_vpes = core_vpe_count(cl, c);
+                       if (c > 0)
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -13,6 +13,7 @@
+ #include <asm/mips-cps.h>
+ #include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7621.h>
++#include <asm/mips-boards/launch.h>
+ #include <pinmux.h>
+@@ -160,6 +161,20 @@ void __init ralink_of_remap(void)
+               panic("Failed to remap core resources");
+ }
++bool plat_cpu_core_present(int core)
++{
++      struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
++
++      if (!core)
++              return true;
++      launch += core * 2; /* 2 VPEs per core */
++      if (!(launch->flags & LAUNCH_FREADY))
++              return false;
++      if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
++              return false;
++      return true;
++}
++
+ void prom_soc_init(struct ralink_soc_info *soc_info)
+ {
+       void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
diff --git a/target/linux/ramips/patches-5.10/321-mt7621-timer.patch b/target/linux/ramips/patches-5.10/321-mt7621-timer.patch
new file mode 100644 (file)
index 0000000..8528b71
--- /dev/null
@@ -0,0 +1,87 @@
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -7,6 +7,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
++#include <linux/jiffies.h>
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+@@ -14,6 +15,7 @@
+ #include <asm/mach-ralink/ralink_regs.h>
+ #include <asm/mach-ralink/mt7621.h>
+ #include <asm/mips-boards/launch.h>
++#include <asm/delay.h>
+ #include <pinmux.h>
+@@ -175,6 +177,58 @@ bool plat_cpu_core_present(int core)
+       return true;
+ }
++#define LPS_PREC 8
++/*
++*  Re-calibration lpj(loop-per-jiffy).
++*  (derived from kernel/calibrate.c)
++*/
++static int udelay_recal(void)
++{
++      unsigned int i, lpj = 0;
++      unsigned long ticks, loopbit;
++      int lps_precision = LPS_PREC;
++
++      lpj = (1<<12);
++
++      while ((lpj <<= 1) != 0) {
++              /* wait for "start of" clock tick */
++              ticks = jiffies;
++              while (ticks == jiffies)
++                      /* nothing */;
++
++              /* Go .. */
++              ticks = jiffies;
++              __delay(lpj);
++              ticks = jiffies - ticks;
++              if (ticks)
++                      break;
++      }
++
++      /*
++       * Do a binary approximation to get lpj set to
++       * equal one clock (up to lps_precision bits)
++       */
++      lpj >>= 1;
++      loopbit = lpj;
++      while (lps_precision-- && (loopbit >>= 1)) {
++              lpj |= loopbit;
++              ticks = jiffies;
++              while (ticks == jiffies)
++                      /* nothing */;
++              ticks = jiffies;
++              __delay(lpj);
++              if (jiffies != ticks)   /* longer than 1 tick */
++                      lpj &= ~loopbit;
++      }
++      printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
++
++      for(i=0; i< NR_CPUS; i++)
++              cpu_data[i].udelay_val = lpj;
++
++      return 0;
++}
++device_initcall(udelay_recal);
++
+ void prom_soc_init(struct ralink_soc_info *soc_info)
+ {
+       void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -58,6 +58,7 @@ choice
+               select CLKSRC_MIPS_GIC
+               select HAVE_PCI if PCI_MT7621
+               select WEAK_REORDERING_BEYOND_LLSC
++              select GENERIC_CLOCKEVENTS_BROADCAST
+ endchoice
+ choice
diff --git a/target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch b/target/linux/ramips/patches-5.10/322-mt7621-fix-cpu-clk-add-clkdev.patch
new file mode 100644 (file)
index 0000000..0c997a3
--- /dev/null
@@ -0,0 +1,224 @@
+--- a/arch/mips/include/asm/mach-ralink/mt7621.h
++++ b/arch/mips/include/asm/mach-ralink/mt7621.h
+@@ -17,6 +17,10 @@
+ #define SYSC_REG_CHIP_REV             0x0c
+ #define SYSC_REG_SYSTEM_CONFIG0               0x10
+ #define SYSC_REG_SYSTEM_CONFIG1               0x14
++#define SYSC_REG_CLKCFG0              0x2c
++#define SYSC_REG_CUR_CLK_STS          0x44
++
++#define MEMC_REG_CPU_PLL              0x648
+ #define CHIP_REV_PKG_MASK             0x1
+ #define CHIP_REV_PKG_SHIFT            16
+@@ -24,6 +28,22 @@
+ #define CHIP_REV_VER_SHIFT            8
+ #define CHIP_REV_ECO_MASK             0xf
++#define XTAL_MODE_SEL_MASK            0x7
++#define XTAL_MODE_SEL_SHIFT           6
++
++#define CPU_CLK_SEL_MASK              0x3
++#define CPU_CLK_SEL_SHIFT             30
++
++#define CUR_CPU_FDIV_MASK             0x1f
++#define CUR_CPU_FDIV_SHIFT            8
++#define CUR_CPU_FFRAC_MASK            0x1f
++#define CUR_CPU_FFRAC_SHIFT           0
++
++#define CPU_PLL_PREDIV_MASK           0x3
++#define CPU_PLL_PREDIV_SHIFT          12
++#define CPU_PLL_FBDIV_MASK            0x7f
++#define CPU_PLL_FBDIV_SHIFT           4
++
+ #define MT7621_DRAM_BASE                0x0
+ #define MT7621_DDR2_SIZE_MIN          32
+ #define MT7621_DDR2_SIZE_MAX          256
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -8,6 +8,10 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/jiffies.h>
++#include <linux/clk.h>
++#include <linux/clkdev.h>
++#include <linux/clk-provider.h>
++#include <dt-bindings/clock/mt7621-clk.h>
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+@@ -16,16 +20,12 @@
+ #include <asm/mach-ralink/mt7621.h>
+ #include <asm/mips-boards/launch.h>
+ #include <asm/delay.h>
++#include <asm/time.h>
+ #include <pinmux.h>
+ #include "common.h"
+-#define SYSC_REG_SYSCFG               0x10
+-#define SYSC_REG_CPLL_CLKCFG0 0x2c
+-#define SYSC_REG_CUR_CLK_STS  0x44
+-#define CPU_CLK_SEL           (BIT(30) | BIT(31))
+-
+ #define MT7621_GPIO_MODE_UART1                1
+ #define MT7621_GPIO_MODE_I2C          2
+ #define MT7621_GPIO_MODE_UART3_MASK   0x3
+@@ -111,49 +111,89 @@ static struct rt2880_pmx_group mt7621_pi
+       { 0 }
+ };
++static struct clk *clks[MT7621_CLK_MAX];
++static struct clk_onecell_data clk_data = {
++      .clks = clks,
++      .clk_num = ARRAY_SIZE(clks),
++};
++
+ phys_addr_t mips_cpc_default_phys_base(void)
+ {
+       panic("Cannot detect cpc address");
+ }
+-void __init ralink_clk_init(void)
++static struct clk *__init mt7621_add_sys_clkdev(
++      const char *id, unsigned long rate)
+ {
+-      int cpu_fdiv = 0;
+-      int cpu_ffrac = 0;
+-      int fbdiv = 0;
+-      u32 clk_sts, syscfg;
+-      u8 clk_sel = 0, xtal_mode;
+-      u32 cpu_clk;
++      struct clk *clk;
++      int err;
++
++      clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate);
++      if (IS_ERR(clk))
++              panic("failed to allocate %s clock structure", id);
++
++      err = clk_register_clkdev(clk, id, NULL);
++      if (err)
++              panic("unable to register %s clock device", id);
+-      if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0)
+-              clk_sel = 1;
++      return clk;
++}
++
++void __init ralink_clk_init(void)
++{
++      u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
++      u32 pll, prediv, fbdiv;
++      u32 xtal_clk, cpu_clk, bus_clk;
++      const static u32 prediv_tbl[] = {0, 1, 2, 2};
++
++      syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
++      xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
++
++      clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0);
++      clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK;
++
++      curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
++      ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK;
++      ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK;
++
++      if (xtal_sel <= 2)
++              xtal_clk = 20 * 1000 * 1000;
++      else if (xtal_sel <= 5)
++              xtal_clk = 40 * 1000 * 1000;
++      else
++              xtal_clk = 25 * 1000 * 1000;
+       switch (clk_sel) {
+       case 0:
+-              clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
+-              cpu_fdiv = ((clk_sts >> 8) & 0x1F);
+-              cpu_ffrac = (clk_sts & 0x1F);
+-              cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000;
++              cpu_clk = 500 * 1000 * 1000;
+               break;
+-
+       case 1:
+-              fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1;
+-              syscfg = rt_sysc_r32(SYSC_REG_SYSCFG);
+-              xtal_mode = (syscfg >> 6) & 0x7;
+-              if (xtal_mode >= 6) {
+-                      /* 25Mhz Xtal */
+-                      cpu_clk = 25 * fbdiv * 1000 * 1000;
+-              } else if (xtal_mode >= 3) {
+-                      /* 40Mhz Xtal */
+-                      cpu_clk = 40 * fbdiv * 1000 * 1000;
+-              } else {
+-                      /* 20Mhz Xtal */
+-                      cpu_clk = 20 * fbdiv * 1000 * 1000;
+-              }
++              pll = rt_memc_r32(MEMC_REG_CPU_PLL);
++              fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK;
++              prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK;
++              cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv];
+               break;
++      default:
++              cpu_clk = xtal_clk;
+       }
++
++      cpu_clk = cpu_clk / ffiv * ffrac;
++      bus_clk = cpu_clk / 4;
++
++      clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", cpu_clk);
++      clks[MT7621_CLK_BUS] = mt7621_add_sys_clkdev("bus", bus_clk);
++
++      pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000);
++      mips_hpt_frequency = cpu_clk / 2;
+ }
++static void __init mt7621_clocks_init_dt(struct device_node *np)
++{
++      of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
++}
++
++CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt);
++
+ void __init ralink_of_remap(void)
+ {
+       rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
+--- a/arch/mips/ralink/timer-gic.c
++++ b/arch/mips/ralink/timer-gic.c
+@@ -9,14 +9,14 @@
+ #include <linux/of.h>
+ #include <linux/clk-provider.h>
+-#include <linux/clocksource.h>
++#include <asm/time.h>
+ #include "common.h"
+ void __init plat_time_init(void)
+ {
+       ralink_of_remap();
+-
++      ralink_clk_init();
+       of_clk_init(NULL);
+       timer_probe();
+ }
+--- /dev/null
++++ b/include/dt-bindings/clock/mt7621-clk.h
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) 2018 Weijie Gao <hackpascal@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#ifndef __DT_BINDINGS_MT7621_CLK_H
++#define __DT_BINDINGS_MT7621_CLK_H
++
++#define MT7621_CLK_CPU                0
++#define MT7621_CLK_BUS                1
++
++#define MT7621_CLK_MAX                2
++
++#endif /* __DT_BINDINGS_MT7621_CLK_H */
diff --git a/target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch b/target/linux/ramips/patches-5.10/323-mt7621-memory-detect.patch
new file mode 100644 (file)
index 0000000..08b4b0d
--- /dev/null
@@ -0,0 +1,125 @@
+From b5a52351a66f3c2a7a207548aa87d78ff2d336c0 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Wed, 10 Jul 2019 00:24:48 +0800
+Subject: [PATCH] MIPS: ralink: mt7621: add memory detection support
+
+mt7621 has the following memory map:
+0x0-0x1c000000: lower 448m memory
+0x1c000000-0x2000000: peripheral registers
+0x20000000-0x2400000: higher 64m memory
+
+detect_memory_region in arch/mips/kernel/setup.c only add the first
+memory region and isn't suitable for 512m memory detection because
+it may accidentally read the memory area for peripheral registers.
+
+This commit adds memory detection capability for mt7621:
+1. add the highmem area when 512m is detected.
+2. guard memcmp from accessing peripheral registers:
+     This only happens when some weird user decided to change
+     kernel load address to 256m or higher address. Since this
+     is a quite unusual case, we just skip 512m testing and return
+     256m as memory size.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/mips/include/asm/mach-ralink/mt7621.h |  7 ++---
+ arch/mips/ralink/mt7621.c                  | 30 +++++++++++++++++++---
+ 2 files changed, 30 insertions(+), 7 deletions(-)
+
+--- a/arch/mips/include/asm/mach-ralink/mt7621.h
++++ b/arch/mips/include/asm/mach-ralink/mt7621.h
+@@ -44,9 +44,10 @@
+ #define CPU_PLL_FBDIV_MASK            0x7f
+ #define CPU_PLL_FBDIV_SHIFT           4
+-#define MT7621_DRAM_BASE                0x0
+-#define MT7621_DDR2_SIZE_MIN          32
+-#define MT7621_DDR2_SIZE_MAX          256
++#define MT7621_LOWMEM_BASE            0x0
++#define MT7621_LOWMEM_MAX_SIZE                0x1C000000
++#define MT7621_HIGHMEM_BASE           0x20000000
++#define MT7621_HIGHMEM_SIZE           0x4000000
+ #define MT7621_CHIP_NAME0             0x3637544D
+ #define MT7621_CHIP_NAME1             0x20203132
+--- a/arch/mips/ralink/mt7621.c
++++ b/arch/mips/ralink/mt7621.c
+@@ -13,6 +13,7 @@
+ #include <linux/clk-provider.h>
+ #include <dt-bindings/clock/mt7621-clk.h>
++#include <asm/bootinfo.h>
+ #include <asm/mipsregs.h>
+ #include <asm/smp-ops.h>
+ #include <asm/mips-cps.h>
+@@ -55,6 +56,8 @@
+ #define MT7621_GPIO_MODE_SDHCI_SHIFT  18
+ #define MT7621_GPIO_MODE_SDHCI_GPIO   1
++static void *detect_magic __initdata = detect_memory_region;
++
+ 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[] = {
+@@ -139,6 +142,28 @@ static struct clk *__init mt7621_add_sys
+       return clk;
+ }
++void __init mt7621_memory_detect(void)
++{
++      void *dm = &detect_magic;
++      phys_addr_t size;
++
++      for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) {
++              if (!memcmp(dm, dm + size, sizeof(detect_magic)))
++                      break;
++      }
++
++      if ((size == 256 * SZ_1M) &&
++          (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) &&
++          memcmp(dm, dm + size, sizeof(detect_magic))) {
++              add_memory_region(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE,
++                                BOOT_MEM_RAM);
++              add_memory_region(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE,
++                                BOOT_MEM_RAM);
++      } else {
++              add_memory_region(MT7621_LOWMEM_BASE, size, BOOT_MEM_RAM);
++      }
++}
++
+ void __init ralink_clk_init(void)
+ {
+       u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
+@@ -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));
+-      soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN;
+-      soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX;
+-      soc_info->mem_base = MT7621_DRAM_BASE;
+-
++      soc_info->mem_detect = mt7621_memory_detect;
+       rt2880_pinmux_data = mt7621_pinmux_data;
+--- a/arch/mips/ralink/common.h
++++ b/arch/mips/ralink/common.h
+@@ -17,6 +17,7 @@ struct ralink_soc_info {
+       unsigned long mem_size;
+       unsigned long mem_size_min;
+       unsigned long mem_size_max;
++      void (*mem_detect)(void);
+ };
+ extern struct ralink_soc_info soc_info;
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -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);
++      else if (soc_info.mem_detect)
++              soc_info.mem_detect();
+       else if (soc_info.mem_size)
+               add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M,
+                                 BOOT_MEM_RAM);
diff --git a/target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch b/target/linux/ramips/patches-5.10/324-mt7621-perfctr-fix.patch
new file mode 100644 (file)
index 0000000..dfeac7e
--- /dev/null
@@ -0,0 +1,15 @@
+--- a/arch/mips/ralink/irq-gic.c
++++ b/arch/mips/ralink/irq-gic.c
+@@ -13,6 +13,12 @@
+ int get_c0_perfcount_int(void)
+ {
++      /*
++       * Performance counter events are routed through GIC.
++       * Prevent them from firing on CPU IRQ7 as well
++       */
++      clear_c0_status(IE_SW0 << 7);
++
+       return gic_get_c0_perfcount_int();
+ }
+ EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
diff --git a/target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch b/target/linux/ramips/patches-5.10/330-fix-pci-init-mt7620.patch
new file mode 100644 (file)
index 0000000..7c00d4c
--- /dev/null
@@ -0,0 +1,21 @@
+--- a/arch/mips/pci/pci-mt7620.c
++++ b/arch/mips/pci/pci-mt7620.c
+@@ -32,6 +32,7 @@
+ #define PPLL_CFG1                     0x9c
+ #define PPLL_DRV                      0xa0
++#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);
+-      if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
+-              dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
++      if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
++              dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n");
+               reset_control_assert(rstpcie0);
+               rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
+               return -1;
diff --git a/target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch b/target/linux/ramips/patches-5.10/400-mtd-cfi-cmdset-0002-force-word-write.patch
new file mode 100644 (file)
index 0000000..7011bbe
--- /dev/null
@@ -0,0 +1,20 @@
+From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 15 Jul 2013 00:39:21 +0200
+Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
+
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -40,7 +40,7 @@
+ #include <linux/mtd/xip.h>
+ #define AMD_BOOTLOC_BUG
+-#define FORCE_WORD_WRITE 0
++#define FORCE_WORD_WRITE 1
+ #define MAX_RETRIES 3
diff --git a/target/linux/ramips/patches-5.10/401-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.10/401-net-ethernet-mediatek-support-net-labels.patch
deleted file mode 100644 (file)
index 6583fca..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-From bd0f89de5476ca25e73fae829ba3e1dafae1d90d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
-Date: Fri, 21 Jun 2019 10:04:05 +0200
-Subject: [PATCH] net: ethernet: mediatek: support net-labels
-
-With this patch, device name can be set within dts file in the same way as dsa
-port can.
-Add: label = "wan"; to GMAC node.
-
-Signed-off-by: RenĂ© van Dorst <opensource@vdorst.com>
----
- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2922,6 +2922,7 @@ static const struct net_device_ops mtk_n
- static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
- {
-+      const char *name = of_get_property(np, "label", NULL);
-       const __be32 *_id = of_get_property(np, "reg", NULL);
-       struct phylink *phylink;
-       int phy_mode, id, err;
-@@ -3014,6 +3015,9 @@ static int mtk_add_mac(struct mtk_eth *e
-       eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
-+      if (name)
-+              strlcpy(eth->netdev[id]->name, name, IFNAMSIZ);
-+
-       return 0;
- free_netdev:
diff --git a/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch b/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch
new file mode 100644 (file)
index 0000000..ba844fe
--- /dev/null
@@ -0,0 +1,1400 @@
+From e84e2430ee0e483842b4ff013ae8a6e7e2fa2734 Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Wed, 1 Apr 2020 02:07:58 +0800
+Subject: [PATCH 1/2] mtd: rawnand: add driver support for MT7621 nand
+ flash controller
+
+This patch adds NAND flash controller driver for MediaTek MT7621 SoC.
+
+The NAND flash controller is similar with controllers described in
+mtk_nand.c, except that the controller from MT7621 doesn't support DMA
+transmission, and some registers' offset and fields are different.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ drivers/mtd/nand/raw/Kconfig       |    8 +
+ drivers/mtd/nand/raw/Makefile      |    1 +
+ drivers/mtd/nand/raw/mt7621_nand.c | 1348 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1357 insertions(+)
+ create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c
+
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -391,6 +391,14 @@ config MTD_NAND_QCOM
+         Enables support for NAND flash chips on SoCs containing the EBI2 NAND
+         controller. This controller is found on IPQ806x SoC.
++config MTD_NAND_MT7621
++      tristate "MT7621 NAND controller"
++      depends on SOC_MT7621 || COMPILE_TEST
++      depends on HAS_IOMEM
++      help
++        Enables support for NAND controller on MT7621 SoC.
++        This driver uses PIO mode for data transmission instead of DMA mode.
++
+ config MTD_NAND_MTK
+       tristate "MTK NAND controller"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -52,6 +52,7 @@ obj-$(CONFIG_MTD_NAND_SUNXI)         += sunxi_n
+ obj-$(CONFIG_MTD_NAND_HISI504)                += hisi504_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND)               += brcmnand/
+ obj-$(CONFIG_MTD_NAND_QCOM)           += qcom_nandc.o
++obj-$(CONFIG_MTD_NAND_MT7621)         += mt7621_nand.o
+ obj-$(CONFIG_MTD_NAND_MTK)            += mtk_ecc.o mtk_nand.o
+ obj-$(CONFIG_MTD_NAND_MXIC)           += mxic_nand.o
+ obj-$(CONFIG_MTD_NAND_TEGRA)          += tegra_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/raw/mt7621_nand.c
+@@ -0,0 +1,1350 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek MT7621 NAND Flash Controller driver
++ *
++ * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/sizes.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/rawnand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <asm/addrspace.h>
++
++/* NFI core registers */
++#define NFI_CNFG                      0x000
++#define   CNFG_OP_MODE_S              12
++#define   CNFG_OP_MODE_M              GENMASK(14, 12)
++#define     CNFG_OP_CUSTOM            6
++#define   CNFG_AUTO_FMT_EN            BIT(9)
++#define   CNFG_HW_ECC_EN              BIT(8)
++#define   CNFG_BYTE_RW                        BIT(6)
++#define   CNFG_READ_MODE              BIT(1)
++
++#define NFI_PAGEFMT                   0x004
++#define   PAGEFMT_FDM_ECC_S           12
++#define   PAGEFMT_FDM_ECC_M           GENMASK(15, 12)
++#define   PAGEFMT_FDM_S                       8
++#define   PAGEFMT_FDM_M                       GENMASK(11, 8)
++#define   PAGEFMT_SPARE_S             4
++#define   PAGEFMT_SPARE_M             GENMASK(5, 4)
++#define   PAGEFMT_PAGE_S              0
++#define   PAGEFMT_PAGE_M              GENMASK(1, 0)
++
++#define NFI_CON                               0x008
++#define   CON_NFI_SEC_S                       12
++#define   CON_NFI_SEC_M                       GENMASK(15, 12)
++#define   CON_NFI_BWR                 BIT(9)
++#define   CON_NFI_BRD                 BIT(8)
++#define   CON_NFI_RST                 BIT(1)
++#define   CON_FIFO_FLUSH              BIT(0)
++
++#define NFI_ACCCON                    0x00c
++#define   ACCCON_POECS_S              28
++#define   ACCCON_POECS_MAX            0x0f
++#define   ACCCON_POECS_DEF            3
++#define   ACCCON_PRECS_S              22
++#define   ACCCON_PRECS_MAX            0x3f
++#define   ACCCON_PRECS_DEF            3
++#define   ACCCON_C2R_S                        16
++#define   ACCCON_C2R_MAX              0x3f
++#define   ACCCON_C2R_DEF              7
++#define   ACCCON_W2R_S                        12
++#define   ACCCON_W2R_MAX              0x0f
++#define   ACCCON_W2R_DEF              7
++#define   ACCCON_WH_S                 8
++#define   ACCCON_WH_MAX                       0x0f
++#define   ACCCON_WH_DEF                       15
++#define   ACCCON_WST_S                        4
++#define   ACCCON_WST_MAX              0x0f
++#define   ACCCON_WST_DEF              15
++#define   ACCCON_WST_MIN              3
++#define   ACCCON_RLT_S                        0
++#define   ACCCON_RLT_MAX              0x0f
++#define   ACCCON_RLT_DEF              15
++#define   ACCCON_RLT_MIN              3
++
++#define NFI_CMD                               0x020
++
++#define NFI_ADDRNOB                   0x030
++#define   ADDR_ROW_NOB_S              4
++#define   ADDR_ROW_NOB_M              GENMASK(6, 4)
++#define   ADDR_COL_NOB_S              0
++#define   ADDR_COL_NOB_M              GENMASK(2, 0)
++
++#define NFI_COLADDR                   0x034
++#define NFI_ROWADDR                   0x038
++
++#define NFI_STRDATA                   0x040
++#define   STR_DATA                    BIT(0)
++
++#define NFI_CNRNB                     0x044
++#define   CB2R_TIME_S                 4
++#define   CB2R_TIME_M                 GENMASK(7, 4)
++#define   STR_CNRNB                   BIT(0)
++
++#define NFI_DATAW                     0x050
++#define NFI_DATAR                     0x054
++
++#define NFI_PIO_DIRDY                 0x058
++#define   PIO_DIRDY                   BIT(0)
++
++#define NFI_STA                               0x060
++#define   STA_NFI_FSM_S                       16
++#define   STA_NFI_FSM_M                       GENMASK(19, 16)
++#define     STA_FSM_CUSTOM_DATA               14
++#define   STA_BUSY                    BIT(8)
++#define   STA_ADDR                    BIT(1)
++#define   STA_CMD                     BIT(0)
++
++#define NFI_ADDRCNTR                  0x070
++#define   SEC_CNTR_S                  12
++#define   SEC_CNTR_M                  GENMASK(15, 12)
++#define   SEC_ADDR_S                  0
++#define   SEC_ADDR_M                  GENMASK(9, 0)
++
++#define NFI_CSEL                      0x090
++#define   CSEL_S                      0
++#define   CSEL_M                      GENMASK(1, 0)
++
++#define NFI_FDM0L                     0x0a0
++#define NFI_FDML(n)                   (0x0a0 + ((n) << 3))
++
++#define NFI_FDM0M                     0x0a4
++#define NFI_FDMM(n)                   (0x0a4 + ((n) << 3))
++
++#define NFI_MASTER_STA                        0x210
++#define   MAS_ADDR                    GENMASK(11, 9)
++#define   MAS_RD                      GENMASK(8, 6)
++#define   MAS_WR                      GENMASK(5, 3)
++#define   MAS_RDDLY                   GENMASK(2, 0)
++
++/* ECC engine registers */
++#define ECC_ENCCON                    0x000
++#define   ENC_EN                      BIT(0)
++
++#define ECC_ENCCNFG                   0x004
++#define   ENC_CNFG_MSG_S              16
++#define   ENC_CNFG_MSG_M              GENMASK(28, 16)
++#define   ENC_MODE_S                  4
++#define   ENC_MODE_M                  GENMASK(5, 4)
++#define     ENC_MODE_NFI              1
++#define   ENC_TNUM_S                  0
++#define   ENC_TNUM_M                  GENMASK(2, 0)
++
++#define ECC_ENCIDLE                   0x00c
++#define   ENC_IDLE                    BIT(0)
++
++#define ECC_DECCON                    0x100
++#define   DEC_EN                      BIT(0)
++
++#define ECC_DECCNFG                   0x104
++#define   DEC_EMPTY_EN                        BIT(31)
++#define   DEC_CS_S                    16
++#define   DEC_CS_M                    GENMASK(28, 16)
++#define   DEC_CON_S                   12
++#define   DEC_CON_M                   GENMASK(13, 12)
++#define     DEC_CON_EL                        2
++#define   DEC_MODE_S                  4
++#define   DEC_MODE_M                  GENMASK(5, 4)
++#define     DEC_MODE_NFI              1
++#define   DEC_TNUM_S                  0
++#define   DEC_TNUM_M                  GENMASK(2, 0)
++
++#define ECC_DECIDLE                   0x10c
++#define   DEC_IDLE                    BIT(1)
++
++#define ECC_DECENUM                   0x114
++#define   ERRNUM_S                    2
++#define   ERRNUM_M                    GENMASK(3, 0)
++
++#define ECC_DECDONE                   0x118
++#define   DEC_DONE7                   BIT(7)
++#define   DEC_DONE6                   BIT(6)
++#define   DEC_DONE5                   BIT(5)
++#define   DEC_DONE4                   BIT(4)
++#define   DEC_DONE3                   BIT(3)
++#define   DEC_DONE2                   BIT(2)
++#define   DEC_DONE1                   BIT(1)
++#define   DEC_DONE0                   BIT(0)
++
++#define ECC_DECEL(n)                  (0x11c + (n) * 4)
++#define   DEC_EL_ODD_S                        16
++#define   DEC_EL_EVEN_S                       0
++#define   DEC_EL_M                    0x1fff
++#define   DEC_EL_BYTE_POS_S           3
++#define   DEC_EL_BIT_POS_M            GENMASK(3, 0)
++
++#define ECC_FDMADDR                   0x13c
++
++/* ENCIDLE and DECIDLE */
++#define   ECC_IDLE                    BIT(0)
++
++#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
++      ((tpoecs) << ACCCON_POECS_S | (tprecs) << ACCCON_PRECS_S | \
++      (tc2r) << ACCCON_C2R_S | (tw2r) << ACCCON_W2R_S | \
++      (twh) << ACCCON_WH_S | (twst) << ACCCON_WST_S | (trlt))
++
++#define MASTER_STA_MASK                       (MAS_ADDR | MAS_RD | MAS_WR | \
++                                       MAS_RDDLY)
++#define NFI_RESET_TIMEOUT             1000000
++#define NFI_CORE_TIMEOUT              500000
++#define ECC_ENGINE_TIMEOUT            500000
++
++#define ECC_SECTOR_SIZE                       512
++#define ECC_PARITY_BITS                       13
++
++#define NFI_FDM_SIZE          8
++
++#define MT7621_NFC_NAME                       "mt7621-nand"
++
++struct mt7621_nfc {
++      struct nand_controller controller;
++      struct nand_chip nand;
++      struct clk *nfi_clk;
++      struct device *dev;
++
++      void __iomem *nfi_regs;
++      void __iomem *ecc_regs;
++
++      u32 spare_per_sector;
++};
++
++static const u16 mt7621_nfi_page_size[] = { SZ_512, SZ_2K, SZ_4K };
++static const u8 mt7621_nfi_spare_size[] = { 16, 26, 27, 28 };
++static const u8 mt7621_ecc_strength[] = { 4, 6, 8, 10, 12 };
++
++static inline u32 nfi_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readl(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++      writel(val, nfc->nfi_regs + reg);
++}
++
++static inline u16 nfi_read16(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readw(nfc->nfi_regs + reg);
++}
++
++static inline void nfi_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++      writew(val, nfc->nfi_regs + reg);
++}
++
++static inline void ecc_write16(struct mt7621_nfc *nfc, u32 reg, u16 val)
++{
++      writew(val, nfc->ecc_regs + reg);
++}
++
++static inline u32 ecc_read32(struct mt7621_nfc *nfc, u32 reg)
++{
++      return readl(nfc->ecc_regs + reg);
++}
++
++static inline void ecc_write32(struct mt7621_nfc *nfc, u32 reg, u32 val)
++{
++      return writel(val, nfc->ecc_regs + reg);
++}
++
++static inline u8 *oob_fdm_ptr(struct nand_chip *nand, int sect)
++{
++      return nand->oob_poi + sect * NFI_FDM_SIZE;
++}
++
++static inline u8 *oob_ecc_ptr(struct mt7621_nfc *nfc, int sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++
++      return nand->oob_poi + nand->ecc.steps * NFI_FDM_SIZE +
++              sect * (nfc->spare_per_sector - NFI_FDM_SIZE);
++}
++
++static inline u8 *page_data_ptr(struct nand_chip *nand, const u8 *buf,
++                              int sect)
++{
++      return (u8 *)buf + sect * nand->ecc.size;
++}
++
++static int mt7621_ecc_wait_idle(struct mt7621_nfc *nfc, u32 reg)
++{
++      struct device *dev = nfc->dev;
++      u32 val;
++      int ret;
++
++      ret = readw_poll_timeout_atomic(nfc->ecc_regs + reg, val,
++                                      val & ECC_IDLE, 10,
++                                      ECC_ENGINE_TIMEOUT);
++      if (ret) {
++              dev_warn(dev, "ECC engine timed out entering idle mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt7621_ecc_decoder_wait_done(struct mt7621_nfc *nfc, u32 sect)
++{
++      struct device *dev = nfc->dev;
++      u32 val;
++      int ret;
++
++      ret = readw_poll_timeout_atomic(nfc->ecc_regs + ECC_DECDONE, val,
++                                      val & (1 << sect), 10,
++                                      ECC_ENGINE_TIMEOUT);
++
++      if (ret) {
++              dev_warn(dev, "ECC decoder for sector %d timed out\n",
++                       sect);
++              return -ETIMEDOUT;
++      }
++
++      return 0;
++}
++
++static void mt7621_ecc_encoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++      mt7621_ecc_wait_idle(nfc, ECC_ENCIDLE);
++      ecc_write16(nfc, ECC_ENCCON, enable ? ENC_EN : 0);
++}
++
++static void mt7621_ecc_decoder_op(struct mt7621_nfc *nfc, bool enable)
++{
++      mt7621_ecc_wait_idle(nfc, ECC_DECIDLE);
++      ecc_write16(nfc, ECC_DECCON, enable ? DEC_EN : 0);
++}
++
++static int mt7621_ecc_correct_check(struct mt7621_nfc *nfc, u8 *sector_buf,
++                                 u8 *fdm_buf, u32 sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 decnum, num_error_bits, fdm_end_bits;
++      u32 error_locations, error_bit_loc;
++      u32 error_byte_pos, error_bit_pos;
++      int bitflips = 0;
++      u32 i;
++
++      decnum = ecc_read32(nfc, ECC_DECENUM);
++      num_error_bits = (decnum >> (sect << ERRNUM_S)) & ERRNUM_M;
++      fdm_end_bits = (nand->ecc.size + NFI_FDM_SIZE) << 3;
++
++      if (!num_error_bits)
++              return 0;
++
++      if (num_error_bits == ERRNUM_M)
++              return -1;
++
++      for (i = 0; i < num_error_bits; i++) {
++              error_locations = ecc_read32(nfc, ECC_DECEL(i / 2));
++              error_bit_loc = (error_locations >> ((i % 2) * DEC_EL_ODD_S)) &
++                              DEC_EL_M;
++              error_byte_pos = error_bit_loc >> DEC_EL_BYTE_POS_S;
++              error_bit_pos = error_bit_loc & DEC_EL_BIT_POS_M;
++
++              if (error_bit_loc < (nand->ecc.size << 3)) {
++                      if (sector_buf) {
++                              sector_buf[error_byte_pos] ^=
++                                      (1 << error_bit_pos);
++                      }
++              } else if (error_bit_loc < fdm_end_bits) {
++                      if (fdm_buf) {
++                              fdm_buf[error_byte_pos - nand->ecc.size] ^=
++                                      (1 << error_bit_pos);
++                      }
++              }
++
++              bitflips++;
++      }
++
++      return bitflips;
++}
++
++static int mt7621_nfc_wait_write_completion(struct mt7621_nfc *nfc,
++                                          struct nand_chip *nand)
++{
++      struct device *dev = nfc->dev;
++      u16 val;
++      int ret;
++
++      ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_ADDRCNTR, val,
++              ((val & SEC_CNTR_M) >> SEC_CNTR_S) >= nand->ecc.steps, 10,
++              NFI_CORE_TIMEOUT);
++
++      if (ret) {
++              dev_warn(dev, "NFI core write operation timed out\n");
++              return -ETIMEDOUT;
++      }
++
++      return ret;
++}
++
++static void mt7621_nfc_hw_reset(struct mt7621_nfc *nfc)
++{
++      u32 val;
++      int ret;
++
++      /* reset all registers and force the NFI master to terminate */
++      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++
++      /* wait for the master to finish the last transaction */
++      ret = readw_poll_timeout(nfc->nfi_regs + NFI_MASTER_STA, val,
++                               !(val & MASTER_STA_MASK), 50,
++                               NFI_RESET_TIMEOUT);
++      if (ret) {
++              dev_warn(nfc->dev, "Failed to reset NFI master in %dms\n",
++                       NFI_RESET_TIMEOUT);
++      }
++
++      /* ensure any status register affected by the NFI master is reset */
++      nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST);
++      nfi_write16(nfc, NFI_STRDATA, 0);
++}
++
++static inline void mt7621_nfc_hw_init(struct mt7621_nfc *nfc)
++{
++      u32 acccon;
++
++      /*
++       * CNRNB: nand ready/busy register
++       * -------------------------------
++       * 7:4: timeout register for polling the NAND busy/ready signal
++       * 0  : poll the status of the busy/ready signal after [7:4]*16 cycles.
++       */
++      nfi_write16(nfc, NFI_CNRNB, CB2R_TIME_M | STR_CNRNB);
++
++      mt7621_nfc_hw_reset(nfc);
++
++      /* Apply default access timing */
++      acccon = ACCTIMING(ACCCON_POECS_DEF, ACCCON_PRECS_DEF, ACCCON_C2R_DEF,
++                         ACCCON_W2R_DEF, ACCCON_WH_DEF, ACCCON_WST_DEF,
++                         ACCCON_RLT_DEF);
++
++      nfi_write32(nfc, NFI_ACCCON, acccon);
++}
++
++static int mt7621_nfc_send_command(struct mt7621_nfc *nfc, u8 command)
++{
++      struct device *dev = nfc->dev;
++      u32 val;
++      int ret;
++
++      nfi_write32(nfc, NFI_CMD, command);
++
++      ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++                                      !(val & STA_CMD), 10,
++                                      NFI_CORE_TIMEOUT);
++      if (ret) {
++              dev_warn(dev, "NFI core timed out entering command mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt7621_nfc_send_address_byte(struct mt7621_nfc *nfc, int addr)
++{
++      struct device *dev = nfc->dev;
++      u32 val;
++      int ret;
++
++      nfi_write32(nfc, NFI_COLADDR, addr);
++      nfi_write32(nfc, NFI_ROWADDR, 0);
++      nfi_write16(nfc, NFI_ADDRNOB, 1);
++
++      ret = readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++                                      !(val & STA_ADDR), 10,
++                                      NFI_CORE_TIMEOUT);
++      if (ret) {
++              dev_warn(dev, "NFI core timed out entering address mode\n");
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int mt7621_nfc_send_address(struct mt7621_nfc *nfc, const u8 *addr,
++                                 unsigned int naddrs)
++{
++      int ret;
++
++      while (naddrs) {
++              ret = mt7621_nfc_send_address_byte(nfc, *addr);
++              if (ret)
++                      return ret;
++
++              addr++;
++              naddrs--;
++      }
++
++      return 0;
++}
++
++static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc)
++{
++      struct device *dev = nfc->dev;
++      int ret;
++      u16 val;
++
++      ret = readw_poll_timeout_atomic(nfc->nfi_regs + NFI_PIO_DIRDY, val,
++                                      val & PIO_DIRDY, 10,
++                                      NFI_CORE_TIMEOUT);
++      if (ret < 0)
++              dev_err(dev, "NFI core PIO mode not ready\n");
++}
++
++static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br)
++{
++      u32 reg;
++
++      /* after each byte read, the NFI_STA reg is reset by the hardware */
++      reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
++      if (reg != STA_FSM_CUSTOM_DATA) {
++              reg = nfi_read16(nfc, NFI_CNFG);
++              reg |= CNFG_READ_MODE | CNFG_BYTE_RW;
++              if (!br)
++                      reg &= ~CNFG_BYTE_RW;
++              nfi_write16(nfc, NFI_CNFG, reg);
++
++              /*
++               * set to max sector to allow the HW to continue reading over
++               * unaligned accesses
++               */
++              nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BRD);
++
++              /* trigger to fetch data */
++              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++      }
++
++      mt7621_nfc_wait_pio_ready(nfc);
++
++      return nfi_read32(nfc, NFI_DATAR);
++}
++
++static void mt7621_nfc_read_data(struct mt7621_nfc *nfc, u8 *buf, u32 len)
++{
++      while (((uintptr_t)buf & 3) && len) {
++              *buf = mt7621_nfc_pio_read(nfc, true);
++              buf++;
++              len--;
++      }
++
++      while (len >= 4) {
++              *(u32 *)buf = mt7621_nfc_pio_read(nfc, false);
++              buf += 4;
++              len -= 4;
++      }
++
++      while (len) {
++              *buf = mt7621_nfc_pio_read(nfc, true);
++              buf++;
++              len--;
++      }
++}
++
++static void mt7621_nfc_read_data_discard(struct mt7621_nfc *nfc, u32 len)
++{
++      while (len >= 4) {
++              mt7621_nfc_pio_read(nfc, false);
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_read(nfc, true);
++              len--;
++      }
++}
++
++static void mt7621_nfc_pio_write(struct mt7621_nfc *nfc, u32 val, bool bw)
++{
++      u32 reg;
++
++      reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S;
++      if (reg != STA_FSM_CUSTOM_DATA) {
++              reg = nfi_read16(nfc, NFI_CNFG);
++              reg &= ~(CNFG_READ_MODE | CNFG_BYTE_RW);
++              if (bw)
++                      reg |= CNFG_BYTE_RW;
++              nfi_write16(nfc, NFI_CNFG, reg);
++
++              nfi_write16(nfc, NFI_CON, CON_NFI_SEC_M | CON_NFI_BWR);
++              nfi_write16(nfc, NFI_STRDATA, STR_DATA);
++      }
++
++      mt7621_nfc_wait_pio_ready(nfc);
++      nfi_write32(nfc, NFI_DATAW, val);
++}
++
++static void mt7621_nfc_write_data(struct mt7621_nfc *nfc, const u8 *buf,
++                                u32 len)
++{
++      while (((uintptr_t)buf & 3) && len) {
++              mt7621_nfc_pio_write(nfc, *buf, true);
++              buf++;
++              len--;
++      }
++
++      while (len >= 4) {
++              mt7621_nfc_pio_write(nfc, *(const u32 *)buf, false);
++              buf += 4;
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_write(nfc, *buf, true);
++              buf++;
++              len--;
++      }
++}
++
++static void mt7621_nfc_write_data_empty(struct mt7621_nfc *nfc, u32 len)
++{
++      while (len >= 4) {
++              mt7621_nfc_pio_write(nfc, 0xffffffff, false);
++              len -= 4;
++      }
++
++      while (len) {
++              mt7621_nfc_pio_write(nfc, 0xff, true);
++              len--;
++      }
++}
++
++static int mt7621_nfc_dev_ready(struct mt7621_nfc *nfc,
++                              unsigned int timeout_ms)
++{
++      u32 val;
++
++      return readl_poll_timeout_atomic(nfc->nfi_regs + NFI_STA, val,
++                                       !(val & STA_BUSY), 10,
++                                       timeout_ms * 1000);
++}
++
++static int mt7621_nfc_exec_instr(struct nand_chip *nand,
++                               const struct nand_op_instr *instr)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++
++      switch (instr->type) {
++      case NAND_OP_CMD_INSTR:
++              mt7621_nfc_hw_reset(nfc);
++              nfi_write16(nfc, NFI_CNFG, CNFG_OP_CUSTOM << CNFG_OP_MODE_S);
++              return mt7621_nfc_send_command(nfc, instr->ctx.cmd.opcode);
++      case NAND_OP_ADDR_INSTR:
++              return mt7621_nfc_send_address(nfc, instr->ctx.addr.addrs,
++                                             instr->ctx.addr.naddrs);
++      case NAND_OP_DATA_IN_INSTR:
++              mt7621_nfc_read_data(nfc, instr->ctx.data.buf.in,
++                                   instr->ctx.data.len);
++              return 0;
++      case NAND_OP_DATA_OUT_INSTR:
++              mt7621_nfc_write_data(nfc, instr->ctx.data.buf.out,
++                                    instr->ctx.data.len);
++              return 0;
++      case NAND_OP_WAITRDY_INSTR:
++              return mt7621_nfc_dev_ready(nfc,
++                                          instr->ctx.waitrdy.timeout_ms);
++      default:
++              WARN_ONCE(1, "unsupported NAND instruction type: %d\n",
++                        instr->type);
++
++              return -EINVAL;
++      }
++}
++
++static int mt7621_nfc_exec_op(struct nand_chip *nand,
++                            const struct nand_operation *op, bool check_only)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int i, ret;
++
++      if (check_only)
++              return 0;
++
++      /* Only CS0 available */
++      nfi_write16(nfc, NFI_CSEL, 0);
++
++      for (i = 0; i < op->ninstrs; i++) {
++              ret = mt7621_nfc_exec_instr(nand, &op->instrs[i]);
++              if (ret)
++                      return ret;
++      }
++
++      return 0;
++}
++
++static int mt7621_nfc_setup_data_interface(struct nand_chip *nand, int csline,
++                                         const struct nand_data_interface *conf)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      const struct nand_sdr_timings *timings;
++      u32 acccon, temp, rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
++
++      if (!nfc->nfi_clk)
++              return -ENOTSUPP;
++
++      timings = nand_get_sdr_timings(conf);
++      if (IS_ERR(timings))
++              return -ENOTSUPP;
++
++      rate = clk_get_rate(nfc->nfi_clk);
++
++      /* turn clock rate into KHZ */
++      rate /= 1000;
++
++      tpoecs = max(timings->tALH_min, timings->tCLH_min) / 1000;
++      tpoecs = DIV_ROUND_UP(tpoecs * rate, 1000000);
++      tpoecs = min_t(u32, tpoecs, ACCCON_POECS_MAX);
++
++      tprecs = max(timings->tCLS_min, timings->tALS_min) / 1000;
++      tprecs = DIV_ROUND_UP(tprecs * rate, 1000000);
++      tprecs = min_t(u32, tprecs, ACCCON_PRECS_MAX);
++
++      /* sdr interface has no tCR which means CE# low to RE# low */
++      tc2r = 0;
++
++      tw2r = timings->tWHR_min / 1000;
++      tw2r = DIV_ROUND_UP(tw2r * rate, 1000000);
++      tw2r = DIV_ROUND_UP(tw2r - 1, 2);
++      tw2r = min_t(u32, tw2r, ACCCON_W2R_MAX);
++
++      twh = max(timings->tREH_min, timings->tWH_min) / 1000;
++      twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
++      twh = min_t(u32, twh, ACCCON_WH_MAX);
++
++      /* Calculate real WE#/RE# hold time in nanosecond */
++      temp = (twh + 1) * 1000000 / rate;
++      /* nanosecond to picosecond */
++      temp *= 1000;
++
++      /*
++       * WE# low level time should be expaned to meet WE# pulse time
++       * and WE# cycle time at the same time.
++       */
++      if (temp < timings->tWC_min)
++              twst = timings->tWC_min - temp;
++      else
++              twst = 0;
++      twst = max(timings->tWP_min, twst) / 1000;
++      twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
++      twst = min_t(u32, twst, ACCCON_WST_MAX);
++
++      /*
++       * RE# low level time should be expaned to meet RE# pulse time
++       * and RE# cycle time at the same time.
++       */
++      if (temp < timings->tRC_min)
++              trlt = timings->tRC_min - temp;
++      else
++              trlt = 0;
++      trlt = max(trlt, timings->tRP_min) / 1000;
++      trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
++      trlt = min_t(u32, trlt, ACCCON_RLT_MAX);
++
++      if (csline == NAND_DATA_IFACE_CHECK_ONLY) {
++              if (twst < ACCCON_WST_MIN || trlt < ACCCON_RLT_MIN)
++                      return -ENOTSUPP;
++      }
++
++      acccon = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
++
++      dev_info(nfc->dev, "Using programmed access timing: %08x\n", acccon);
++
++      nfi_write32(nfc, NFI_ACCCON, acccon);
++
++      return 0;
++}
++
++static int mt7621_nfc_calc_ecc_strength(struct mt7621_nfc *nfc,
++                                      u32 avail_ecc_bytes)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 strength;
++      int i;
++
++      strength = avail_ecc_bytes * 8 / ECC_PARITY_BITS;
++
++      /* Find the closest supported ecc strength */
++      for (i = ARRAY_SIZE(mt7621_ecc_strength) - 1; i >= 0; i--) {
++              if (mt7621_ecc_strength[i] <= strength)
++                      break;
++      }
++
++      if (unlikely(i < 0)) {
++              dev_err(nfc->dev, "OOB size (%u) is not supported\n",
++                      mtd->oobsize);
++              return -EINVAL;
++      }
++
++      nand->ecc.strength = mt7621_ecc_strength[i];
++      nand->ecc.bytes =
++              DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8);
++
++      dev_info(nfc->dev, "ECC strength adjusted to %u bits\n",
++               nand->ecc.strength);
++
++      return i;
++}
++
++static int mt7621_nfc_set_spare_per_sector(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 size;
++      int i;
++
++      size = nand->ecc.bytes + NFI_FDM_SIZE;
++
++      /* Find the closest supported spare size */
++      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_spare_size); i++) {
++              if (mt7621_nfi_spare_size[i] >= size)
++                      break;
++      }
++
++      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_spare_size))) {
++              dev_err(nfc->dev, "OOB size (%u) is not supported\n",
++                      mtd->oobsize);
++              return -EINVAL;
++      }
++
++      nfc->spare_per_sector = mt7621_nfi_spare_size[i];
++
++      return i;
++}
++
++static int mt7621_nfc_ecc_init(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      u32 spare_per_sector, encode_block_size, decode_block_size;
++      u32 ecc_enccfg, ecc_deccfg;
++      int ecc_cap;
++
++      /* Only hardware ECC mode is supported */
++      if (nand->ecc.mode != NAND_ECC_HW_SYNDROME) {
++              dev_err(nfc->dev, "Only hardware ECC mode is supported\n");
++              return -EINVAL;
++      }
++
++      nand->ecc.size = ECC_SECTOR_SIZE;
++      nand->ecc.steps = mtd->writesize / nand->ecc.size;
++
++      spare_per_sector = mtd->oobsize / nand->ecc.steps;
++
++      ecc_cap = mt7621_nfc_calc_ecc_strength(nfc,
++              spare_per_sector - NFI_FDM_SIZE);
++      if (ecc_cap < 0)
++              return ecc_cap;
++
++      /* Sector + FDM */
++      encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8;
++      ecc_enccfg = ecc_cap | (ENC_MODE_NFI << ENC_MODE_S) |
++                   (encode_block_size << ENC_CNFG_MSG_S);
++
++      /* Sector + FDM + ECC parity bits */
++      decode_block_size = ((nand->ecc.size + NFI_FDM_SIZE) * 8) +
++                          nand->ecc.strength * ECC_PARITY_BITS;
++      ecc_deccfg = ecc_cap | (DEC_MODE_NFI << DEC_MODE_S) |
++                   (decode_block_size << DEC_CS_S) |
++                   (DEC_CON_EL << DEC_CON_S) | DEC_EMPTY_EN;
++
++      mt7621_ecc_encoder_op(nfc, false);
++      ecc_write32(nfc, ECC_ENCCNFG, ecc_enccfg);
++
++      mt7621_ecc_decoder_op(nfc, false);
++      ecc_write32(nfc, ECC_DECCNFG, ecc_deccfg);
++
++      return 0;
++}
++
++static int mt7621_nfc_set_page_format(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      int i, spare_size;
++      u32 pagefmt;
++
++      spare_size = mt7621_nfc_set_spare_per_sector(nfc);
++      if (spare_size < 0)
++              return spare_size;
++
++      for (i = 0; i < ARRAY_SIZE(mt7621_nfi_page_size); i++) {
++              if (mt7621_nfi_page_size[i] == mtd->writesize)
++                      break;
++      }
++
++      if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_page_size))) {
++              dev_err(nfc->dev, "Page size (%u) is not supported\n",
++                      mtd->writesize);
++              return -EINVAL;
++      }
++
++      pagefmt = i | (spare_size << PAGEFMT_SPARE_S) |
++                (NFI_FDM_SIZE << PAGEFMT_FDM_S) |
++                (NFI_FDM_SIZE << PAGEFMT_FDM_ECC_S);
++
++      nfi_write16(nfc, NFI_PAGEFMT, pagefmt);
++
++      return 0;
++}
++
++static int mt7621_nfc_attach_chip(struct nand_chip *nand)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int ret;
++
++      if (nand->options & NAND_BUSWIDTH_16) {
++              dev_err(nfc->dev, "16-bit buswidth is not supported");
++              return -EINVAL;
++      }
++
++      ret = mt7621_nfc_ecc_init(nfc);
++      if (ret)
++              return ret;
++
++      return mt7621_nfc_set_page_format(nfc);
++}
++
++static const struct nand_controller_ops mt7621_nfc_controller_ops = {
++      .attach_chip = mt7621_nfc_attach_chip,
++      .exec_op = mt7621_nfc_exec_op,
++      .setup_data_interface = mt7621_nfc_setup_data_interface,
++};
++
++static int mt7621_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++                                   struct mtd_oob_region *oob_region)
++{
++      struct nand_chip *nand = mtd_to_nand(mtd);
++
++      if (section >= nand->ecc.steps)
++              return -ERANGE;
++
++      oob_region->length = NFI_FDM_SIZE - 1;
++      oob_region->offset = section * NFI_FDM_SIZE + 1;
++
++      return 0;
++}
++
++static int mt7621_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                  struct mtd_oob_region *oob_region)
++{
++      struct nand_chip *nand = mtd_to_nand(mtd);
++
++      if (section)
++              return -ERANGE;
++
++      oob_region->offset = NFI_FDM_SIZE * nand->ecc.steps;
++      oob_region->length = mtd->oobsize - oob_region->offset;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops mt7621_nfc_ooblayout_ops = {
++      .free = mt7621_nfc_ooblayout_free,
++      .ecc = mt7621_nfc_ooblayout_ecc,
++};
++
++static void mt7621_nfc_write_fdm(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 vall, valm;
++      u8 *oobptr;
++      int i, j;
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              vall = 0;
++              valm = 0;
++              oobptr = oob_fdm_ptr(nand, i);
++
++              for (j = 0; j < 4; j++)
++                      vall |= (u32)oobptr[j] << (j * 8);
++
++              for (j = 0; j < 4; j++)
++                      valm |= (u32)oobptr[j + 4] << ((j - 4) * 8);
++
++              nfi_write32(nfc, NFI_FDML(i), vall);
++              nfi_write32(nfc, NFI_FDMM(i), valm);
++      }
++}
++
++static void mt7621_nfc_read_sector_fdm(struct mt7621_nfc *nfc, u32 sect)
++{
++      struct nand_chip *nand = &nfc->nand;
++      u32 vall, valm;
++      u8 *oobptr;
++      int i;
++
++      vall = nfi_read32(nfc, NFI_FDML(sect));
++      valm = nfi_read32(nfc, NFI_FDMM(sect));
++      oobptr = oob_fdm_ptr(nand, sect);
++
++      for (i = 0; i < 4; i++)
++              oobptr[i] = (vall >> (i * 8)) & 0xff;
++
++      for (i = 0; i < 4; i++)
++              oobptr[i + 4] = (valm >> (i * 8)) & 0xff;
++}
++
++static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf,
++                                    int oob_required, int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      int bitflips = 0;
++      int rc, i;
++
++      nand_read_page_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++                  CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++      mt7621_ecc_decoder_op(nfc, true);
++
++      nfi_write16(nfc, NFI_CON,
++                  CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              if (buf)
++                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++                                           nand->ecc.size);
++              else
++                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++              rc = mt7621_ecc_decoder_wait_done(nfc, i);
++
++              mt7621_nfc_read_sector_fdm(nfc, i);
++
++              if (rc < 0) {
++                      bitflips = -EIO;
++                      continue;
++              }
++
++              rc = mt7621_ecc_correct_check(nfc,
++                      buf ? page_data_ptr(nand, buf, i) : NULL,
++                      oob_fdm_ptr(nand, i), i);
++
++              if (rc < 0) {
++                      dev_warn(nfc->dev,
++                               "Uncorrectable ECC error at page %d.%d\n",
++                               page, i);
++                      bitflips = -EBADMSG;
++                      mtd->ecc_stats.failed++;
++              } else if (bitflips >= 0) {
++                      bitflips += rc;
++                      mtd->ecc_stats.corrected += rc;
++              }
++      }
++
++      mt7621_ecc_decoder_op(nfc, false);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return bitflips;
++}
++
++static int mt7621_nfc_read_page_raw(struct nand_chip *nand, uint8_t *buf,
++                                  int oob_required, int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int i;
++
++      nand_read_page_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++                  CNFG_READ_MODE);
++
++      nfi_write16(nfc, NFI_CON,
++                  CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S));
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              /* Read data */
++              if (buf)
++                      mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i),
++                                           nand->ecc.size);
++              else
++                      mt7621_nfc_read_data_discard(nfc, nand->ecc.size);
++
++              /* Read FDM */
++              mt7621_nfc_read_data(nfc, oob_fdm_ptr(nand, i), NFI_FDM_SIZE);
++
++              /* Read ECC parity data */
++              mt7621_nfc_read_data(nfc, oob_ecc_ptr(nfc, i),
++                                   nfc->spare_per_sector - NFI_FDM_SIZE);
++      }
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return 0;
++}
++
++static int mt7621_nfc_read_oob_hwecc(struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_read_page_hwecc(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_read_oob_raw(struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_read_page_raw(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_check_empty_page(struct nand_chip *nand, const u8 *buf)
++{
++      struct mtd_info *mtd = nand_to_mtd(nand);
++      uint32_t i, j;
++      u8 *oobptr;
++
++      if (buf) {
++              for (i = 0; i < mtd->writesize; i++)
++                      if (buf[i] != 0xff)
++                              return 0;
++      }
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              oobptr = oob_fdm_ptr(nand, i);
++              for (j = 0; j < NFI_FDM_SIZE; j++)
++                      if (oobptr[j] != 0xff)
++                              return 0;
++      }
++
++      return 1;
++}
++
++static int mt7621_nfc_write_page_hwecc(struct nand_chip *nand,
++                                     const uint8_t *buf, int oob_required,
++                                     int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      struct mtd_info *mtd = nand_to_mtd(nand);
++
++      if (mt7621_nfc_check_empty_page(nand, buf)) {
++              /*
++               * MT7621 ECC engine always generates parity code for input
++               * pages, even for empty pages. Doing so will write back ECC
++               * parity code to the oob region, which means such pages will
++               * no longer be empty pages.
++               *
++               * To avoid this, stop write operation if current page is an
++               * empty page.
++               */
++              return 0;
++      }
++
++      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) |
++                 CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN);
++
++      mt7621_ecc_encoder_op(nfc, true);
++
++      mt7621_nfc_write_fdm(nfc);
++
++      nfi_write16(nfc, NFI_CON,
++                  CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
++
++      if (buf)
++              mt7621_nfc_write_data(nfc, buf, mtd->writesize);
++      else
++              mt7621_nfc_write_data_empty(nfc, mtd->writesize);
++
++      mt7621_nfc_wait_write_completion(nfc, nand);
++
++      mt7621_ecc_encoder_op(nfc, false);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_page_raw(struct nand_chip *nand,
++                                   const uint8_t *buf, int oob_required,
++                                   int page)
++{
++      struct mt7621_nfc *nfc = nand_get_controller_data(nand);
++      int i;
++
++      nand_prog_page_begin_op(nand, page, 0, NULL, 0);
++
++      nfi_write16(nfc, NFI_CNFG, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S));
++
++      nfi_write16(nfc, NFI_CON,
++                  CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S));
++
++      for (i = 0; i < nand->ecc.steps; i++) {
++              /* Write data */
++              if (buf)
++                      mt7621_nfc_write_data(nfc, page_data_ptr(nand, buf, i),
++                                            nand->ecc.size);
++              else
++                      mt7621_nfc_write_data_empty(nfc, nand->ecc.size);
++
++              /* Write FDM */
++              mt7621_nfc_write_data(nfc, oob_fdm_ptr(nand, i),
++                                    NFI_FDM_SIZE);
++
++              /* Write dummy ECC parity data */
++              mt7621_nfc_write_data_empty(nfc, nfc->spare_per_sector -
++                                          NFI_FDM_SIZE);
++      }
++
++      mt7621_nfc_wait_write_completion(nfc, nand);
++
++      nfi_write16(nfc, NFI_CON, 0);
++
++      return nand_prog_page_end_op(nand);
++}
++
++static int mt7621_nfc_write_oob_hwecc(struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_write_page_hwecc(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_write_oob_raw(struct nand_chip *nand, int page)
++{
++      return mt7621_nfc_write_page_raw(nand, NULL, 1, page);
++}
++
++static int mt7621_nfc_init_chip(struct mt7621_nfc *nfc)
++{
++      struct nand_chip *nand = &nfc->nand;
++      struct mtd_info *mtd;
++      int ret;
++
++      nand->controller = &nfc->controller;
++      nand_set_controller_data(nand, (void *)nfc);
++      nand_set_flash_node(nand, nfc->dev->of_node);
++
++      nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_NO_SUBPAGE_WRITE;
++      if (!nfc->nfi_clk)
++              nand->options |= NAND_KEEP_TIMINGS;
++
++      nand->ecc.mode = NAND_ECC_HW_SYNDROME;
++      nand->ecc.read_page = mt7621_nfc_read_page_hwecc;
++      nand->ecc.read_page_raw = mt7621_nfc_read_page_raw;
++      nand->ecc.write_page = mt7621_nfc_write_page_hwecc;
++      nand->ecc.write_page_raw = mt7621_nfc_write_page_raw;
++      nand->ecc.read_oob = mt7621_nfc_read_oob_hwecc;
++      nand->ecc.read_oob_raw = mt7621_nfc_read_oob_raw;
++      nand->ecc.write_oob = mt7621_nfc_write_oob_hwecc;
++      nand->ecc.write_oob_raw = mt7621_nfc_write_oob_raw;
++
++      mtd = nand_to_mtd(nand);
++      mtd->owner = THIS_MODULE;
++      mtd->dev.parent = nfc->dev;
++      mtd->name = MT7621_NFC_NAME;
++      mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops);
++
++      mt7621_nfc_hw_init(nfc);
++
++      ret = nand_scan(nand, 1);
++      if (ret)
++              return ret;
++
++      ret = mtd_device_register(mtd, NULL, 0);
++      if (ret) {
++              dev_err(nfc->dev, "Failed to register MTD: %d\n", ret);
++              nand_release(nand);
++              return ret;
++      }
++
++      return 0;
++}
++
++static int mt7621_nfc_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct mt7621_nfc *nfc;
++      struct resource *res;
++      int ret;
++
++      nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL);
++      if (!nfc)
++              return -ENOMEM;
++
++      nand_controller_init(&nfc->controller);
++      nfc->controller.ops = &mt7621_nfc_controller_ops;
++      nfc->dev = dev;
++
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nfi");
++      nfc->nfi_regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(nfc->nfi_regs)) {
++              ret = PTR_ERR(nfc->nfi_regs);
++              return ret;
++      }
++
++      res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ecc");
++      nfc->ecc_regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(nfc->ecc_regs)) {
++              ret = PTR_ERR(nfc->ecc_regs);
++              return ret;
++      }
++
++      nfc->nfi_clk = devm_clk_get(dev, "nfi_clk");
++      if (IS_ERR(nfc->nfi_clk)) {
++              dev_warn(dev, "nfi clk not provided\n");
++              nfc->nfi_clk = NULL;
++      } else {
++              ret = clk_prepare_enable(nfc->nfi_clk);
++              if (ret) {
++                      dev_err(dev, "Failed to enable nfi core clock\n");
++                      return ret;
++              }
++      }
++
++      platform_set_drvdata(pdev, nfc);
++
++      ret = mt7621_nfc_init_chip(nfc);
++      if (ret) {
++              dev_err(dev, "Failed to initialize nand chip\n");
++              goto clk_disable;
++      }
++
++      return 0;
++
++clk_disable:
++      clk_disable_unprepare(nfc->nfi_clk);
++
++      return ret;
++}
++
++static int mt7621_nfc_remove(struct platform_device *pdev)
++{
++      struct mt7621_nfc *nfc = platform_get_drvdata(pdev);
++
++      nand_release(&nfc->nand);
++      clk_disable_unprepare(nfc->nfi_clk);
++
++      return 0;
++}
++
++static const struct of_device_id mt7621_nfc_id_table[] = {
++      { .compatible = "mediatek,mt7621-nfc" },
++      { },
++};
++MODULE_DEVICE_TABLE(of, match);
++
++static struct platform_driver mt7621_nfc_driver = {
++      .probe = mt7621_nfc_probe,
++      .remove = mt7621_nfc_remove,
++      .driver = {
++              .name = MT7621_NFC_NAME,
++              .owner = THIS_MODULE,
++              .of_match_table = mt7621_nfc_id_table,
++      },
++};
++module_platform_driver(mt7621_nfc_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
++MODULE_DESCRIPTION("MediaTek MT7621 NAND Flash Controller driver");
diff --git a/target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch b/target/linux/ramips/patches-5.10/411-dt-bindings-add-documentation-for-mt7621-nand-driver.patch
new file mode 100644 (file)
index 0000000..3d122c1
--- /dev/null
@@ -0,0 +1,85 @@
+From 3d5f4da8296b23eb3abf8b13122b0d06a215e79c Mon Sep 17 00:00:00 2001
+From: Weijie Gao <weijie.gao@mediatek.com>
+Date: Wed, 1 Apr 2020 02:07:59 +0800
+Subject: [PATCH 2/2] dt-bindings: add documentation for mt7621-nand driver
+
+This patch adds documentation for MediaTek MT7621 NAND flash controller
+driver.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+---
+ .../bindings/mtd/mediatek,mt7621-nfc.yaml          | 68 ++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
+@@ -0,0 +1,68 @@
++# SPDX-License-Identifier: GPL-2.0
++%YAML 1.2
++---
++$id: http://devicetree.org/schemas/mtd/mediatek,mt7621-nfc.yaml#
++$schema: http://devicetree.org/meta-schemas/core.yaml#
++
++title: MediaTek MT7621 SoC NAND Flash Controller (NFC) DT binding
++
++maintainers:
++  - Weijie Gao <weijie.gao@mediatek.com>
++
++description: |
++  This driver uses a single node to describe both NAND Flash controller
++  interface (NFI) and ECC engine for MT7621 SoC.
++  MT7621 supports only one chip select.
++
++properties:
++  "#address-cells": false
++  "#size-cells": false
++
++  compatible:
++    enum:
++      - mediatek,mt7621-nfc
++
++  reg:
++    items:
++      - description: Register base of NFI core
++      - description: Register base of ECC engine
++
++  reg-names:
++    items:
++      - const: nfi
++      - const: ecc
++
++  clocks:
++    items:
++      - description: Source clock for NFI core, fixed 125MHz
++
++  clock-names:
++    items:
++      - const: nfi_clk
++
++required:
++  - compatible
++  - reg
++  - reg-names
++  - clocks
++  - clock-names
++
++examples:
++  - |
++    nficlock: nficlock {
++      #clock-cells = <0>;
++      compatible = "fixed-clock";
++
++      clock-frequency = <125000000>;
++    };
++
++    nand@1e003000 {
++      compatible = "mediatek,mt7621-nfc";
++
++      reg = <0x1e003000 0x800
++             0x1e003800 0x800>;
++      reg-names = "nfi", "ecc";
++
++      clocks = <&nficlock>;
++      clock-names = "nfi_clk";
++    };
diff --git a/target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch b/target/linux/ramips/patches-5.10/420-spi-nor-add-gd25q512.patch
new file mode 100644 (file)
index 0000000..7fcf0c5
--- /dev/null
@@ -0,0 +1,14 @@
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -2303,6 +2303,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,
++                      SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
++                      SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES)
++      },
+       /* Intel/Numonyx -- xxxs33b */
+       { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
diff --git a/target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.10/700-net-ethernet-mediatek-support-net-labels.patch
new file mode 100644 (file)
index 0000000..6583fca
--- /dev/null
@@ -0,0 +1,34 @@
+From bd0f89de5476ca25e73fae829ba3e1dafae1d90d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
+Date: Fri, 21 Jun 2019 10:04:05 +0200
+Subject: [PATCH] net: ethernet: mediatek: support net-labels
+
+With this patch, device name can be set within dts file in the same way as dsa
+port can.
+Add: label = "wan"; to GMAC node.
+
+Signed-off-by: RenĂ© van Dorst <opensource@vdorst.com>
+---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -2922,6 +2922,7 @@ static const struct net_device_ops mtk_n
+ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+ {
++      const char *name = of_get_property(np, "label", NULL);
+       const __be32 *_id = of_get_property(np, "reg", NULL);
+       struct phylink *phylink;
+       int phy_mode, id, err;
+@@ -3014,6 +3015,9 @@ static int mtk_add_mac(struct mtk_eth *e
+       eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
++      if (name)
++              strlcpy(eth->netdev[id]->name, name, IFNAMSIZ);
++
+       return 0;
+ free_netdev:
diff --git a/target/linux/ramips/patches-5.10/710-at803x.patch b/target/linux/ramips/patches-5.10/710-at803x.patch
new file mode 100644 (file)
index 0000000..af0132f
--- /dev/null
@@ -0,0 +1,156 @@
+From 924453aa9d2324e5611f8e2b71df746d8f0c79f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
+Date: Fri, 13 Nov 2020 16:11:32 +0100
+Subject: [PATCH] net: phy: at803x: add support for SFP module in
+ RGMII-to-x-base mode
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: RenĂ© van Dorst <opensource@vdorst.com>
+---
+ drivers/net/phy/at803x.c | 91 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 91 insertions(+)
+
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -14,6 +14,8 @@
+ #include <linux/etherdevice.h>
+ #include <linux/of_gpio.h>
+ #include <linux/gpio/consumer.h>
++#include <linux/sfp.h>
++#include <linux/phylink.h>
+ #define AT803X_SPECIFIC_STATUS                        0x11
+ #define AT803X_SS_SPEED_MASK                  (3 << 14)
+@@ -53,9 +55,18 @@
+ #define AT803X_MODE_CFG_MASK                  0x0F
+ #define AT803X_MODE_CFG_SGMII                 0x01
++#define AT803X_MODE_CFG_BX1000_RGMII_50               0x02
++#define AT803X_MODE_CFG_BX1000_RGMII_75               0x03
++#define AT803X_MODE_FIBER                     0x01
++#define AT803X_MODE_COPPER                    0x00
+ #define AT803X_PSSR                   0x11    /*PHY-Specific Status Register*/
+ #define AT803X_PSSR_MR_AN_COMPLETE    0x0200
++#define        PSSR_LINK                      BIT(10)
++#define        PSSR_SYNC_STATUS               BIT(8)
++#define        PSSR_DUPLEX                    BIT(13)
++#define        PSSR_SPEED_1000                BIT(15)
++#define        PSSR_SPEED_100                 BIT(14)
+ #define AT803X_DEBUG_REG_0                    0x00
+ #define AT803X_DEBUG_RX_CLK_DLY_EN            BIT(15)
+@@ -243,10 +254,72 @@ static int at803x_resume(struct phy_devi
+       return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
+ }
++static int at803x_mode(struct phy_device *phydev)
++{
++      int mode;
++
++      mode = phy_read(phydev, AT803X_REG_CHIP_CONFIG) & AT803X_MODE_CFG_MASK;
++
++      if (mode == AT803X_MODE_CFG_BX1000_RGMII_50 ||
++          mode == AT803X_MODE_CFG_BX1000_RGMII_75)
++              return AT803X_MODE_FIBER;
++      return AT803X_MODE_COPPER;
++}
++
++static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
++{
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(at803x_support) = { 0, };
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
++      struct phy_device *phydev = upstream;
++      phy_interface_t iface;
++
++      phylink_set(at803x_support, 1000baseX_Full);
++      /* AT803x only support 1000baseX but SGMII works fine when module runs
++       * at 1Gbit.
++       */
++      phylink_set(at803x_support, 1000baseT_Full);
++
++      sfp_parse_support(phydev->sfp_bus, id, support);
++
++      // Limit to interfaces that both sides support
++      linkmode_and(support, support, at803x_support);
++
++      if (linkmode_empty(support))
++              goto unsupported_mode;
++
++      iface = sfp_select_interface(phydev->sfp_bus, support);
++
++      if (iface != PHY_INTERFACE_MODE_SGMII &&
++          iface != PHY_INTERFACE_MODE_1000BASEX)
++              goto unsupported_mode;
++
++      dev_info(&phydev->mdio.dev, "SFP interface %s", phy_modes(iface));
++
++      return 0;
++
++unsupported_mode:
++      dev_info(&phydev->mdio.dev, "incompatible SFP module inserted;"
++               "Only SGMII at 1Gbit/1000BASEX are supported!\n");
++      return -EINVAL;
++}
++
++static const struct sfp_upstream_ops at803x_sfp_ops = {
++      .attach = phy_sfp_attach,
++      .detach = phy_sfp_detach,
++      .module_insert = at803x_sfp_insert,
++};
++
+ static int at803x_probe(struct phy_device *phydev)
+ {
+       struct device *dev = &phydev->mdio.dev;
+       struct at803x_priv *priv;
++      int ret;
++
++      if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
++              ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
++              if (ret < 0)
++                      return ret;
++      }
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+@@ -394,6 +467,10 @@ static int at803x_read_status(struct phy
+ {
+       int ss, err, old_link = phydev->link;
++      /* Handle (Fiber) SGMII to RGMII mode */
++      if (at803x_mode(phydev) == AT803X_MODE_FIBER)
++              return genphy_c37_read_status(phydev);
++
+       /* Update the link, but return if there was an error */
+       err = genphy_update_link(phydev);
+       if (err)
+@@ -448,6 +525,19 @@ static int at803x_read_status(struct phy
+       return 0;
+ }
++static int at803x_config_aneg(struct phy_device *phydev)
++{
++      /* Handle (Fiber) SerDes to RGMII mode */
++      if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
++              pr_warn("%s: fiber\n", __func__);
++              return genphy_c37_config_aneg(phydev);
++      }
++
++      pr_warn("%s: enter\n", __func__);
++
++      return genphy_config_aneg(phydev);
++}
++
+ static struct phy_driver at803x_driver[] = {
+ {
+       /* ATHEROS 8035 */
+@@ -491,6 +581,7 @@ static struct phy_driver at803x_driver[]
+       .suspend                = at803x_suspend,
+       .resume                 = at803x_resume,
+       /* PHY_GBIT_FEATURES */
++      .config_aneg            = at803x_config_aneg,
+       .read_status            = at803x_read_status,
+       .aneg_done              = at803x_aneg_done,
+       .ack_interrupt          = &at803x_ack_interrupt,
diff --git a/target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch b/target/linux/ramips/patches-5.10/721-NET-no-auto-carrier-off-support.patch
new file mode 100644 (file)
index 0000000..a31d1ac
--- /dev/null
@@ -0,0 +1,47 @@
+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
+@@ -546,7 +546,10 @@ static int phy_check_link_status(struct
+               phy_link_up(phydev);
+       } else if (!phydev->link && phydev->state != PHY_NOLINK) {
+               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);
+       }
+       return 0;
+@@ -926,7 +929,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
+@@ -380,6 +380,7 @@ struct phy_device {
+       unsigned suspended_by_mdio_bus:1;
+       unsigned sysfs_links:1;
+       unsigned loopback_enabled:1;
++      unsigned no_auto_carrier_off:1;
+       unsigned autoneg:1;
+       /* The most recently read link state */
diff --git a/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch b/target/linux/ramips/patches-5.10/800-GPIO-add-named-gpio-exports.patch
new file mode 100644 (file)
index 0000000..d4ea379
--- /dev/null
@@ -0,0 +1,165 @@
+From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 12 Aug 2014 20:49:27 +0200
+Subject: [PATCH 24/53] GPIO: add named gpio exports
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  |   10 +++++-
+ include/asm-generic/gpio.h    |    6 ++++
+ include/linux/gpio/consumer.h |    8 +++++
+ 4 files changed, 91 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib-of.c
++++ b/drivers/gpio/gpiolib-of.c
+@@ -19,6 +19,8 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/slab.h>
+ #include <linux/gpio/machine.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
+ #include "gpiolib.h"
+ #include "gpiolib-of.h"
+@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip
+ {
+       of_node_put(chip->of_node);
+ }
++
++static struct of_device_id gpio_export_ids[] = {
++      { .compatible = "gpio-export" },
++      { /* sentinel */ }
++};
++
++static int of_gpio_export_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct device_node *cnp;
++      u32 val;
++      int nb = 0;
++
++      for_each_child_of_node(np, cnp) {
++              const char *name = NULL;
++              int gpio;
++              bool dmc;
++              int max_gpio = 1;
++              int i;
++
++              of_property_read_string(cnp, "gpio-export,name", &name);
++
++              if (!name)
++                      max_gpio = of_gpio_count(cnp);
++
++              for (i = 0; i < max_gpio; i++) {
++                      unsigned flags = 0;
++                      enum of_gpio_flags of_flags;
++
++                      gpio = of_get_gpio_flags(cnp, i, &of_flags);
++                      if (!gpio_is_valid(gpio))
++                              return gpio;
++
++                      if (of_flags == OF_GPIO_ACTIVE_LOW)
++                              flags |= GPIOF_ACTIVE_LOW;
++
++                      if (!of_property_read_u32(cnp, "gpio-export,output", &val))
++                              flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
++                      else
++                              flags |= GPIOF_IN;
++
++                      if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
++                              continue;
++
++                      dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
++                      gpio_export_with_name(gpio, dmc, name);
++                      nb++;
++              }
++      }
++
++      dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
++
++      return 0;
++}
++
++static struct platform_driver gpio_export_driver = {
++      .driver         = {
++              .name           = "gpio-export",
++              .owner  = THIS_MODULE,
++              .of_match_table = of_match_ptr(gpio_export_ids),
++      },
++      .probe          = of_gpio_export_probe,
++};
++
++module_platform_driver(gpio_export_driver);
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -563,7 +563,7 @@ static struct class gpio_class = {
+  *
+  * Returns zero on success, else an error.
+  */
+-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
+ {
+       struct gpio_chip        *chip;
+       struct gpio_device      *gdev;
+@@ -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];
++      if (name)
++              ioname = name;
+       dev = device_create_with_groups(&gpio_class, &gdev->dev,
+                                       MKDEV(0, 0), data, gpio_groups,
+@@ -646,6 +648,12 @@ err_unlock:
+       gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       return status;
+ }
++EXPORT_SYMBOL_GPL(__gpiod_export);
++
++int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++{
++      return __gpiod_export(desc, direction_may_change, NULL);
++}
+ EXPORT_SYMBOL_GPL(gpiod_export);
+ static int match_export(struct device *dev, const void *desc)
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
+       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ }
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
++{
++      return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
++}
++
+ static inline int gpio_export_link(struct device *dev, const char *name,
+                                  unsigned gpio)
+ {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_
+ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+ 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);
+@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de
+ #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
++static inline int _gpiod_export(struct gpio_desc *desc,
++                             bool direction_may_change,
++                             const char *name)
++{
++      return -ENOSYS;
++}
++
+ static inline int gpiod_export(struct gpio_desc *desc,
+                              bool direction_may_change)
+ {
diff --git a/target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch b/target/linux/ramips/patches-5.10/801-DT-Add-documentation-for-gpio-ralink.patch
new file mode 100644 (file)
index 0000000..7d5f98f
--- /dev/null
@@ -0,0 +1,59 @@
+From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 28 Jul 2013 19:45:30 +0200
+Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
+
+Describe gpio-ralink binding.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Cc: devicetree@vger.kernel.org
+Cc: linux-gpio@vger.kernel.org
+---
+ .../devicetree/bindings/gpio/gpio-ralink.txt       |   40 ++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+@@ -0,0 +1,40 @@
++Ralink SoC GPIO controller bindings
++
++Required properties:
++- compatible:
++  - "ralink,rt2880-gpio" for Ralink controllers
++- #gpio-cells : Should be two.
++  - first cell is the pin number
++  - second cell is used to specify optional parameters (unused)
++- gpio-controller : Marks the device node as a GPIO controller
++- reg : Physical base address and length of the controller's registers
++- interrupt-parent: phandle to the INTC device node
++- interrupts : Specify the INTC interrupt number
++- ralink,num-gpios : Specify the number of GPIOs
++- ralink,register-map : The register layout depends on the GPIO bank and actual
++              SoC type. Register offsets need to be in this order.
++              [ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
++
++Optional properties:
++- ralink,gpio-base : Specify the GPIO chips base number
++
++Example:
++
++      gpio0: gpio@600 {
++              compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
++
++              #gpio-cells = <2>;
++              gpio-controller;
++
++              reg = <0x600 0x34>;
++
++              interrupt-parent = <&intc>;
++              interrupts = <6>;
++
++              ralink,gpio-base = <0>;
++              ralink,num-gpios = <24>;
++              ralink,register-map = [ 00 04 08 0c
++                              20 24 28 2c
++                              30 34 ];
++
++      };
diff --git a/target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch b/target/linux/ramips/patches-5.10/802-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch
new file mode 100644 (file)
index 0000000..eae507b
--- /dev/null
@@ -0,0 +1,416 @@
+From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Aug 2014 20:36:29 +0200
+Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
+
+Add gpio driver for Ralink SoC. This driver makes the gpio core on
+RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Cc: linux-gpio@vger.kernel.org
+---
+ arch/mips/include/asm/mach-ralink/gpio.h |   24 ++
+ drivers/gpio/Kconfig                     |    6 +
+ drivers/gpio/Makefile                    |    1 +
+ drivers/gpio/gpio-ralink.c               |  355 ++++++++++++++++++++++++++++++
+ 4 files changed, 386 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
+ create mode 100644 drivers/gpio/gpio-ralink.c
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/gpio.h
+@@ -0,0 +1,24 @@
++/*
++ *  Ralink SoC GPIO API support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ *
++ */
++
++#ifndef __ASM_MACH_RALINK_GPIO_H
++#define __ASM_MACH_RALINK_GPIO_H
++
++#define ARCH_NR_GPIOS 128
++#include <asm-generic/gpio.h>
++
++#define gpio_get_value        __gpio_get_value
++#define gpio_set_value        __gpio_set_value
++#define gpio_cansleep __gpio_cansleep
++#define gpio_to_irq   __gpio_to_irq
++
++#endif /* __ASM_MACH_RALINK_GPIO_H */
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -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"
++      depends on RALINK
++      help
++        Say yes here to support the Ralink SoC GPIO device
++
+ config GPIO_SPEAR_SPICS
+       bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+       depends on PLAT_SPEAR
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -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,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
++ * by the Free Software Foundation.
++ *
++ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/of_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/interrupt.h>
++
++enum ralink_gpio_reg {
++      GPIO_REG_INT = 0,
++      GPIO_REG_EDGE,
++      GPIO_REG_RENA,
++      GPIO_REG_FENA,
++      GPIO_REG_DATA,
++      GPIO_REG_DIR,
++      GPIO_REG_POL,
++      GPIO_REG_SET,
++      GPIO_REG_RESET,
++      GPIO_REG_TOGGLE,
++      GPIO_REG_MAX
++};
++
++struct ralink_gpio_chip {
++      struct gpio_chip chip;
++      u8 regs[GPIO_REG_MAX];
++
++      spinlock_t lock;
++      void __iomem *membase;
++      struct irq_domain *domain;
++      int irq;
++
++      u32 rising;
++      u32 falling;
++};
++
++#define MAP_MAX       4
++static struct irq_domain *irq_map[MAP_MAX];
++static int irq_map_count;
++static atomic_t irq_refcount = ATOMIC_INIT(0);
++
++static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
++{
++      struct ralink_gpio_chip *rg;
++
++      rg = container_of(chip, struct ralink_gpio_chip, chip);
++
++      return rg;
++}
++
++static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
++{
++      iowrite32(val, rg->membase + rg->regs[reg]);
++}
++
++static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
++{
++      return ioread32(rg->membase + rg->regs[reg]);
++}
++
++static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
++}
++
++static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
++}
++
++static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      t = rt_gpio_r32(rg, GPIO_REG_DIR);
++      t &= ~BIT(offset);
++      rt_gpio_w32(rg, GPIO_REG_DIR, t);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int ralink_gpio_direction_output(struct gpio_chip *chip,
++                                      unsigned offset, int value)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      ralink_gpio_set(chip, offset, value);
++      t = rt_gpio_r32(rg, GPIO_REG_DIR);
++      t |= BIT(offset);
++      rt_gpio_w32(rg, GPIO_REG_DIR, t);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      if (rg->irq < 1)
++              return -1;
++
++      return irq_create_mapping(rg->domain, pin);
++}
++
++static void ralink_gpio_irq_handler(struct irq_desc *desc)
++{
++      int i;
++
++      for (i = 0; i < irq_map_count; i++) {
++              struct irq_domain *domain = irq_map[i];
++              struct ralink_gpio_chip *rg;
++              unsigned long pending;
++              int bit;
++
++              rg = (struct ralink_gpio_chip *) domain->host_data;
++              pending = rt_gpio_r32(rg, GPIO_REG_INT);
++
++              for_each_set_bit(bit, &pending, rg->chip.ngpio) {
++                      u32 map = irq_find_mapping(domain, bit);
++                      generic_handle_irq(map);
++                      rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
++              }
++      }
++}
++
++static void ralink_gpio_irq_unmask(struct irq_data *d)
++{
++      struct ralink_gpio_chip *rg;
++      unsigned long flags;
++      u32 rise, fall;
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
++      rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static void ralink_gpio_irq_mask(struct irq_data *d)
++{
++      struct ralink_gpio_chip *rg;
++      unsigned long flags;
++      u32 rise, fall;
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
++      rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++      struct ralink_gpio_chip *rg;
++      u32 mask = BIT(d->hwirq);
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++
++      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 ralink_gpio_irq_chip = {
++      .name           = "GPIO",
++      .irq_unmask     = ralink_gpio_irq_unmask,
++      .irq_mask       = ralink_gpio_irq_mask,
++      .irq_mask_ack   = ralink_gpio_irq_mask,
++      .irq_set_type   = ralink_gpio_irq_type,
++};
++
++static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
++{
++      irq_set_chip_and_handler(irq, &ralink_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 = gpio_map,
++};
++
++static void ralink_gpio_irq_init(struct device_node *np,
++                               struct ralink_gpio_chip *rg)
++{
++      if (irq_map_count >= MAP_MAX)
++              return;
++
++      rg->irq = irq_of_parse_and_map(np, 0);
++      if (!rg->irq)
++              return;
++
++      rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
++                                         &irq_domain_ops, rg);
++      if (!rg->domain) {
++              dev_err(rg->chip.parent, "irq_domain_add_linear failed\n");
++              return;
++      }
++
++      irq_map[irq_map_count++] = rg->domain;
++
++      rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
++      rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
++
++      if (!atomic_read(&irq_refcount))
++              irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
++      atomic_inc(&irq_refcount);
++
++      dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio);
++}
++
++static int ralink_gpio_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      struct ralink_gpio_chip *rg;
++      const __be32 *ngpio, *gpiobase;
++
++      if (!res) {
++              dev_err(&pdev->dev, "failed to find resource\n");
++              return -ENOMEM;
++      }
++
++      rg = devm_kzalloc(&pdev->dev,
++                      sizeof(struct ralink_gpio_chip), GFP_KERNEL);
++      if (!rg)
++              return -ENOMEM;
++
++      rg->membase = devm_ioremap_resource(&pdev->dev, res);
++      if (!rg->membase) {
++              dev_err(&pdev->dev, "cannot remap I/O memory region\n");
++              return -ENOMEM;
++      }
++
++      if (of_property_read_u8_array(np, "ralink,register-map",
++                      rg->regs, GPIO_REG_MAX)) {
++              dev_err(&pdev->dev, "failed to read register definition\n");
++              return -EINVAL;
++      }
++
++      ngpio = of_get_property(np, "ralink,num-gpios", NULL);
++      if (!ngpio) {
++              dev_err(&pdev->dev, "failed to read number of pins\n");
++              return -EINVAL;
++      }
++
++      gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
++      if (gpiobase)
++              rg->chip.base = be32_to_cpu(*gpiobase);
++      else
++              rg->chip.base = -1;
++
++      spin_lock_init(&rg->lock);
++
++      rg->chip.parent = &pdev->dev;
++      rg->chip.label = dev_name(&pdev->dev);
++      rg->chip.of_node = np;
++      rg->chip.ngpio = be32_to_cpu(*ngpio);
++      rg->chip.direction_input = ralink_gpio_direction_input;
++      rg->chip.direction_output = ralink_gpio_direction_output;
++      rg->chip.get = ralink_gpio_get;
++      rg->chip.set = ralink_gpio_set;
++      rg->chip.request = gpiochip_generic_request;
++      rg->chip.to_irq = ralink_gpio_to_irq;
++      rg->chip.free = gpiochip_generic_free;
++
++      /* set polarity to low for all lines */
++      rt_gpio_w32(rg, GPIO_REG_POL, 0);
++
++      dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
++
++      ralink_gpio_irq_init(np, rg);
++
++      return gpiochip_add(&rg->chip);
++}
++
++static const struct of_device_id ralink_gpio_match[] = {
++      { .compatible = "ralink,rt2880-gpio" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, ralink_gpio_match);
++
++static struct platform_driver ralink_gpio_driver = {
++      .probe = ralink_gpio_probe,
++      .driver = {
++              .name = "rt2880_gpio",
++              .owner = THIS_MODULE,
++              .of_match_table = ralink_gpio_match,
++      },
++};
++
++static int __init ralink_gpio_init(void)
++{
++      return platform_driver_register(&ralink_gpio_driver);
++}
++
++subsys_initcall(ralink_gpio_init);
diff --git a/target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch b/target/linux/ramips/patches-5.10/803-gpio-ralink-Add-support-for-GPIO-as-interrupt-contro.patch
new file mode 100644 (file)
index 0000000..8520ce3
--- /dev/null
@@ -0,0 +1,44 @@
+From 57fa7f2f4ef6f78ce1d30509c0d111aa3791b524 Mon Sep 17 00:00:00 2001
+From: Daniel Santos <daniel.santos@pobox.com>
+Date: Sun, 4 Nov 2018 20:24:32 -0600
+Subject: gpio-ralink: Add support for GPIO as interrupt-controller
+
+Signed-off-by: Daniel Santos <daniel.santos@pobox.com>
+---
+ Documentation/devicetree/bindings/gpio/gpio-ralink.txt | 6 ++++++
+ drivers/gpio/gpio-ralink.c                             | 2 +-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
++++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+@@ -17,6 +17,9 @@ Required properties:
+ Optional properties:
+ - ralink,gpio-base : Specify the GPIO chips base number
++- interrupt-controller : marks this as an interrupt controller
++- #interrupt-cells : a standard two-cell interrupt flag, see
++  interrupt-controller/interrupts.txt
+ Example:
+@@ -28,6 +31,9 @@ Example:
+               reg = <0x600 0x34>;
++              interrupt-controller;
++              #interrupt-cells = <2>;
++
+               interrupt-parent = <&intc>;
+               interrupts = <6>;
+--- a/drivers/gpio/gpio-ralink.c
++++ b/drivers/gpio/gpio-ralink.c
+@@ -220,7 +220,7 @@ static int gpio_map(struct irq_domain *d
+ }
+ static const struct irq_domain_ops irq_domain_ops = {
+-      .xlate = irq_domain_xlate_onecell,
++      .xlate = irq_domain_xlate_twocell,
+       .map = gpio_map,
+ };
diff --git a/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-5.10/810-uvc-add-iPassion-iP2970-support.patch
new file mode 100644 (file)
index 0000000..084b655
--- /dev/null
@@ -0,0 +1,246 @@
+From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 19 Sep 2013 01:50:59 +0200
+Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/media/usb/uvc/uvc_driver.c |   12 +++
+ drivers/media/usb/uvc/uvc_status.c |    2 +
+ drivers/media/usb/uvc/uvc_video.c  |  147 ++++++++++++++++++++++++++++++++++++
+ drivers/media/usb/uvc/uvcvideo.h   |    5 +-
+ 4 files changed, 165 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -2908,6 +2908,18 @@ static const struct usb_device_id uvc_id
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_INFO_META(V4L2_META_FMT_D4XX) },
++      /* iPassion iP2970 */
++      { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++                              | USB_DEVICE_ID_MATCH_INT_INFO,
++       .idVendor              = 0x1B3B,
++       .idProduct             = 0x2970,
++       .bInterfaceClass       = USB_CLASS_VIDEO,
++       .bInterfaceSubClass    = 1,
++       .bInterfaceProtocol    = 0,
++       .driver_info           = UVC_QUIRK_PROBE_MINMAX
++                              | UVC_QUIRK_STREAM_NO_FID
++                              | UVC_QUIRK_MOTION
++                              | UVC_QUIRK_SINGLE_ISO },
+       /* Generic USB Video Class */
+       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
+       { 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
+@@ -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;
+               }
+@@ -271,6 +272,7 @@ int uvc_status_init(struct uvc_device *d
+       }
+       pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
++      dev->motion = 0;
+       /* For high-speed interrupt endpoints, the bInterval value is used as
+        * 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
+@@ -16,6 +16,11 @@
+ #include <linux/wait.h>
+ #include <linux/atomic.h>
+ #include <asm/unaligned.h>
++#include <linux/skbuff.h>
++#include <linux/kobject.h>
++#include <linux/netlink.h>
++#include <linux/kobject.h>
++#include <linux/workqueue.h>
+ #include <media/v4l2-common.h>
+@@ -1156,9 +1161,149 @@ static void uvc_video_decode_data(struct
+       uvc_urb->async_operations++;
+ }
++struct bh_priv {
++      unsigned long   seen;
++};
++
++struct bh_event {
++      const char              *name;
++      struct sk_buff          *skb;
++      struct work_struct      work;
++};
++
++#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
++#define BH_DBG(fmt, args...) do {} while (0)
++#define BH_SKB_SIZE     2048
++
++extern u64 uevent_next_seqnum(void);
++static int seen = 0;
++
++static int bh_event_add_var(struct bh_event *event, int argv,
++              const char *format, ...)
++{
++      static char buf[128];
++      char *s;
++      va_list args;
++      int len;
++
++      if (argv)
++              return 0;
++
++      va_start(args, format);
++      len = vsnprintf(buf, sizeof(buf), format, args);
++      va_end(args);
++
++      if (len >= sizeof(buf)) {
++              BH_ERR("buffer size too small\n");
++              WARN_ON(1);
++              return -ENOMEM;
++      }
++
++      s = skb_put(event->skb, len + 1);
++      strcpy(s, buf);
++
++      BH_DBG("added variable '%s'\n", s);
++
++      return 0;
++}
++
++static int motion_hotplug_fill_event(struct bh_event *event)
++{
++      int s = jiffies;
++      int ret;
++
++      if (!seen)
++              seen = jiffies;
++
++      ret = bh_event_add_var(event, 0, "HOME=%s", "/");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "PATH=%s",
++              "/sbin:/bin:/usr/sbin:/usr/bin");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "ACTION=motion");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
++      if (ret)
++              return ret;
++      seen = s;
++
++      ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
++
++      return ret;
++}
++
++static void motion_hotplug_work(struct work_struct *work)
++{
++      struct bh_event *event = container_of(work, struct bh_event, work);
++      int ret = 0;
++
++      event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
++      if (!event->skb)
++              goto out_free_event;
++
++      ret = bh_event_add_var(event, 0, "%s@", "add");
++      if (ret)
++              goto out_free_skb;
++
++      ret = motion_hotplug_fill_event(event);
++      if (ret)
++              goto out_free_skb;
++
++      NETLINK_CB(event->skb).dst_group = 1;
++      broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
++
++out_free_skb:
++      if (ret) {
++              BH_ERR("work error %d\n", ret);
++              kfree_skb(event->skb);
++      }
++out_free_event:
++      kfree(event);
++}
++
++static int motion_hotplug_create_event(void)
++{
++      struct bh_event *event;
++
++      event = kzalloc(sizeof(*event), GFP_KERNEL);
++      if (!event)
++              return -ENOMEM;
++
++      event->name = "motion";
++
++      INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
++      schedule_work(&event->work);
++
++      return 0;
++}
++
++#define MOTION_FLAG_OFFSET    4
+ static void uvc_video_decode_end(struct uvc_streaming *stream,
+               struct uvc_buffer *buf, const u8 *data, int len)
+ {
++      if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
++                      (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
++              u8 *mem;
++              buf->state = UVC_BUF_STATE_READY;
++              mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
++              if ( stream->dev->motion ) {
++                      stream->dev->motion = 0;
++                      motion_hotplug_create_event();
++              } else {
++                      *mem &= 0x7f;
++              }
++      }
++
+       /* 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");
+@@ -1715,6 +1860,8 @@ static int uvc_init_video_isoc(struct uv
+       if (npackets == 0)
+               return -ENOMEM;
++      if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
++              npackets = 1;
+       size = npackets * psize;
+       for_each_uvc_urb(uvc_urb, stream) {
+--- a/drivers/media/usb/uvc/uvcvideo.h
++++ b/drivers/media/usb/uvc/uvcvideo.h
+@@ -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
++ 
+ /* Format flags */
+ #define UVC_FMT_FLAG_COMPRESSED               0x00000001
+ #define UVC_FMT_FLAG_STREAM           0x00000002
+@@ -666,6 +668,7 @@ struct uvc_device {
+       u8 *status;
+       struct input_dev *input;
+       char input_phys[64];
++      int motion;
+       struct uvc_ctrl_work {
+               struct work_struct work;
diff --git a/target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch b/target/linux/ramips/patches-5.10/820-DT-Add-documentation-for-spi-rt2880.patch
new file mode 100644 (file)
index 0000000..e2643e3
--- /dev/null
@@ -0,0 +1,44 @@
+From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Aug 2013 20:12:59 +0200
+Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880
+
+Describe the SPI master found on the MIPS based Ralink RT2880 SoC.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ .../devicetree/bindings/spi/spi-rt2880.txt         |   28 ++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt
+@@ -0,0 +1,28 @@
++Ralink SoC RT2880 SPI master controller.
++
++This SPI controller is found on most wireless SoCs made by ralink.
++
++Required properties:
++- compatible : "ralink,rt2880-spi"
++- reg : The register base for the controller.
++- #address-cells : <1>, as required by generic SPI binding.
++- #size-cells : <0>, also as required by generic SPI binding.
++
++Child nodes as per the generic SPI binding.
++
++Example:
++
++      spi@b00 {
++              compatible = "ralink,rt2880-spi";
++              reg = <0xb00 0x100>;
++
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              m25p80@0 {
++                      compatible = "m25p80";
++                      reg = <0>;
++                      spi-max-frequency = <10000000>;
++              };
++      };
++
diff --git a/target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-5.10/821-SPI-ralink-add-Ralink-SoC-spi-driver.patch
new file mode 100644 (file)
index 0000000..6523716
--- /dev/null
@@ -0,0 +1,574 @@
+From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 11:15:12 +0100
+Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver
+
+Add the driver needed to make SPI work on Ralink SoC.
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Acked-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/spi/Kconfig      |    6 +
+ drivers/spi/Makefile     |    1 +
+ drivers/spi/spi-rt2880.c |  530 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 537 insertions(+)
+ create mode 100644 drivers/spi/spi-rt2880.c
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -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-geni-qcom.
++config SPI_RT2880
++      tristate "Ralink RT288x SPI Controller"
++      depends on RALINK
++      help
++        This selects a driver for the Ralink RT288x/RT305x SPI Controller.
++
+ config SPI_S3C24XX
+       tristate "Samsung S3C24XX series SPI"
+       depends on ARCH_S3C24XX
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -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
++obj-$(CONFIG_SPI_RT2880)              += spi-rt2880.o
+ obj-$(CONFIG_SPI_S3C24XX)             += spi-s3c24xx-hw.o
+ spi-s3c24xx-hw-y                      := spi-s3c24xx.o
+ spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
+--- /dev/null
++++ b/drivers/spi/spi-rt2880.c
+@@ -0,0 +1,530 @@
++/*
++ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
++ *
++ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
++ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Some parts are based on spi-orion.c:
++ *   Author: Shadi Ammouri <shadi@marvell.com>
++ *   Copyright (C) 2007-2008 Marvell Ltd.
++ *
++ * 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.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/reset.h>
++#include <linux/spi/spi.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
++#define DRIVER_NAME                   "spi-rt2880"
++
++#define RAMIPS_SPI_STAT                       0x00
++#define RAMIPS_SPI_CFG                        0x10
++#define RAMIPS_SPI_CTL                        0x14
++#define RAMIPS_SPI_DATA                       0x20
++#define RAMIPS_SPI_ADDR                       0x24
++#define RAMIPS_SPI_BS                 0x28
++#define RAMIPS_SPI_USER                       0x2C
++#define RAMIPS_SPI_TXFIFO             0x30
++#define RAMIPS_SPI_RXFIFO             0x34
++#define RAMIPS_SPI_FIFO_STAT          0x38
++#define RAMIPS_SPI_MODE                       0x3C
++#define RAMIPS_SPI_DEV_OFFSET         0x40
++#define RAMIPS_SPI_DMA                        0x80
++#define RAMIPS_SPI_DMASTAT            0x84
++#define RAMIPS_SPI_ARBITER            0xF0
++
++/* SPISTAT register bit field */
++#define SPISTAT_BUSY                  BIT(0)
++
++/* SPICFG register bit field */
++#define SPICFG_ADDRMODE                       BIT(12)
++#define SPICFG_RXENVDIS                       BIT(11)
++#define SPICFG_RXCAP                  BIT(10)
++#define SPICFG_SPIENMODE              BIT(9)
++#define SPICFG_MSBFIRST                       BIT(8)
++#define SPICFG_SPICLKPOL              BIT(6)
++#define SPICFG_RXCLKEDGE_FALLING      BIT(5)
++#define SPICFG_TXCLKEDGE_FALLING      BIT(4)
++#define SPICFG_HIZSPI                 BIT(3)
++#define SPICFG_SPICLK_PRESCALE_MASK   0x7
++#define SPICFG_SPICLK_DIV2            0
++#define SPICFG_SPICLK_DIV4            1
++#define SPICFG_SPICLK_DIV8            2
++#define SPICFG_SPICLK_DIV16           3
++#define SPICFG_SPICLK_DIV32           4
++#define SPICFG_SPICLK_DIV64           5
++#define SPICFG_SPICLK_DIV128          6
++#define SPICFG_SPICLK_DISABLE         7
++
++/* SPICTL register bit field */
++#define SPICTL_START                  BIT(4)
++#define SPICTL_HIZSDO                 BIT(3)
++#define SPICTL_STARTWR                        BIT(2)
++#define SPICTL_STARTRD                        BIT(1)
++#define SPICTL_SPIENA                 BIT(0)
++
++/* SPIUSER register bit field */
++#define SPIUSER_USERMODE              BIT(21)
++#define SPIUSER_INSTR_PHASE           BIT(20)
++#define SPIUSER_ADDR_PHASE_MASK               0x7
++#define SPIUSER_ADDR_PHASE_OFFSET     17
++#define SPIUSER_MODE_PHASE            BIT(16)
++#define SPIUSER_DUMMY_PHASE_MASK      0x3
++#define SPIUSER_DUMMY_PHASE_OFFSET    14
++#define SPIUSER_DATA_PHASE_MASK               0x3
++#define SPIUSER_DATA_PHASE_OFFSET     12
++#define SPIUSER_DATA_READ             (BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_DATA_WRITE            (BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
++#define SPIUSER_ADDR_TYPE_OFFSET      9
++#define SPIUSER_MODE_TYPE_OFFSET      6
++#define SPIUSER_DUMMY_TYPE_OFFSET     3
++#define SPIUSER_DATA_TYPE_OFFSET      0
++#define SPIUSER_TRANSFER_MASK         0x7
++#define SPIUSER_TRANSFER_SINGLE               BIT(0)
++#define SPIUSER_TRANSFER_DUAL         BIT(1)
++#define SPIUSER_TRANSFER_QUAD         BIT(2)
++
++#define SPIUSER_TRANSFER_TYPE(type) ( \
++      (type << SPIUSER_ADDR_TYPE_OFFSET) | \
++      (type << SPIUSER_MODE_TYPE_OFFSET) | \
++      (type << SPIUSER_DUMMY_TYPE_OFFSET) | \
++      (type << SPIUSER_DATA_TYPE_OFFSET) \
++)
++
++/* SPIFIFOSTAT register bit field */
++#define SPIFIFOSTAT_TXEMPTY           BIT(19)
++#define SPIFIFOSTAT_RXEMPTY           BIT(18)
++#define SPIFIFOSTAT_TXFULL            BIT(17)
++#define SPIFIFOSTAT_RXFULL            BIT(16)
++#define SPIFIFOSTAT_FIFO_MASK         0xff
++#define SPIFIFOSTAT_TX_OFFSET         8
++#define SPIFIFOSTAT_RX_OFFSET         0
++
++#define SPI_FIFO_DEPTH                        16
++
++/* SPIMODE register bit field */
++#define SPIMODE_MODE_OFFSET           24
++#define SPIMODE_DUMMY_OFFSET          0
++
++/* SPIARB register bit field */
++#define SPICTL_ARB_EN                 BIT(31)
++#define SPICTL_CSCTL1                 BIT(16)
++#define SPI1_POR                      BIT(1)
++#define SPI0_POR                      BIT(0)
++
++#define RT2880_SPI_MODE_BITS  (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
++              SPI_CS_HIGH)
++
++static atomic_t hw_reset_count = ATOMIC_INIT(0);
++
++struct rt2880_spi {
++      struct spi_master       *master;
++      void __iomem            *base;
++      u32                     speed;
++      u16                     wait_loops;
++      u16                     mode;
++      struct clk              *clk;
++};
++
++static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
++{
++      return spi_master_get_devdata(spi->master);
++}
++
++static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg)
++{
++      return ioread32(rs->base + reg);
++}
++
++static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
++              const u32 val)
++{
++      iowrite32(val, rs->base + reg);
++}
++
++static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask)
++{
++      void __iomem *addr = rs->base + reg;
++
++      iowrite32((ioread32(addr) | mask), addr);
++}
++
++static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask)
++{
++      void __iomem *addr = rs->base + reg;
++
++      iowrite32((ioread32(addr) & ~mask), addr);
++}
++
++static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
++{
++      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++      u32 rate;
++      u32 prescale;
++
++      /*
++       * the supported rates are: 2, 4, 8, ... 128
++       * round up as we look for equal or less speed
++       */
++      rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
++      rate = roundup_pow_of_two(rate);
++
++      /* Convert the rate to SPI clock divisor value. */
++      prescale = ilog2(rate / 2);
++
++      /* some tolerance. double and add 100 */
++      rs->wait_loops = (8 * HZ * loops_per_jiffy) /
++              (clk_get_rate(rs->clk) / rate);
++      rs->wait_loops = (rs->wait_loops << 1) + 100;
++      rs->speed = speed;
++
++      dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
++                      clk_get_rate(rs->clk) / rate, speed, rate, prescale,
++                      rs->wait_loops);
++
++      return prescale;
++}
++
++static u32 get_arbiter_offset(struct spi_master *master)
++{
++      u32 offset;
++
++      offset = RAMIPS_SPI_ARBITER;
++      if (master->bus_num == 1)
++              offset -= RAMIPS_SPI_DEV_OFFSET;
++
++      return offset;
++}
++
++static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
++{
++      struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++
++      if (enable)
++              rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++      else
++              rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++}
++
++static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
++{
++      int loop = rs->wait_loops * len;
++
++      while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
++              cpu_relax();
++
++      if (loop)
++              return 0;
++
++      return -ETIMEDOUT;
++}
++
++static void rt2880_dump_reg(struct spi_master *master)
++{
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++
++      dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
++                      "data: %08x, arb: %08x\n",
++                      rt2880_spi_read(rs, RAMIPS_SPI_STAT),
++                      rt2880_spi_read(rs, RAMIPS_SPI_CFG),
++                      rt2880_spi_read(rs, RAMIPS_SPI_CTL),
++                      rt2880_spi_read(rs, RAMIPS_SPI_DATA),
++                      rt2880_spi_read(rs, get_arbiter_offset(master)));
++}
++
++static int rt2880_spi_transfer_one(struct spi_master *master,
++              struct spi_device *spi, struct spi_transfer *xfer)
++{
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      unsigned len;
++      const u8 *tx = xfer->tx_buf;
++      u8 *rx = xfer->rx_buf;
++      int err = 0;
++
++      /* change clock speed  */
++      if (unlikely(rs->speed != xfer->speed_hz)) {
++              u32 reg;
++              reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++              reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
++              reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
++              rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++      }
++
++      if (tx) {
++              len = xfer->len;
++              while (len-- > 0) {
++                      rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
++                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
++                      err = rt2880_spi_wait_ready(rs, 1);
++                      if (err) {
++                              dev_err(&spi->dev, "TX failed, err=%d\n", err);
++                              goto out;
++                      }
++              }
++      }
++
++      if (rx) {
++              len = xfer->len;
++              while (len-- > 0) {
++                      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
++                      err = rt2880_spi_wait_ready(rs, 1);
++                      if (err) {
++                              dev_err(&spi->dev, "RX failed, err=%d\n", err);
++                              goto out;
++                      }
++                      *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
++              }
++      }
++
++out:
++      return err;
++}
++
++/* copy from spi.c */
++static void spi_set_cs(struct spi_device *spi, bool enable)
++{
++      if (spi->mode & SPI_CS_HIGH)
++              enable = !enable;
++
++      if (spi->cs_gpio >= 0)
++              gpio_set_value(spi->cs_gpio, !enable);
++      else if (spi->master->set_cs)
++              spi->master->set_cs(spi, !enable);
++}
++
++static int rt2880_spi_setup(struct spi_device *spi)
++{
++      struct spi_master *master = spi->master;
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      u32 reg, old_reg, arbit_off;
++
++      if ((spi->max_speed_hz > master->max_speed_hz) ||
++                      (spi->max_speed_hz < master->min_speed_hz)) {
++              dev_err(&spi->dev, "invalide requested speed %d Hz\n",
++                              spi->max_speed_hz);
++              return -EINVAL;
++      }
++
++      if (!(master->bits_per_word_mask &
++                              BIT(spi->bits_per_word - 1))) {
++              dev_err(&spi->dev, "invalide bits_per_word %d\n",
++                              spi->bits_per_word);
++              return -EINVAL;
++      }
++
++      /* the hardware seems can't work on mode0 force it to mode3 */
++      if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
++              dev_warn(&spi->dev, "force spi mode3\n");
++              spi->mode |= SPI_MODE_3;
++      }
++
++      /* chip polarity */
++      arbit_off = get_arbiter_offset(master);
++      reg = old_reg = rt2880_spi_read(rs, arbit_off);
++      if (spi->mode & SPI_CS_HIGH) {
++              switch (master->bus_num) {
++              case 1:
++                      reg |= SPI1_POR;
++                      break;
++              default:
++                      reg |= SPI0_POR;
++                      break;
++              }
++      } else {
++              switch (master->bus_num) {
++              case 1:
++                      reg &= ~SPI1_POR;
++                      break;
++              default:
++                      reg &= ~SPI0_POR;
++                      break;
++              }
++      }
++
++      /* enable spi1 */
++      if (master->bus_num == 1)
++              reg |= SPICTL_ARB_EN;
++
++      if (reg != old_reg)
++              rt2880_spi_write(rs, arbit_off, reg);
++
++      /* deselected the spi device */
++      spi_set_cs(spi, false);
++
++      rt2880_dump_reg(master);
++
++      return 0;
++}
++
++static int rt2880_spi_prepare_message(struct spi_master *master,
++              struct spi_message *msg)
++{
++      struct rt2880_spi *rs = spi_master_get_devdata(master);
++      struct spi_device *spi = msg->spi;
++      u32 reg;
++
++      if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
++              return 0;
++
++#if 0
++      /* set spido to tri-state */
++      rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
++#endif
++
++      reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++
++      reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
++                      SPICFG_RXCLKEDGE_FALLING |
++                      SPICFG_TXCLKEDGE_FALLING |
++                      SPICFG_SPICLK_PRESCALE_MASK);
++
++      /* MSB */
++      if (!(spi->mode & SPI_LSB_FIRST))
++              reg |= SPICFG_MSBFIRST;
++
++      /* spi mode */
++      switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
++      case SPI_MODE_0:
++              reg |= SPICFG_TXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_1:
++              reg |= SPICFG_RXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_2:
++              reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
++              break;
++      case SPI_MODE_3:
++              reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
++              break;
++      }
++      rs->mode = spi->mode;
++
++#if 0
++      /* set spiclk and spiena to tri-state */
++      reg |= SPICFG_HIZSPI;
++#endif
++
++      /* clock divide */
++      reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
++
++      rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++
++      return 0;
++}
++
++static int rt2880_spi_probe(struct platform_device *pdev)
++{
++      struct spi_master *master;
++      struct rt2880_spi *rs;
++      void __iomem *base;
++      struct resource *r;
++      struct clk *clk;
++      int ret;
++
++      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\n");
++              return PTR_ERR(clk);
++      }
++
++      ret = clk_prepare_enable(clk);
++      if (ret)
++              goto err_clk;
++
++      master = spi_alloc_master(&pdev->dev, sizeof(*rs));
++      if (master == NULL) {
++              dev_dbg(&pdev->dev, "master allocation failed\n");
++              ret = -ENOMEM;
++              goto err_clk;
++      }
++
++      master->dev.of_node = pdev->dev.of_node;
++      master->mode_bits = RT2880_SPI_MODE_BITS;
++      master->bits_per_word_mask = SPI_BPW_MASK(8);
++      master->min_speed_hz = clk_get_rate(clk) / 128;
++      master->max_speed_hz = clk_get_rate(clk) / 2;
++      master->flags = SPI_MASTER_HALF_DUPLEX;
++      master->setup = rt2880_spi_setup;
++      master->prepare_message = rt2880_spi_prepare_message;
++      master->set_cs = rt2880_spi_set_cs;
++      master->transfer_one = rt2880_spi_transfer_one,
++
++      dev_set_drvdata(&pdev->dev, master);
++
++      rs = spi_master_get_devdata(master);
++      rs->master = master;
++      rs->base = base;
++      rs->clk = clk;
++
++      if (atomic_inc_return(&hw_reset_count) == 1)
++              device_reset(&pdev->dev);
++
++      ret = devm_spi_register_master(&pdev->dev, master);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "devm_spi_register_master error.\n");
++              goto err_master;
++      }
++
++      return ret;
++
++err_master:
++      spi_master_put(master);
++      kfree(master);
++err_clk:
++      clk_disable_unprepare(clk);
++
++      return ret;
++}
++
++static int rt2880_spi_remove(struct platform_device *pdev)
++{
++      struct spi_master *master;
++      struct rt2880_spi *rs;
++
++      master = dev_get_drvdata(&pdev->dev);
++      rs = spi_master_get_devdata(master);
++
++      clk_disable_unprepare(rs->clk);
++      atomic_dec(&hw_reset_count);
++
++      return 0;
++}
++
++MODULE_ALIAS("platform:" DRIVER_NAME);
++
++static const struct of_device_id rt2880_spi_match[] = {
++      { .compatible = "ralink,rt2880-spi" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, rt2880_spi_match);
++
++static struct platform_driver rt2880_spi_driver = {
++      .driver = {
++              .name = DRIVER_NAME,
++              .owner = THIS_MODULE,
++              .of_match_table = rt2880_spi_match,
++      },
++      .probe = rt2880_spi_probe,
++      .remove = rt2880_spi_remove,
++};
++
++module_platform_driver(rt2880_spi_driver);
++
++MODULE_DESCRIPTION("Ralink SPI driver");
++MODULE_AUTHOR("Sergiy <piratfm@gmail.com>");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch b/target/linux/ramips/patches-5.10/825-i2c-MIPS-adds-ralink-I2C-driver.patch
new file mode 100644 (file)
index 0000000..e3bb7f2
--- /dev/null
@@ -0,0 +1,507 @@
+From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:52:56 +0100
+Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ .../devicetree/bindings/i2c/i2c-ralink.txt         |   27 ++
+ drivers/i2c/busses/Kconfig                         |    4 +
+ drivers/i2c/busses/Makefile                        |    1 +
+ drivers/i2c/busses/i2c-ralink.c                    |  327 ++++++++++++++++++++
+ 4 files changed, 359 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
+ create mode 100644 drivers/i2c/busses/i2c-ralink.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
+@@ -0,0 +1,27 @@
++I2C for Ralink platforms
++
++Required properties :
++- compatible : Must be "link,rt3052-i2c"
++- reg: physical base address of the controller and length of memory mapped
++     region.
++- #address-cells = <1>;
++- #size-cells = <0>;
++
++Optional properties:
++- Child nodes conforming to i2c bus binding
++
++Example :
++
++palmbus@10000000 {
++      i2c@900 {
++              compatible = "link,rt3052-i2c";
++              reg = <0x900 0x100>;
++              #address-cells = <1>;
++              #size-cells = <0>;
++
++              hwmon@4b {
++                      compatible = "national,lm92";
++                      reg = <0x4b>;
++              };
++      };
++};
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -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.
++config I2C_RALINK
++      tristate "Ralink I2C Controller"
++      depends on RALINK && !SOC_MT7621
++      select OF_I2C
++
+ config HAVE_S3C2410_I2C
+       bool
+       help
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -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
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-ralink.c
+@@ -0,0 +1,435 @@
++/*
++ * drivers/i2c/busses/i2c-ralink.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_CONFIG_REG                0x00
++#define REG_CLKDIV_REG                0x04
++#define REG_DEVADDR_REG               0x08
++#define REG_ADDR_REG          0x0C
++#define REG_DATAOUT_REG               0x10
++#define REG_DATAIN_REG                0x14
++#define REG_STATUS_REG                0x18
++#define REG_STARTXFR_REG      0x1C
++#define REG_BYTECNT_REG               0x20
++
++/* REG_CONFIG_REG */
++#define I2C_ADDRLEN_OFFSET    5
++#define I2C_DEVADLEN_OFFSET   2
++#define I2C_ADDRLEN_MASK      0x3
++#define I2C_ADDR_DIS          BIT(1)
++#define I2C_DEVADDR_DIS               BIT(0)
++#define I2C_ADDRLEN_8         (7 << I2C_ADDRLEN_OFFSET)
++#define I2C_DEVADLEN_7                (6 << I2C_DEVADLEN_OFFSET)
++#define I2C_CONF_DEFAULT      (I2C_ADDRLEN_8 | I2C_DEVADLEN_7)
++
++/* REG_CLKDIV_REG */
++#define I2C_CLKDIV_MASK               0xffff
++
++/* REG_DEVADDR_REG */
++#define I2C_DEVADDR_MASK      0x7f
++
++/* REG_ADDR_REG */
++#define I2C_ADDR_MASK         0xff
++
++/* REG_STATUS_REG */
++#define I2C_STARTERR          BIT(4)
++#define I2C_ACKERR            BIT(3)
++#define I2C_DATARDY           BIT(2)
++#define I2C_SDOEMPTY          BIT(1)
++#define I2C_BUSY              BIT(0)
++
++/* REG_STARTXFR_REG */
++#define NOSTOP_CMD            BIT(2)
++#define NODATA_CMD            BIT(1)
++#define READ_CMD              BIT(0)
++
++/* REG_BYTECNT_REG */
++#define BYTECNT_MAX           64
++#define SET_BYTECNT(x)                (x - 1)
++
++/* timeout waiting for I2C devices to respond (clock streching) */
++#define TIMEOUT_MS              1000
++#define DELAY_INTERVAL_US       100
++
++struct rt_i2c {
++      void __iomem *base;
++      struct clk *clk;
++      struct device *dev;
++      struct i2c_adapter adap;
++      u32 cur_clk;
++      u32 clk_div;
++      u32 flags;
++};
++
++static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg)
++{
++      iowrite32(val, i2c->base + reg);
++}
++
++static u32 rt_i2c_r32(struct rt_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 rt_i2c_wait_idle(struct rt_i2c *i2c)
++{
++      int ret;
++
++      ret = poll_down_timeout(i2c->base + REG_STATUS_REG, 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);
++
++              /* check error status */
++              if (status & I2C_STARTERR)
++                      return -EAGAIN;
++              else if (status & I2C_ACKERR)
++                      return -ENXIO;
++              else if (status & mask)
++                      return 0;
++
++              usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
++      } while (time_before(jiffies, timeout));
++
++      return -ETIMEDOUT;
++}
++
++static int rt_i2c_wait_rx_done(struct rt_i2c *i2c)
++{
++      int ret;
++
++      ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY);
++      if (ret < 0)
++              dev_dbg(i2c->dev, "rx err(%d)\n", ret);
++
++      return ret;
++}
++
++static int rt_i2c_wait_tx_done(struct rt_i2c *i2c)
++{
++      int ret;
++
++      ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY);
++      if (ret < 0)
++              dev_dbg(i2c->dev, "tx err(%d)\n", ret);
++
++      return ret;
++}
++
++static void rt_i2c_reset(struct rt_i2c *i2c)
++{
++      device_reset(i2c->adap.dev.parent);
++      barrier();
++      rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG);
++}
++
++static void rt_i2c_dump_reg(struct rt_i2c *i2c)
++{
++      dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \
++                      "addr %08x, dataout %08x, datain %08x, " \
++                      "status %08x, startxfr %08x, bytecnt %08x\n",
++                      rt_i2c_r32(i2c, REG_CONFIG_REG),
++                      rt_i2c_r32(i2c, REG_CLKDIV_REG),
++                      rt_i2c_r32(i2c, REG_DEVADDR_REG),
++                      rt_i2c_r32(i2c, REG_ADDR_REG),
++                      rt_i2c_r32(i2c, REG_DATAOUT_REG),
++                      rt_i2c_r32(i2c, REG_DATAIN_REG),
++                      rt_i2c_r32(i2c, REG_STATUS_REG),
++                      rt_i2c_r32(i2c, REG_STARTXFR_REG),
++                      rt_i2c_r32(i2c, REG_BYTECNT_REG));
++}
++
++static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
++              int num)
++{
++      struct rt_i2c *i2c;
++      struct i2c_msg *pmsg;
++      unsigned char addr;
++      int i, j, ret;
++      u32 cmd;
++
++      i2c = i2c_get_adapdata(adap);
++
++      for (i = 0; i < num; i++) {
++              pmsg = &msgs[i];
++              if (i == (num - 1))
++                      cmd = 0;
++              else
++                      cmd = NOSTOP_CMD;
++
++              dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n",
++                              pmsg->addr, pmsg->len, pmsg->flags,
++                              (cmd == 0)? 1 : 0);
++
++              /* wait hardware idle */
++              if ((ret = rt_i2c_wait_idle(i2c)))
++                      goto err_timeout;
++
++              if (pmsg->flags & I2C_M_TEN) {
++                      rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG);
++                      /* 10 bits address */
++                      addr = 0x78 | ((pmsg->addr >> 8) & 0x03);
++                      rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK,
++                                      REG_DEVADDR_REG);
++                      rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK,
++                                      REG_ADDR_REG);
++              } else {
++                      rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS,
++                                      REG_CONFIG_REG);
++                      /* 7 bits address */
++                      rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
++                                      REG_DEVADDR_REG);
++              }
++
++              /* buffer length */
++              if (pmsg->len == 0)
++                      cmd |= NODATA_CMD;
++              else
++                      rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
++                                      REG_BYTECNT_REG);
++
++              j = 0;
++              if (pmsg->flags & I2C_M_RD) {
++                      cmd |= READ_CMD;
++                      /* start transfer */
++                      barrier();
++                      rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
++                      do {
++                              /* wait */
++                              if ((ret = rt_i2c_wait_rx_done(i2c)))
++                                      goto err_timeout;
++                              /* read data */
++                              if (pmsg->len)
++                                      pmsg->buf[j] = rt_i2c_r32(i2c,
++                                                      REG_DATAIN_REG);
++                              j++;
++                      } while (j < pmsg->len);
++              } else {
++                      do {
++                              /* write data */
++                              if (pmsg->len)
++                                      rt_i2c_w32(i2c, pmsg->buf[j],
++                                                      REG_DATAOUT_REG);
++                              /* start transfer */
++                              if (j == 0) {
++                                      barrier();
++                                      rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
++                              }
++                              /* wait */
++                              if ((ret = rt_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:
++      rt_i2c_dump_reg(i2c);
++      rt_i2c_reset(i2c);
++      return ret;
++}
++
++static u32 rt_i2c_func(struct i2c_adapter *a)
++{
++      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static const struct i2c_algorithm rt_i2c_algo = {
++      .master_xfer    = rt_i2c_master_xfer,
++      .functionality  = rt_i2c_func,
++};
++
++static const struct of_device_id i2c_rt_dt_ids[] = {
++      { .compatible = "ralink,rt2880-i2c" },
++      { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
++
++static struct i2c_adapter_quirks rt_i2c_quirks = {
++        .max_write_len = BYTECNT_MAX,
++        .max_read_len = BYTECNT_MAX,
++};
++
++static int rt_i2c_init(struct rt_i2c *i2c)
++{
++      u32 reg;
++
++      /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */
++      i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) /
++              (2 * i2c->cur_clk);
++      if (i2c->clk_div < 8)
++              i2c->clk_div = 8;
++      if (i2c->clk_div > I2C_CLKDIV_MASK)
++              i2c->clk_div = I2C_CLKDIV_MASK;
++
++      /* check support combinde/repeated start message */
++      rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG);
++      reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD;
++
++      rt_i2c_reset(i2c);
++
++      return reg;
++}
++
++static int rt_i2c_probe(struct platform_device *pdev)
++{
++      struct resource *res;
++      struct rt_i2c *i2c;
++      struct i2c_adapter *adap;
++      const struct of_device_id *match;
++      int ret, restart;
++
++      match = of_match_device(i2c_rt_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 rt_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 = &rt_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 = &rt_i2c_quirks;
++
++      platform_set_drvdata(pdev, i2c);
++
++      restart = rt_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 %ssupport\n",
++                      i2c->cur_clk/1000, restart ? "" : "not ");
++
++      return ret;
++}
++
++static int rt_i2c_remove(struct platform_device *pdev)
++{
++      struct rt_i2c *i2c = platform_get_drvdata(pdev);
++
++      i2c_del_adapter(&i2c->adap);
++      clk_disable_unprepare(i2c->clk);
++
++      return 0;
++}
++
++static struct platform_driver rt_i2c_driver = {
++      .probe          = rt_i2c_probe,
++      .remove         = rt_i2c_remove,
++      .driver         = {
++              .owner  = THIS_MODULE,
++              .name   = "i2c-ralink",
++              .of_match_table = i2c_rt_dt_ids,
++      },
++};
++
++static int __init i2c_rt_init (void)
++{
++      return platform_driver_register(&rt_i2c_driver);
++}
++subsys_initcall(i2c_rt_init);
++
++static void __exit i2c_rt_exit (void)
++{
++      platform_driver_unregister(&rt_i2c_driver);
++}
++module_exit(i2c_rt_exit);
++
++MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
++MODULE_DESCRIPTION("Ralink I2c host driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:Ralink-I2C");
diff --git a/target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch b/target/linux/ramips/patches-5.10/830-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch
new file mode 100644 (file)
index 0000000..f3912a1
--- /dev/null
@@ -0,0 +1,43 @@
+From 23147af14531cbdada194b94120ef8774f46292d Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 13 Nov 2014 19:08:40 +0100
+Subject: [PATCH 46/53] mmc: MIPS: ralink: add sdhci for mt7620a SoC
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/mmc/host/Kconfig             |    2 +
+ drivers/mmc/host/Makefile            |    1 +
+ drivers/mmc/host/mtk-mmc/Kconfig     |   16 +
+ drivers/mmc/host/mtk-mmc/Makefile    |   42 +
+ drivers/mmc/host/mtk-mmc/board.h     |  137 ++
+ drivers/mmc/host/mtk-mmc/dbg.c       |  347 ++++
+ drivers/mmc/host/mtk-mmc/dbg.h       |  156 ++
+ drivers/mmc/host/mtk-mmc/mt6575_sd.h | 1001 +++++++++++
+ drivers/mmc/host/mtk-mmc/sd.c        | 3060 ++++++++++++++++++++++++++++++++++
+ 9 files changed, 4762 insertions(+)
+ create mode 100644 drivers/mmc/host/mtk-mmc/Kconfig
+ create mode 100644 drivers/mmc/host/mtk-mmc/Makefile
+ create mode 100644 drivers/mmc/host/mtk-mmc/board.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/dbg.c
+ create mode 100644 drivers/mmc/host/mtk-mmc/dbg.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/mt6575_sd.h
+ create mode 100644 drivers/mmc/host/mtk-mmc/sd.c
+
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -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"
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -3,6 +3,7 @@
+ # Makefile for MMC/SD host controller drivers
+ #
++obj-$(CONFIG_MTK_MMC)                 += mtk-mmc/
+ obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
+ armmmci-y := mmci.o
+ armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
diff --git a/target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch b/target/linux/ramips/patches-5.10/835-asoc-add-mt7620-support.patch
new file mode 100644 (file)
index 0000000..d0d4141
--- /dev/null
@@ -0,0 +1,1046 @@
+From 7f29222b1731e8182ba94a331531dec18865a1e4 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:31:47 +0100
+Subject: [PATCH 48/53] asoc: add mt7620 support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/of.c            |    2 +
+ sound/soc/Kconfig                |    1 +
+ sound/soc/Makefile               |    1 +
+ sound/soc/ralink/Kconfig         |   15 ++
+ sound/soc/ralink/Makefile        |   11 +
+ sound/soc/ralink/mt7620-i2s.c    |  436 ++++++++++++++++++++++++++++++++++++++
+ sound/soc/ralink/mt7620-wm8960.c |  233 ++++++++++++++++++++
+ 7 files changed, 699 insertions(+)
+ create mode 100644 sound/soc/ralink/Kconfig
+ create mode 100644 sound/soc/ralink/Makefile
+ create mode 100644 sound/soc/ralink/mt7620-i2s.c
+ create mode 100644 sound/soc/ralink/mt7620-wm8960.c
+
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -13,6 +13,7 @@
+ #include <linux/of_fdt.h>
+ #include <linux/kernel.h>
+ #include <linux/memblock.h>
++#include <linux/module.h>
+ #include <linux/of_platform.h>
+ #include <linux/of_address.h>
+@@ -24,6 +25,7 @@
+ #include "common.h"
+ __iomem void *rt_sysc_membase;
++EXPORT_SYMBOL(rt_sysc_membase);
+ __iomem void *rt_memc_membase;
+ __iomem void *plat_of_remap_node(const char *node)
+--- a/sound/soc/Kconfig
++++ b/sound/soc/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"
++source "sound/soc/ralink/Kconfig"
+ source "sound/soc/samsung/Kconfig"
+ source "sound/soc/sh/Kconfig"
+ source "sound/soc/sirf/Kconfig"
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_SND_SOC)        += kirkwood/
+ obj-$(CONFIG_SND_SOC) += pxa/
+ obj-$(CONFIG_SND_SOC) += qcom/
+ obj-$(CONFIG_SND_SOC) += rockchip/
++obj-$(CONFIG_SND_SOC) += ralink/
+ obj-$(CONFIG_SND_SOC) += samsung/
+ obj-$(CONFIG_SND_SOC) += sh/
+ obj-$(CONFIG_SND_SOC) += sirf/
+--- /dev/null
++++ b/sound/soc/ralink/Kconfig
+@@ -0,0 +1,8 @@
++config SND_RALINK_SOC_I2S
++      depends on RALINK && SND_SOC && !SOC_RT288X
++      select SND_SOC_GENERIC_DMAENGINE_PCM
++      select REGMAP_MMIO
++      tristate "SoC Audio (I2S protocol) for Ralink SoC"
++      help
++        Say Y if you want to use I2S protocol and I2S codec on Ralink/MediaTek
++        based boards.
+--- /dev/null
++++ b/sound/soc/ralink/Makefile
+@@ -0,0 +1,6 @@
++#
++# Ralink/MediaTek Platform Support
++#
++snd-soc-ralink-i2s-objs := ralink-i2s.o
++
++obj-$(CONFIG_SND_RALINK_SOC_I2S) += snd-soc-ralink-i2s.o
+--- /dev/null
++++ b/sound/soc/ralink/ralink-i2s.c
+@@ -0,0 +1,965 @@
++/*
++ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
++ *  Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
++ *
++ *  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.
++ *
++ *  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.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/regmap.h>
++#include <linux/reset.h>
++#include <linux/debugfs.h>
++#include <linux/of_device.h>
++#include <sound/pcm_params.h>
++#include <sound/dmaengine_pcm.h>
++
++#include <asm/mach-ralink/ralink_regs.h>
++
++#define DRV_NAME "ralink-i2s"
++
++#define I2S_REG_CFG0          0x00
++#define I2S_REG_INT_STATUS    0x04
++#define I2S_REG_INT_EN                0x08
++#define I2S_REG_FF_STATUS     0x0c
++#define I2S_REG_WREG          0x10
++#define I2S_REG_RREG          0x14
++#define I2S_REG_CFG1          0x18
++#define I2S_REG_DIVCMP                0x20
++#define I2S_REG_DIVINT                0x24
++
++/* I2S_REG_CFG0 */
++#define I2S_REG_CFG0_EN               BIT(31)
++#define I2S_REG_CFG0_DMA_EN   BIT(30)
++#define I2S_REG_CFG0_BYTE_SWAP        BIT(28)
++#define I2S_REG_CFG0_TX_EN    BIT(24)
++#define I2S_REG_CFG0_RX_EN    BIT(20)
++#define I2S_REG_CFG0_SLAVE    BIT(16)
++#define I2S_REG_CFG0_RX_THRES 12
++#define I2S_REG_CFG0_TX_THRES 4
++#define I2S_REG_CFG0_THRES_MASK       (0xf << I2S_REG_CFG0_RX_THRES) | \
++      (4 << I2S_REG_CFG0_TX_THRES)
++#define I2S_REG_CFG0_DFT_THRES        (4 << I2S_REG_CFG0_RX_THRES) | \
++      (4 << I2S_REG_CFG0_TX_THRES)
++/* RT305x */
++#define I2S_REG_CFG0_CLK_DIS  BIT(8)
++#define I2S_REG_CFG0_TXCH_SWAP        BIT(3)
++#define I2S_REG_CFG0_TXCH1_OFF        BIT(2)
++#define I2S_REG_CFG0_TXCH0_OFF        BIT(1)
++#define I2S_REG_CFG0_SLAVE_EN BIT(0)
++/* RT3883 */
++#define I2S_REG_CFG0_RXCH_SWAP        BIT(11)
++#define I2S_REG_CFG0_RXCH1_OFF        BIT(10)
++#define I2S_REG_CFG0_RXCH0_OFF        BIT(9)
++#define I2S_REG_CFG0_WS_INV   BIT(0)
++/* MT7628 */
++#define I2S_REG_CFG0_FMT_LE   BIT(29)
++#define I2S_REG_CFG0_SYS_BE   BIT(28)
++#define I2S_REG_CFG0_NORM_24  BIT(18)
++#define I2S_REG_CFG0_DATA_24  BIT(17)
++
++/* I2S_REG_INT_STATUS */
++#define I2S_REG_INT_RX_FAULT  BIT(7)
++#define I2S_REG_INT_RX_OVRUN  BIT(6)
++#define I2S_REG_INT_RX_UNRUN  BIT(5)
++#define I2S_REG_INT_RX_THRES  BIT(4)
++#define I2S_REG_INT_TX_FAULT  BIT(3)
++#define I2S_REG_INT_TX_OVRUN  BIT(2)
++#define I2S_REG_INT_TX_UNRUN  BIT(1)
++#define I2S_REG_INT_TX_THRES  BIT(0)
++#define I2S_REG_INT_TX_MASK   0xf
++#define I2S_REG_INT_RX_MASK   0xf0
++
++/* I2S_REG_INT_STATUS */
++#define I2S_RX_AVCNT(x)               ((x >> 4) & 0xf)
++#define I2S_TX_AVCNT(x)               (x & 0xf)
++/* MT7628 */
++#define MT7628_I2S_RX_AVCNT(x)        ((x >> 8) & 0x1f)
++#define MT7628_I2S_TX_AVCNT(x)        (x & 0x1f)
++
++/* I2S_REG_CFG1 */
++#define I2S_REG_CFG1_LBK      BIT(31)
++#define I2S_REG_CFG1_EXTLBK   BIT(30)
++/* RT3883 */
++#define I2S_REG_CFG1_LEFT_J   BIT(0)
++#define I2S_REG_CFG1_RIGHT_J  BIT(1)
++#define I2S_REG_CFG1_FMT_MASK 0x3
++
++/* I2S_REG_DIVCMP */
++#define I2S_REG_DIVCMP_CLKEN  BIT(31)
++#define I2S_REG_DIVCMP_DIVCOMP_MASK   0x1ff
++
++/* I2S_REG_DIVINT */
++#define I2S_REG_DIVINT_MASK   0x3ff
++
++/* BCLK dividers */
++#define RALINK_I2S_DIVCMP     0
++#define RALINK_I2S_DIVINT     1
++
++/* FIFO */
++#define RALINK_I2S_FIFO_SIZE  32
++
++/* feature flags */
++#define RALINK_FLAGS_TXONLY   BIT(0)
++#define RALINK_FLAGS_LEFT_J   BIT(1)
++#define RALINK_FLAGS_RIGHT_J  BIT(2)
++#define RALINK_FLAGS_ENDIAN   BIT(3)
++#define RALINK_FLAGS_24BIT    BIT(4)
++
++#define RALINK_I2S_INT_EN     0
++
++struct ralink_i2s_stats {
++      u32 dmafault;
++      u32 overrun;
++      u32 underrun;
++      u32 belowthres;
++};
++
++struct ralink_i2s {
++      struct device *dev;
++      void __iomem *regs;
++      struct clk *clk;
++      struct regmap *regmap;
++      u32 flags;
++      unsigned int fmt;
++      u16 txdma_req;
++      u16 rxdma_req;
++
++      struct snd_dmaengine_dai_dma_data playback_dma_data;
++      struct snd_dmaengine_dai_dma_data capture_dma_data;
++
++      struct dentry *dbg_dir;
++        struct dentry *dbg_stats;
++      struct ralink_i2s_stats txstats;
++      struct ralink_i2s_stats rxstats;
++};
++
++static void ralink_i2s_dump_regs(struct ralink_i2s *i2s)
++{
++      u32 buf[10];
++      int ret;
++
++      ret = regmap_bulk_read(i2s->regmap, I2S_REG_CFG0,
++                      buf, ARRAY_SIZE(buf));
++
++      dev_dbg(i2s->dev, "CFG0: %08x, INTSTAT: %08x, INTEN: %08x, " \
++                      "FFSTAT: %08x, WREG: %08x, RREG: %08x, " \
++                      "CFG1: %08x, DIVCMP: %08x, DIVINT: %08x\n",
++                      buf[0], buf[1], buf[2], buf[3], buf[4],
++                      buf[5], buf[6], buf[8], buf[9]);
++}
++
++static int ralink_i2s_set_sysclk(struct snd_soc_dai *dai,
++                              int clk_id, unsigned int freq, int dir)
++{
++      return 0;
++}
++
++static int ralink_i2s_set_sys_bclk(struct snd_soc_dai *dai, int width, int rate)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++      unsigned long clk = clk_get_rate(i2s->clk);
++      int div;
++      uint32_t data;
++
++      /* disable clock at slave mode */
++      if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
++                      SND_SOC_DAIFMT_CBM_CFM) {
++              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                              I2S_REG_CFG0_CLK_DIS,
++                              I2S_REG_CFG0_CLK_DIS);
++              return 0;
++      }
++
++      /* FREQOUT = FREQIN / (I2S_CLK_DIV + 1) */
++      div = (clk / rate ) - 1;
++
++      data = rt_sysc_r32(0x30);
++      data &= (0xff << 8);
++      data |= (0x1 << 15) | (div << 8);
++      rt_sysc_w32(data, 0x30);
++
++      /* enable clock */
++      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_CLK_DIS, 0);
++
++      dev_dbg(i2s->dev, "clk: %lu, rate: %u, div: %d\n",
++                      clk, rate, div);
++
++      return 0;
++}
++
++static int ralink_i2s_set_bclk(struct snd_soc_dai *dai, int width, int rate)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++      unsigned long clk = clk_get_rate(i2s->clk);
++      int divint, divcomp;
++
++      /* disable clock at slave mode */
++      if ((i2s->fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
++                      SND_SOC_DAIFMT_CBM_CFM) {
++              regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
++                              I2S_REG_DIVCMP_CLKEN, 0);
++              return 0;
++      }
++
++      /* FREQOUT = FREQIN * (1/2) * (1/(DIVINT + DIVCOMP/512)) */
++      clk = clk / (2 * 2 * width);
++      divint = clk / rate;
++      divcomp = ((clk % rate) * 512) / rate;
++
++      if ((divint > I2S_REG_DIVINT_MASK) ||
++                      (divcomp > I2S_REG_DIVCMP_DIVCOMP_MASK))
++              return -EINVAL;
++
++      regmap_update_bits(i2s->regmap, I2S_REG_DIVINT,
++                      I2S_REG_DIVINT_MASK, divint);
++      regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP,
++                      I2S_REG_DIVCMP_DIVCOMP_MASK, divcomp);
++
++      /* enable clock */
++      regmap_update_bits(i2s->regmap, I2S_REG_DIVCMP, I2S_REG_DIVCMP_CLKEN,
++                      I2S_REG_DIVCMP_CLKEN);
++
++      dev_dbg(i2s->dev, "clk: %lu, rate: %u, int: %d, comp: %d\n",
++                      clk_get_rate(i2s->clk), rate, divint, divcomp);
++
++      return 0;
++}
++
++static int ralink_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++      unsigned int cfg0 = 0, cfg1 = 0;
++
++      /* set master/slave audio interface */
++      switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++      case SND_SOC_DAIFMT_CBM_CFM:
++              if (i2s->flags & RALINK_FLAGS_TXONLY)
++                      cfg0 |= I2S_REG_CFG0_SLAVE_EN;
++              else
++                      cfg0 |= I2S_REG_CFG0_SLAVE;
++              break;
++      case SND_SOC_DAIFMT_CBS_CFS:
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      /* interface format */
++      switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++      case SND_SOC_DAIFMT_I2S:
++              break;
++      case SND_SOC_DAIFMT_RIGHT_J:
++              if (i2s->flags & RALINK_FLAGS_RIGHT_J) {
++                      cfg1 |= I2S_REG_CFG1_RIGHT_J;
++                      break;
++              }
++              return -EINVAL;
++      case SND_SOC_DAIFMT_LEFT_J:
++              if (i2s->flags & RALINK_FLAGS_LEFT_J) {
++                      cfg1 |= I2S_REG_CFG1_LEFT_J;
++                      break;
++              }
++              return -EINVAL;
++      default:
++              return -EINVAL;
++      }
++
++      /* clock inversion */
++      switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++      case SND_SOC_DAIFMT_NB_NF:
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (i2s->flags & RALINK_FLAGS_TXONLY) {
++              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                              I2S_REG_CFG0_SLAVE_EN, cfg0);
++      } else {
++              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                              I2S_REG_CFG0_SLAVE, cfg0);
++      }
++      regmap_update_bits(i2s->regmap, I2S_REG_CFG1,
++                      I2S_REG_CFG1_FMT_MASK, cfg1);
++      i2s->fmt = fmt;
++
++      return 0;
++}
++
++static int ralink_i2s_startup(struct snd_pcm_substream *substream,
++              struct snd_soc_dai *dai)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++      if (dai->active)
++              return 0;
++
++      /* setup status interrupt */
++#if (RALINK_I2S_INT_EN)
++      regmap_write(i2s->regmap, I2S_REG_INT_EN, 0xff);
++#else
++      regmap_write(i2s->regmap, I2S_REG_INT_EN, 0x0);
++#endif
++
++      /* enable */
++      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                      I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
++                      I2S_REG_CFG0_THRES_MASK,
++                      I2S_REG_CFG0_EN | I2S_REG_CFG0_DMA_EN |
++                      I2S_REG_CFG0_DFT_THRES);
++
++      return 0;
++}
++
++static void ralink_i2s_shutdown(struct snd_pcm_substream *substream,
++              struct snd_soc_dai *dai)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++      /* If both streams are stopped, disable module and clock */
++      if (dai->active)
++              return;
++
++      /*
++       * datasheet mention when disable all control regs are cleared
++       * to initial values. need reinit at startup.
++       */
++      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, I2S_REG_CFG0_EN, 0);
++}
++
++static int ralink_i2s_hw_params(struct snd_pcm_substream *substream,
++              struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++      int width;
++      int ret;
++
++      width = params_width(params);
++      switch (width) {
++      case 16:
++              if (i2s->flags & RALINK_FLAGS_24BIT)
++                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                                      I2S_REG_CFG0_DATA_24, 0);
++              break;
++      case 24:
++              if (i2s->flags & RALINK_FLAGS_24BIT) {
++                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                                      I2S_REG_CFG0_DATA_24,
++                                      I2S_REG_CFG0_DATA_24);
++                      break;
++              }
++              return -EINVAL;
++      default:
++              return -EINVAL;
++      }
++
++      switch (params_channels(params)) {
++      case 2:
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      if (i2s->flags & RALINK_FLAGS_ENDIAN) {
++              /* system endian */
++#ifdef SNDRV_LITTLE_ENDIAN
++              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                              I2S_REG_CFG0_SYS_BE, 0);
++#else
++              regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                              I2S_REG_CFG0_SYS_BE,
++                              I2S_REG_CFG0_SYS_BE);
++#endif
++
++              /* data endian */
++              switch (params_format(params)) {
++              case SNDRV_PCM_FORMAT_S16_LE:
++              case SNDRV_PCM_FORMAT_S24_LE:
++                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                                      I2S_REG_CFG0_FMT_LE,
++                                      I2S_REG_CFG0_FMT_LE);
++                      break;
++              case SNDRV_PCM_FORMAT_S16_BE:
++              case SNDRV_PCM_FORMAT_S24_BE:
++                      regmap_update_bits(i2s->regmap, I2S_REG_CFG0,
++                                      I2S_REG_CFG0_FMT_LE, 0);
++                      break;
++              default:
++                      return -EINVAL;
++              }
++      }
++
++      /* setup bclk rate */
++      if (i2s->flags & RALINK_FLAGS_TXONLY)
++              ret = ralink_i2s_set_sys_bclk(dai, width, params_rate(params));
++      else
++              ret = ralink_i2s_set_bclk(dai, width, params_rate(params));
++
++      return ret;
++}
++
++static int ralink_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
++              struct snd_soc_dai *dai)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++      unsigned int mask, val;
++
++      if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++              mask = I2S_REG_CFG0_TX_EN;
++      else
++              mask = I2S_REG_CFG0_RX_EN;
++
++      switch (cmd) {
++      case SNDRV_PCM_TRIGGER_START:
++      case SNDRV_PCM_TRIGGER_RESUME:
++      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++              val = mask;
++              break;
++      case SNDRV_PCM_TRIGGER_STOP:
++      case SNDRV_PCM_TRIGGER_SUSPEND:
++      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++              val = 0;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      regmap_update_bits(i2s->regmap, I2S_REG_CFG0, mask, val);
++
++      return 0;
++}
++
++static void ralink_i2s_init_dma_data(struct ralink_i2s *i2s,
++              struct resource *res)
++{
++      struct snd_dmaengine_dai_dma_data *dma_data;
++
++      /* Playback */
++      dma_data = &i2s->playback_dma_data;
++      dma_data->addr = res->start + I2S_REG_WREG;
++      dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++      dma_data->maxburst = 1;
++      dma_data->slave_id = i2s->txdma_req;
++
++      if (i2s->flags & RALINK_FLAGS_TXONLY)
++              return;
++
++      /* Capture */
++      dma_data = &i2s->capture_dma_data;
++      dma_data->addr = res->start + I2S_REG_RREG;
++      dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++      dma_data->maxburst = 1;
++      dma_data->slave_id = i2s->rxdma_req;
++}
++
++static int ralink_i2s_dai_probe(struct snd_soc_dai *dai)
++{
++      struct ralink_i2s *i2s = snd_soc_dai_get_drvdata(dai);
++
++      snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
++                      &i2s->capture_dma_data);
++
++      return 0;
++}
++
++static int ralink_i2s_dai_remove(struct snd_soc_dai *dai)
++{
++      return 0;
++}
++
++static const struct snd_soc_dai_ops ralink_i2s_dai_ops = {
++      .set_sysclk = ralink_i2s_set_sysclk,
++      .set_fmt = ralink_i2s_set_fmt,
++      .startup = ralink_i2s_startup,
++      .shutdown = ralink_i2s_shutdown,
++      .hw_params = ralink_i2s_hw_params,
++      .trigger = ralink_i2s_trigger,
++};
++
++static struct snd_soc_dai_driver ralink_i2s_dai = {
++      .name = DRV_NAME,
++      .probe = ralink_i2s_dai_probe,
++      .remove = ralink_i2s_dai_remove,
++      .ops = &ralink_i2s_dai_ops,
++      .capture = {
++              .stream_name = "I2S Capture",
++              .channels_min = 2,
++              .channels_max = 2,
++              .rate_min = 5512,
++              .rate_max = 192000,
++              .rates = SNDRV_PCM_RATE_CONTINUOUS,
++              .formats = SNDRV_PCM_FMTBIT_S16_LE,
++      },
++      .playback = {
++              .stream_name = "I2S Playback",
++              .channels_min = 2,
++              .channels_max = 2,
++              .rate_min = 5512,
++              .rate_max = 192000,
++              .rates = SNDRV_PCM_RATE_CONTINUOUS,
++              .formats = SNDRV_PCM_FMTBIT_S16_LE,
++      },
++      .symmetric_rates = 1,
++};
++
++static struct snd_pcm_hardware ralink_pcm_hardware = {
++      .info = SNDRV_PCM_INFO_MMAP |
++              SNDRV_PCM_INFO_MMAP_VALID |
++              SNDRV_PCM_INFO_INTERLEAVED |
++              SNDRV_PCM_INFO_BLOCK_TRANSFER,
++      .formats = SNDRV_PCM_FMTBIT_S16_LE,
++      .channels_min           = 2,
++      .channels_max           = 2,
++      .period_bytes_min       = PAGE_SIZE,
++      .period_bytes_max       = PAGE_SIZE * 2,
++      .periods_min            = 2,
++      .periods_max            = 128,
++      .buffer_bytes_max       = 128 * 1024,
++      .fifo_size              = RALINK_I2S_FIFO_SIZE,
++};
++
++static const struct snd_dmaengine_pcm_config ralink_dmaengine_pcm_config = {
++      .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
++      .pcm_hardware = &ralink_pcm_hardware,
++      .prealloc_buffer_size = 256 * PAGE_SIZE,
++};
++
++static const struct snd_soc_component_driver ralink_i2s_component = {
++      .name = DRV_NAME,
++};
++
++static bool ralink_i2s_readable_reg(struct device *dev, unsigned int reg)
++{
++      return true;
++}
++
++static bool ralink_i2s_volatile_reg(struct device *dev, unsigned int reg)
++{
++      switch (reg) {
++      case I2S_REG_INT_STATUS:
++      case I2S_REG_FF_STATUS:
++              return true;
++      }
++      return false;
++}
++
++static bool ralink_i2s_writeable_reg(struct device *dev, unsigned int reg)
++{
++      switch (reg) {
++      case I2S_REG_FF_STATUS:
++      case I2S_REG_RREG:
++              return false;
++      }
++      return true;
++}
++
++static const struct regmap_config ralink_i2s_regmap_config = {
++      .reg_bits = 32,
++      .reg_stride = 4,
++      .val_bits = 32,
++      .writeable_reg = ralink_i2s_writeable_reg,
++      .readable_reg = ralink_i2s_readable_reg,
++      .volatile_reg = ralink_i2s_volatile_reg,
++      .max_register = I2S_REG_DIVINT,
++};
++
++#if (RALINK_I2S_INT_EN)
++static irqreturn_t ralink_i2s_irq(int irq, void *devid)
++{
++      struct ralink_i2s *i2s = devid;
++      u32 status;
++
++      regmap_read(i2s->regmap, I2S_REG_INT_STATUS, &status);
++      if (unlikely(!status))
++              return IRQ_NONE;
++
++      /* tx stats */
++      if (status & I2S_REG_INT_TX_MASK) {
++              if (status & I2S_REG_INT_TX_THRES)
++                      i2s->txstats.belowthres++;
++              if (status & I2S_REG_INT_TX_UNRUN)
++                      i2s->txstats.underrun++;
++              if (status & I2S_REG_INT_TX_OVRUN)
++                      i2s->txstats.overrun++;
++              if (status & I2S_REG_INT_TX_FAULT)
++                      i2s->txstats.dmafault++;
++      }
++
++      /* rx stats */
++      if (status & I2S_REG_INT_RX_MASK) {
++              if (status & I2S_REG_INT_RX_THRES)
++                      i2s->rxstats.belowthres++;
++              if (status & I2S_REG_INT_RX_UNRUN)
++                      i2s->rxstats.underrun++;
++              if (status & I2S_REG_INT_RX_OVRUN)
++                      i2s->rxstats.overrun++;
++              if (status & I2S_REG_INT_RX_FAULT)
++                      i2s->rxstats.dmafault++;
++      }
++
++      /* clean status bits */
++      regmap_write(i2s->regmap, I2S_REG_INT_STATUS, status);
++
++      return IRQ_HANDLED;
++}
++#endif
++
++#if IS_ENABLED(CONFIG_DEBUG_FS)
++static int ralink_i2s_stats_show(struct seq_file *s, void *unused)
++{
++        struct ralink_i2s *i2s = s->private;
++
++      seq_printf(s, "tx stats\n");
++      seq_printf(s, "\tbelow threshold\t%u\n", i2s->txstats.belowthres);
++      seq_printf(s, "\tunder run\t%u\n", i2s->txstats.underrun);
++      seq_printf(s, "\tover run\t%u\n", i2s->txstats.overrun);
++      seq_printf(s, "\tdma fault\t%u\n", i2s->txstats.dmafault);
++
++      seq_printf(s, "rx stats\n");
++      seq_printf(s, "\tbelow threshold\t%u\n", i2s->rxstats.belowthres);
++      seq_printf(s, "\tunder run\t%u\n", i2s->rxstats.underrun);
++      seq_printf(s, "\tover run\t%u\n", i2s->rxstats.overrun);
++      seq_printf(s, "\tdma fault\t%u\n", i2s->rxstats.dmafault);
++
++      ralink_i2s_dump_regs(i2s);
++
++      return 0;
++}
++
++static int ralink_i2s_stats_open(struct inode *inode, struct file *file)
++{
++        return single_open(file, ralink_i2s_stats_show, inode->i_private);
++}
++
++static const struct file_operations ralink_i2s_stats_ops = {
++        .open = ralink_i2s_stats_open,
++        .read = seq_read,
++        .llseek = seq_lseek,
++        .release = single_release,
++};
++
++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
++{
++        i2s->dbg_dir = debugfs_create_dir(dev_name(i2s->dev), NULL);
++        if (!i2s->dbg_dir)
++                return -ENOMEM;
++
++        i2s->dbg_stats = debugfs_create_file("stats", S_IRUGO,
++                        i2s->dbg_dir, i2s, &ralink_i2s_stats_ops);
++        if (!i2s->dbg_stats) {
++                debugfs_remove(i2s->dbg_dir);
++                return -ENOMEM;
++        }
++
++        return 0;
++}
++
++static inline void ralink_i2s_debugfs_remove(struct ralink_i2s *i2s)
++{
++      debugfs_remove(i2s->dbg_stats);
++      debugfs_remove(i2s->dbg_dir);
++}
++#else
++static inline int ralink_i2s_debugfs_create(struct ralink_i2s *i2s)
++{
++      return 0;
++}
++
++static inline void ralink_i2s_debugfs_remove(struct fsl_ssi_dbg *ssi_dbg)
++{
++}
++#endif
++
++/*
++ * TODO: these refclk setup functions should use
++ * clock framework instead. hardcode it now.
++ */
++static void rt3350_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data |= (0x1 << 8);
++      rt_sysc_w32(data, 0x2c);
++}
++
++static void rt3883_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data &= ~(0x3 << 13);
++      data |= (0x1 << 13);
++      rt_sysc_w32(data, 0x2c);
++}
++
++static void rt3552_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data &= ~(0xf << 8);
++      data |= (0x3 << 8);
++      rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7620_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data &= ~(0x7 << 9);
++      data |= 0x1 << 9;
++      rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7621_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data &= ~(0x1f << 18);
++      data |= (0x19 << 18);
++      data &= ~(0x1f << 12);
++      data |= (0x1 << 12);
++      data &= ~(0x7 << 9);
++      data |= (0x5 << 9);
++      rt_sysc_w32(data, 0x2c);
++}
++
++static void mt7628_refclk_setup(void)
++{
++      uint32_t data;
++
++      /* set i2s and refclk digital pad */
++      data = rt_sysc_r32(0x3c);
++      data |= 0x1f;
++      rt_sysc_w32(data, 0x3c);
++
++      /* Adjust REFCLK0's driving strength */
++      data = rt_sysc_r32(0x1354);
++      data &= ~(0x1 << 5);
++      rt_sysc_w32(data, 0x1354);
++      data = rt_sysc_r32(0x1364);
++      data |= ~(0x1 << 5);
++      rt_sysc_w32(data, 0x1364);
++
++      /* set refclk output 12Mhz clock */
++      data = rt_sysc_r32(0x2c);
++      data &= ~(0x7 << 9);
++      data |= 0x1 << 9;
++      rt_sysc_w32(data, 0x2c);
++}
++
++struct rt_i2s_data {
++      u32 flags;
++      void (*refclk_setup)(void);
++};
++
++struct rt_i2s_data rt3050_i2s_data = { .flags = RALINK_FLAGS_TXONLY };
++struct rt_i2s_data rt3350_i2s_data = { .flags = RALINK_FLAGS_TXONLY,
++      .refclk_setup = rt3350_refclk_setup };
++struct rt_i2s_data rt3883_i2s_data = {
++      .flags = (RALINK_FLAGS_LEFT_J | RALINK_FLAGS_RIGHT_J),
++      .refclk_setup = rt3883_refclk_setup };
++struct rt_i2s_data rt3352_i2s_data = { .refclk_setup = rt3552_refclk_setup};
++struct rt_i2s_data mt7620_i2s_data = { .refclk_setup = mt7620_refclk_setup};
++struct rt_i2s_data mt7621_i2s_data = { .refclk_setup = mt7621_refclk_setup};
++struct rt_i2s_data mt7628_i2s_data = {
++      .flags = (RALINK_FLAGS_ENDIAN | RALINK_FLAGS_24BIT |
++                      RALINK_FLAGS_LEFT_J),
++      .refclk_setup = mt7628_refclk_setup};
++
++static const struct of_device_id ralink_i2s_match_table[] = {
++      { .compatible = "ralink,rt3050-i2s",
++              .data = (void *)&rt3050_i2s_data },
++      { .compatible = "ralink,rt3350-i2s",
++              .data = (void *)&rt3350_i2s_data },
++      { .compatible = "ralink,rt3883-i2s",
++              .data = (void *)&rt3883_i2s_data },
++      { .compatible = "ralink,rt3352-i2s",
++              .data = (void *)&rt3352_i2s_data },
++      { .compatible = "mediatek,mt7620-i2s",
++              .data = (void *)&mt7620_i2s_data },
++      { .compatible = "mediatek,mt7621-i2s",
++              .data = (void *)&mt7621_i2s_data },
++      { .compatible = "mediatek,mt7628-i2s",
++              .data = (void *)&mt7628_i2s_data },
++};
++MODULE_DEVICE_TABLE(of, ralink_i2s_match_table);
++
++static int ralink_i2s_probe(struct platform_device *pdev)
++{
++      const struct of_device_id *match;
++      struct device_node *np = pdev->dev.of_node;
++      struct ralink_i2s *i2s;
++      struct resource *res;
++      int irq, ret;
++      u32 dma_req;
++      struct rt_i2s_data *data;
++
++      i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
++      if (!i2s)
++              return -ENOMEM;
++
++      platform_set_drvdata(pdev, i2s);
++      i2s->dev = &pdev->dev;
++
++      match = of_match_device(ralink_i2s_match_table, &pdev->dev);
++      if (!match)
++              return -EINVAL;
++      data = (struct rt_i2s_data *)match->data;
++      i2s->flags = data->flags;
++      /* setup out 12Mhz refclk to codec as mclk */
++      if (data->refclk_setup)
++              data->refclk_setup();
++
++      if (of_property_read_u32(np, "txdma-req", &dma_req)) {
++              dev_err(&pdev->dev, "no txdma-req define\n");
++              return -EINVAL;
++      }
++      i2s->txdma_req = (u16)dma_req;
++      if (!(i2s->flags & RALINK_FLAGS_TXONLY)) {
++              if (of_property_read_u32(np, "rxdma-req", &dma_req)) {
++                      dev_err(&pdev->dev, "no rxdma-req define\n");
++                      return -EINVAL;
++              }
++              i2s->rxdma_req = (u16)dma_req;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      i2s->regs = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(i2s->regs))
++              return PTR_ERR(i2s->regs);
++
++      i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
++                      &ralink_i2s_regmap_config);
++      if (IS_ERR(i2s->regmap)) {
++              dev_err(&pdev->dev, "regmap init failed\n");
++              return PTR_ERR(i2s->regmap);
++      }
++
++        irq = platform_get_irq(pdev, 0);
++        if (irq < 0) {
++                dev_err(&pdev->dev, "failed to get irq\n");
++                return -EINVAL;
++        }
++
++#if (RALINK_I2S_INT_EN)
++      ret = devm_request_irq(&pdev->dev, irq, ralink_i2s_irq,
++                      0, dev_name(&pdev->dev), i2s);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to request irq\n");
++              return ret;
++      }
++#endif
++
++      i2s->clk = devm_clk_get(&pdev->dev, NULL);
++      if (IS_ERR(i2s->clk)) {
++              dev_err(&pdev->dev, "no clock defined\n");
++              return PTR_ERR(i2s->clk);
++      }
++
++      ret = clk_prepare_enable(i2s->clk);
++      if (ret)
++              return ret;
++
++      ralink_i2s_init_dma_data(i2s, res);
++
++      device_reset(&pdev->dev);
++
++      ret = ralink_i2s_debugfs_create(i2s);
++      if (ret) {
++              dev_err(&pdev->dev, "create debugfs failed\n");
++              goto err_clk_disable;
++      }
++
++      /* enable 24bits support */
++      if (i2s->flags & RALINK_FLAGS_24BIT) {
++              ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S24_LE;
++              ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S24_LE;
++      }
++
++      /* enable big endian support */
++      if (i2s->flags & RALINK_FLAGS_ENDIAN) {
++              ralink_i2s_dai.capture.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++              ralink_i2s_dai.playback.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++              ralink_pcm_hardware.formats |= SNDRV_PCM_FMTBIT_S16_BE;
++              if (i2s->flags & RALINK_FLAGS_24BIT) {
++                      ralink_i2s_dai.capture.formats |=
++                              SNDRV_PCM_FMTBIT_S24_BE;
++                      ralink_i2s_dai.playback.formats |=
++                              SNDRV_PCM_FMTBIT_S24_BE;
++                      ralink_pcm_hardware.formats |=
++                              SNDRV_PCM_FMTBIT_S24_BE;
++              }
++      }
++
++      /* disable capture support */
++      if (i2s->flags & RALINK_FLAGS_TXONLY)
++              memset(&ralink_i2s_dai.capture, sizeof(ralink_i2s_dai.capture),
++                              0);
++
++      ret = devm_snd_soc_register_component(&pdev->dev, &ralink_i2s_component,
++                      &ralink_i2s_dai, 1);
++      if (ret)
++              goto err_debugfs;
++
++      ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
++                      &ralink_dmaengine_pcm_config,
++                      SND_DMAENGINE_PCM_FLAG_COMPAT);
++      if (ret)
++              goto err_debugfs;
++
++      dev_info(i2s->dev, "mclk %luMHz\n", clk_get_rate(i2s->clk) / 1000000);
++
++      return 0;
++
++err_debugfs:
++      ralink_i2s_debugfs_remove(i2s);
++
++err_clk_disable:
++      clk_disable_unprepare(i2s->clk);
++
++      return ret;
++}
++
++static int ralink_i2s_remove(struct platform_device *pdev)
++{
++      struct ralink_i2s *i2s = platform_get_drvdata(pdev);
++
++      ralink_i2s_debugfs_remove(i2s);
++      clk_disable_unprepare(i2s->clk);
++
++      return 0;
++}
++
++static struct platform_driver ralink_i2s_driver = {
++      .probe = ralink_i2s_probe,
++      .remove = ralink_i2s_remove,
++      .driver = {
++              .name = DRV_NAME,
++              .of_match_table = ralink_i2s_match_table,
++      },
++};
++module_platform_driver(ralink_i2s_driver);
++
++MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
++MODULE_DESCRIPTION("Ralink/MediaTek I2S driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch b/target/linux/ramips/patches-5.10/840-serial-add-ugly-custom-baud-rate-hack.patch
new file mode 100644 (file)
index 0000000..4822226
--- /dev/null
@@ -0,0 +1,22 @@
+From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:31:08 +0100
+Subject: [PATCH 51/53] serial: add ugly custom baud rate hack
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/tty/serial/serial_core.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/tty/serial/serial_core.c
++++ b/drivers/tty/serial/serial_core.c
+@@ -416,6 +416,9 @@ uart_get_baud_rate(struct uart_port *por
+               break;
+       }
++      if (tty_termios_baud_rate(termios) == 2500000)
++              return 250000;
++
+       for (try = 0; try < 2; try++) {
+               baud = tty_termios_baud_rate(termios);
diff --git a/target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch b/target/linux/ramips/patches-5.10/845-pwm-add-mediatek-support.patch
new file mode 100644 (file)
index 0000000..d2c5724
--- /dev/null
@@ -0,0 +1,217 @@
+From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:16:50 +0100
+Subject: [PATCH 52/53] pwm: add mediatek support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/pwm/Kconfig        |    9 +++
+ drivers/pwm/Makefile       |    1 +
+ drivers/pwm/pwm-mediatek.c |  173 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 183 insertions(+)
+ create mode 100644 drivers/pwm/pwm-mediatek.c
+
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -316,6 +316,15 @@ config PWM_MEDIATEK
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-mediatek.
++config PWM_MEDIATEK_RAMIPS
++      tristate "Mediatek PWM support"
++      depends on RALINK && OF
++      help
++        Generic PWM framework driver for Mediatek ARM SoC.
++
++        To compile this driver as a module, choose M here: the module
++        will be called pwm-mxs.
++
+ config PWM_MXS
+       tristate "Freescale MXS PWM support"
+       depends on ARCH_MXS && OF
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -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
++obj-$(CONFIG_PWM_MEDIATEK_RAMIPS)     += pwm-mediatek-ramips.o
+ obj-$(CONFIG_PWM_MTK_DISP)    += pwm-mtk-disp.o
+ obj-$(CONFIG_PWM_MXS)         += pwm-mxs.o
+ obj-$(CONFIG_PWM_OMAP_DMTIMER)        += pwm-omap-dmtimer.o
+--- /dev/null
++++ b/drivers/pwm/pwm-mediatek-ramips.c
+@@ -0,0 +1,173 @@
++/*
++ * Mediatek Pulse Width Modulator driver
++ *
++ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++
++#define NUM_PWM               4
++
++/* PWM registers and bits definitions */
++#define PWMCON                        0x00
++#define PWMHDUR                       0x04
++#define PWMLDUR                       0x08
++#define PWMGDUR                       0x0c
++#define PWMWAVENUM            0x28
++#define PWMDWIDTH             0x2c
++#define PWMTHRES              0x30
++
++/**
++ * struct mtk_pwm_chip - struct representing pwm chip
++ *
++ * @mmio_base: base address of pwm chip
++ * @chip: linux pwm chip representation
++ */
++struct mtk_pwm_chip {
++      void __iomem *mmio_base;
++      struct pwm_chip chip;
++};
++
++static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
++{
++      return container_of(chip, struct mtk_pwm_chip, chip);
++}
++
++static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
++                                unsigned long offset)
++{
++      return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
++                                  unsigned int num, unsigned long offset,
++                                  unsigned long val)
++{
++      iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
++}
++
++static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++                          int duty_ns, int period_ns)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 resolution = 100 / 4;
++      u32 clkdiv = 0;
++
++      while (period_ns / resolution  > 8191) {
++              clkdiv++;
++              resolution *= 2;
++      }
++
++      if (clkdiv > 7)
++              return -1;
++
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
++      mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
++      return 0;
++}
++
++static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 val;
++
++      val = ioread32(pc->mmio_base);
++      val |= BIT(pwm->hwpwm);
++      iowrite32(val, pc->mmio_base);
++
++      return 0;
++}
++
++static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++      struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
++      u32 val;
++
++      val = ioread32(pc->mmio_base);
++      val &= ~BIT(pwm->hwpwm);
++      iowrite32(val, pc->mmio_base);
++}
++
++static const struct pwm_ops mtk_pwm_ops = {
++      .config = mtk_pwm_config,
++      .enable = mtk_pwm_enable,
++      .disable = mtk_pwm_disable,
++      .owner = THIS_MODULE,
++};
++
++static int mtk_pwm_probe(struct platform_device *pdev)
++{
++      struct mtk_pwm_chip *pc;
++      struct resource *r;
++      int ret;
++
++      pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
++      if (!pc)
++              return -ENOMEM;
++
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
++      if (IS_ERR(pc->mmio_base))
++              return PTR_ERR(pc->mmio_base);
++
++      platform_set_drvdata(pdev, pc);
++
++      pc->chip.dev = &pdev->dev;
++      pc->chip.ops = &mtk_pwm_ops;
++      pc->chip.base = -1;
++      pc->chip.npwm = NUM_PWM;
++
++      ret = pwmchip_add(&pc->chip);
++      if (ret < 0)
++              dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
++
++      return ret;
++}
++
++static int mtk_pwm_remove(struct platform_device *pdev)
++{
++      struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
++      int i;
++
++      for (i = 0; i < NUM_PWM; i++)
++              pwm_disable(&pc->chip.pwms[i]);
++
++      return pwmchip_remove(&pc->chip);
++}
++
++static const struct of_device_id mtk_pwm_of_match[] = {
++      { .compatible = "mediatek,mt7628-pwm" },
++      { }
++};
++
++MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
++
++static struct platform_driver mtk_pwm_driver = {
++      .driver = {
++              .name = "mtk-pwm",
++              .owner = THIS_MODULE,
++              .of_match_table = mtk_pwm_of_match,
++      },
++      .probe = mtk_pwm_probe,
++      .remove = mtk_pwm_remove,
++};
++
++module_platform_driver(mtk_pwm_driver);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_ALIAS("platform:mtk-pwm");
diff --git a/target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch b/target/linux/ramips/patches-5.10/850-awake-rt305x-dwc2-controller.patch
new file mode 100644 (file)
index 0000000..7110a5b
--- /dev/null
@@ -0,0 +1,15 @@
+--- a/drivers/usb/dwc2/platform.c
++++ b/drivers/usb/dwc2/platform.c
+@@ -431,6 +431,12 @@ static int dwc2_driver_probe(struct plat
+       if (retval)
+               return retval;
++      /* Enable USB port before any regs access */
++      if (readl(hsotg->regs + PCGCTL) & 0x0f) {
++              writel(0x00, hsotg->regs + PCGCTL);
++              /* TODO: mdelay(25) here? vendor driver don't use it */
++      }
++
+       hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
+       retval = dwc2_get_dr_mode(hsotg);
diff --git a/target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch b/target/linux/ramips/patches-5.10/855-linkit_bootstrap.patch
new file mode 100644 (file)
index 0000000..9142faa
--- /dev/null
@@ -0,0 +1,97 @@
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -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
+ obj-$(CONFIG_OCXL)            += ocxl/
+ obj-y                         += cardreader/
+ obj-$(CONFIG_PVPANIC)         += pvpanic.o
+--- /dev/null
++++ b/drivers/misc/linkit.c
+@@ -0,0 +1,84 @@
++/*
++ *  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) 2015 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/mtd/mtd.h>
++#include <linux/gpio.h>
++
++#define LINKIT_LATCH_GPIO     11
++
++struct linkit_hw_data {
++      char board[16];
++      char rev[16];
++};
++
++static void sanify_string(char *s)
++{
++      int i;
++
++      for (i = 0; i < 15; i++)
++              if (s[i] <= 0x20)
++                      s[i] = '\0';
++      s[15] = '\0';
++}
++
++static int linkit_probe(struct platform_device *pdev)
++{
++      struct linkit_hw_data hw;
++      struct mtd_info *mtd;
++      size_t retlen;
++      int ret;
++
++      mtd = get_mtd_device_nm("factory");
++      if (IS_ERR(mtd))
++              return PTR_ERR(mtd);
++
++      ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw);
++      put_mtd_device(mtd);
++
++      sanify_string(hw.board);
++      sanify_string(hw.rev);
++
++      dev_info(&pdev->dev, "Version  : %s\n", hw.board);
++      dev_info(&pdev->dev, "Revision : %s\n", hw.rev);
++
++      if (!strcmp(hw.board, "LINKITS7688")) {
++              dev_info(&pdev->dev, "setting up bootstrap latch\n");
++
++              if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) {
++                      dev_err(&pdev->dev, "failed to setup bootstrap gpio\n");
++                      return -1;
++              }
++              gpio_direction_output(LINKIT_LATCH_GPIO, 0);
++      }
++
++      return 0;
++}
++
++static const struct of_device_id linkit_match[] = {
++      { .compatible = "mediatek,linkit" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, linkit_match);
++
++static struct platform_driver linkit_driver = {
++      .probe = linkit_probe,
++      .driver = {
++              .name = "mtk-linkit",
++              .owner = THIS_MODULE,
++              .of_match_table = linkit_match,
++      },
++};
++
++int __init linkit_init(void)
++{
++      return platform_driver_register(&linkit_driver);
++}
++late_initcall_sync(linkit_init);
diff --git a/target/linux/ramips/patches-5.10/990-NET-no-auto-carrier-off-support.patch b/target/linux/ramips/patches-5.10/990-NET-no-auto-carrier-off-support.patch
deleted file mode 100644 (file)
index a31d1ac..0000000
+++ /dev/null
@@ -1,47 +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
-@@ -546,7 +546,10 @@ static int phy_check_link_status(struct
-               phy_link_up(phydev);
-       } else if (!phydev->link && phydev->state != PHY_NOLINK) {
-               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);
-       }
-       return 0;
-@@ -926,7 +929,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
-@@ -380,6 +380,7 @@ struct phy_device {
-       unsigned suspended_by_mdio_bus:1;
-       unsigned sysfs_links:1;
-       unsigned loopback_enabled:1;
-+      unsigned no_auto_carrier_off:1;
-       unsigned autoneg:1;
-       /* The most recently read link state */
diff --git a/target/linux/ramips/patches-5.10/991-at803x.patch b/target/linux/ramips/patches-5.10/991-at803x.patch
deleted file mode 100644 (file)
index af0132f..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-From 924453aa9d2324e5611f8e2b71df746d8f0c79f1 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
-Date: Fri, 13 Nov 2020 16:11:32 +0100
-Subject: [PATCH] net: phy: at803x: add support for SFP module in
- RGMII-to-x-base mode
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: RenĂ© van Dorst <opensource@vdorst.com>
----
- drivers/net/phy/at803x.c | 91 ++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 91 insertions(+)
-
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -14,6 +14,8 @@
- #include <linux/etherdevice.h>
- #include <linux/of_gpio.h>
- #include <linux/gpio/consumer.h>
-+#include <linux/sfp.h>
-+#include <linux/phylink.h>
- #define AT803X_SPECIFIC_STATUS                        0x11
- #define AT803X_SS_SPEED_MASK                  (3 << 14)
-@@ -53,9 +55,18 @@
- #define AT803X_MODE_CFG_MASK                  0x0F
- #define AT803X_MODE_CFG_SGMII                 0x01
-+#define AT803X_MODE_CFG_BX1000_RGMII_50               0x02
-+#define AT803X_MODE_CFG_BX1000_RGMII_75               0x03
-+#define AT803X_MODE_FIBER                     0x01
-+#define AT803X_MODE_COPPER                    0x00
- #define AT803X_PSSR                   0x11    /*PHY-Specific Status Register*/
- #define AT803X_PSSR_MR_AN_COMPLETE    0x0200
-+#define        PSSR_LINK                      BIT(10)
-+#define        PSSR_SYNC_STATUS               BIT(8)
-+#define        PSSR_DUPLEX                    BIT(13)
-+#define        PSSR_SPEED_1000                BIT(15)
-+#define        PSSR_SPEED_100                 BIT(14)
- #define AT803X_DEBUG_REG_0                    0x00
- #define AT803X_DEBUG_RX_CLK_DLY_EN            BIT(15)
-@@ -243,10 +254,72 @@ static int at803x_resume(struct phy_devi
-       return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
- }
-+static int at803x_mode(struct phy_device *phydev)
-+{
-+      int mode;
-+
-+      mode = phy_read(phydev, AT803X_REG_CHIP_CONFIG) & AT803X_MODE_CFG_MASK;
-+
-+      if (mode == AT803X_MODE_CFG_BX1000_RGMII_50 ||
-+          mode == AT803X_MODE_CFG_BX1000_RGMII_75)
-+              return AT803X_MODE_FIBER;
-+      return AT803X_MODE_COPPER;
-+}
-+
-+static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-+{
-+      __ETHTOOL_DECLARE_LINK_MODE_MASK(at803x_support) = { 0, };
-+      __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
-+      struct phy_device *phydev = upstream;
-+      phy_interface_t iface;
-+
-+      phylink_set(at803x_support, 1000baseX_Full);
-+      /* AT803x only support 1000baseX but SGMII works fine when module runs
-+       * at 1Gbit.
-+       */
-+      phylink_set(at803x_support, 1000baseT_Full);
-+
-+      sfp_parse_support(phydev->sfp_bus, id, support);
-+
-+      // Limit to interfaces that both sides support
-+      linkmode_and(support, support, at803x_support);
-+
-+      if (linkmode_empty(support))
-+              goto unsupported_mode;
-+
-+      iface = sfp_select_interface(phydev->sfp_bus, support);
-+
-+      if (iface != PHY_INTERFACE_MODE_SGMII &&
-+          iface != PHY_INTERFACE_MODE_1000BASEX)
-+              goto unsupported_mode;
-+
-+      dev_info(&phydev->mdio.dev, "SFP interface %s", phy_modes(iface));
-+
-+      return 0;
-+
-+unsupported_mode:
-+      dev_info(&phydev->mdio.dev, "incompatible SFP module inserted;"
-+               "Only SGMII at 1Gbit/1000BASEX are supported!\n");
-+      return -EINVAL;
-+}
-+
-+static const struct sfp_upstream_ops at803x_sfp_ops = {
-+      .attach = phy_sfp_attach,
-+      .detach = phy_sfp_detach,
-+      .module_insert = at803x_sfp_insert,
-+};
-+
- static int at803x_probe(struct phy_device *phydev)
- {
-       struct device *dev = &phydev->mdio.dev;
-       struct at803x_priv *priv;
-+      int ret;
-+
-+      if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
-+              ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
-+              if (ret < 0)
-+                      return ret;
-+      }
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-@@ -394,6 +467,10 @@ static int at803x_read_status(struct phy
- {
-       int ss, err, old_link = phydev->link;
-+      /* Handle (Fiber) SGMII to RGMII mode */
-+      if (at803x_mode(phydev) == AT803X_MODE_FIBER)
-+              return genphy_c37_read_status(phydev);
-+
-       /* Update the link, but return if there was an error */
-       err = genphy_update_link(phydev);
-       if (err)
-@@ -448,6 +525,19 @@ static int at803x_read_status(struct phy
-       return 0;
- }
-+static int at803x_config_aneg(struct phy_device *phydev)
-+{
-+      /* Handle (Fiber) SerDes to RGMII mode */
-+      if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
-+              pr_warn("%s: fiber\n", __func__);
-+              return genphy_c37_config_aneg(phydev);
-+      }
-+
-+      pr_warn("%s: enter\n", __func__);
-+
-+      return genphy_config_aneg(phydev);
-+}
-+
- static struct phy_driver at803x_driver[] = {
- {
-       /* ATHEROS 8035 */
-@@ -491,6 +581,7 @@ static struct phy_driver at803x_driver[]
-       .suspend                = at803x_suspend,
-       .resume                 = at803x_resume,
-       /* PHY_GBIT_FEATURES */
-+      .config_aneg            = at803x_config_aneg,
-       .read_status            = at803x_read_status,
-       .aneg_done              = at803x_aneg_done,
-       .ack_interrupt          = &at803x_ack_interrupt,
diff --git a/target/linux/ramips/patches-5.10/999-fix-pci-init-mt7620.patch b/target/linux/ramips/patches-5.10/999-fix-pci-init-mt7620.patch
deleted file mode 100644 (file)
index 7c00d4c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
---- a/arch/mips/pci/pci-mt7620.c
-+++ b/arch/mips/pci/pci-mt7620.c
-@@ -32,6 +32,7 @@
- #define PPLL_CFG1                     0x9c
- #define PPLL_DRV                      0xa0
-+#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);
--      if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
--              dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
-+      if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
-+              dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n");
-               reset_control_assert(rstpcie0);
-               rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
-               return -1;