[openwrt/openwrt] ath79: restore kernel 6.1 config files and patches

LEDE Commits lede-commits at lists.infradead.org
Thu May 9 14:58:48 PDT 2024


hauke pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/d123330aa93a2d09f7dff039a2351d947d4fd8f7

commit d123330aa93a2d09f7dff039a2351d947d4fd8f7
Author: Shiji Yang <yangshiji66 at qq.com>
AuthorDate: Sat Mar 16 08:39:16 2024 +0800

    ath79: restore kernel 6.1 config files and patches
    
    Copy patches and kernel configs from kernel 6.6 to restore the
    default 6.1 kernel support files.
    
    Signed-off-by: Shiji Yang <yangshiji66 at qq.com>
---
 target/linux/ath79/config-6.1                      | 215 +++++
 ...-gpio-ath79-Convert-to-immutable-irq_chip.patch |  60 ++
 .../100-reset-ath79-read-back-reset-register.patch |  33 +
 ...-ath79-intc-add-irq-cascade-driver-for-QC.patch | 168 ++++
 ...irqchip-irq-ath79-cpu-drop-OF-init-helper.patch |  23 +
 ...bindings-PCI-qcom-ar7100-adds-binding-doc.patch |  57 ++
 .../311-MIPS-pci-ar71xx-convert-to-OF.patch        | 206 +++++
 ...bindings-PCI-qcom-ar7240-adds-binding-doc.patch |  61 ++
 .../313-MIPS-pci-ar724x-convert-to-OF.patch        | 213 +++++
 .../314-MIPS-ath79-remove-irq-code-from-pci.patch  | 149 ++++
 ...IPS-pci-ar724x-add-QCA9550-reset-sequence.patch | 130 +++
 ...MIPS-ath79-swizzle-pci-address-for-ar71xx.patch | 109 +++
 .../ath79/patches-6.1/330-missing-registers.patch  |  20 +
 ...-ath79-add-missing-QCA955x-GMAC-registers.patch |  90 ++
 .../ath79/patches-6.1/332-ath79-sgmii-config.patch |  30 +
 .../340-register_gpio_driver_earlier.patch         |  26 +
 .../patches-6.1/350-MIPS-ath79-ath9k-exports.patch |  36 +
 .../351-MIPS-ath79-common-exports.patch            |  26 +
 ...0-MIPS-ath79-export-UART1-reference-clock.patch |  67 ++
 .../370-MIPS-ath79-sanitize-symbols.patch          |  93 +++
 ...mtd-nor-support-mtd-name-from-device-tree.patch |  53 ++
 .../patches-6.1/410-mtd-cybertan-trx-parser.patch  |  45 +
 .../420-drivers-link-spi-before-mtd.patch          |  20 +
 .../patches-6.1/430-mtd-ar934x-nand-driver.patch   |  34 +
 .../patches-6.1/700-phy-add-ath79-usb-phys.patch   | 333 ++++++++
 .../701-usb-add-more-OF-quirk-properties.patch     |  24 +
 .../710-net-use-downstream-ag71xx.patch            |  42 +
 .../720-mdio_bitbang_ignore_ta_value.patch         |  44 +
 ...tbang-prevent-rescheduling-during-command.patch |  61 ++
 .../730-ar8216-make-reg-access-atomic.patch        |  59 ++
 ...00-leds-add-reset-controller-based-driver.patch | 186 +++++
 ...ore-the-abused-interrupt-map-on-pcie-node.patch |  33 +
 .../patches-6.1/900-unaligned_access_hacks.patch   | 909 +++++++++++++++++++++
 .../ath79/patches-6.1/910-mikrotik-rb4xx.patch     | 121 +++
 .../ath79/patches-6.1/911-mikrotik-rb91x.patch     |  96 +++
 35 files changed, 3872 insertions(+)

diff --git a/target/linux/ath79/config-6.1 b/target/linux/ath79/config-6.1
new file mode 100644
index 0000000000..87f520228f
--- /dev/null
+++ b/target/linux/ath79/config-6.1
@@ -0,0 +1,215 @@
+CONFIG_AG71XX=y
+# CONFIG_AG71XX_DEBUG is not set
+CONFIG_AG71XX_DEBUG_FS=y
+CONFIG_AR8216_PHY=y
+CONFIG_AR8216_PHY_LEDS=y
+CONFIG_ARCH_32BIT_OFF_T=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_KEEP_MEMBLOCK=y
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_AT803X_PHY=y
+CONFIG_ATH79=y
+CONFIG_ATH79_WDT=y
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
+CONFIG_CC_NO_ARRAY_BOUNDS=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_DIEI=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_RIXI=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_FIXED_PHY=y
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_GCC11_NO_ARRAY_BOUNDS=y
+CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CPU_AUTOPROBE=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_LIB_ASHLDI3=y
+CONFIG_GENERIC_LIB_ASHRDI3=y
+CONFIG_GENERIC_LIB_CMPDI2=y
+CONFIG_GENERIC_LIB_LSHRDI3=y
+CONFIG_GENERIC_LIB_UCMPDI2=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_74X164=y
+CONFIG_GPIO_ATH79=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_GENERIC=y
+# CONFIG_GPIO_LATCH_MIKROTIK is not set
+# CONFIG_GPIO_RB91X_KEY is not set
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_RESET is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MDIO_GPIO=y
+CONFIG_MEMFD_CREATE=y
+# CONFIG_MFD_RB4XX_CPLD is not set
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+# CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_LD_CAN_LINK_VDSO=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+CONFIG_MTD_PARSER_CYBERTAN=y
+# CONFIG_MTD_PARSER_TPLINK_SAFELOADER is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_ELF_FW=y
+CONFIG_MTD_SPLIT_LZMA_FW=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_TPLINK_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_SPLIT_WRGG_FW=y
+CONFIG_MTD_VIRT_CONCAT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+CONFIG_NVMEM=y
+CONFIG_NVMEM_LAYOUTS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_PAGE_POOL=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PCI=y
+CONFIG_PCI_AR71XX=y
+CONFIG_PCI_AR724X=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHYLIB_LEDS=y
+# CONFIG_PHY_AR7100_USB is not set
+# CONFIG_PHY_AR7200_USB is not set
+# CONFIG_PHY_ATH79_USB is not set
+CONFIG_PINCTRL=y
+CONFIG_PREEMPT_NONE_BUILD=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_QCOM_NET_PHYLIB=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_RESET_ATH79=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_AR933X=y
+CONFIG_SERIAL_AR933X_CONSOLE=y
+CONFIG_SERIAL_AR933X_NR_UARTS=2
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_AR934X=y
+CONFIG_SPI_ATH79=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+# CONFIG_SPI_RB4XX is not set
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_SUPPORTS_ZBOOT_UART_PROM=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TINY_SRCU=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_ZBOOT_LOAD_ADDRESS=0x0
diff --git a/target/linux/ath79/patches-6.1/010-v6.4-gpio-ath79-Convert-to-immutable-irq_chip.patch b/target/linux/ath79/patches-6.1/010-v6.4-gpio-ath79-Convert-to-immutable-irq_chip.patch
new file mode 100644
index 0000000000..942380fc7b
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/010-v6.4-gpio-ath79-Convert-to-immutable-irq_chip.patch
@@ -0,0 +1,60 @@
+From b11ce7e48121a02ceedec9f4dfcab4f2bee8f35f Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij at linaro.org>
+Date: Thu, 9 Mar 2023 08:45:54 +0100
+Subject: gpio: ath79: Convert to immutable irq_chip
+
+Convert the driver to immutable irq-chip with a bit of
+intuition.
+
+Cc: Marc Zyngier <maz at kernel.org>
+Acked-by: Marc Zyngier <maz at kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij at linaro.org>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski at linaro.org>
+---
+ drivers/gpio/gpio-ath79.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpio/gpio-ath79.c
++++ b/drivers/gpio/gpio-ath79.c
+@@ -71,6 +71,7 @@ static void ath79_gpio_irq_unmask(struct
+ 	u32 mask = BIT(irqd_to_hwirq(data));
+ 	unsigned long flags;
+ 
++	gpiochip_enable_irq(&ctrl->gc, irqd_to_hwirq(data));
+ 	raw_spin_lock_irqsave(&ctrl->lock, flags);
+ 	ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask);
+ 	raw_spin_unlock_irqrestore(&ctrl->lock, flags);
+@@ -85,6 +86,7 @@ static void ath79_gpio_irq_mask(struct i
+ 	raw_spin_lock_irqsave(&ctrl->lock, flags);
+ 	ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0);
+ 	raw_spin_unlock_irqrestore(&ctrl->lock, flags);
++	gpiochip_disable_irq(&ctrl->gc, irqd_to_hwirq(data));
+ }
+ 
+ static void ath79_gpio_irq_enable(struct irq_data *data)
+@@ -169,13 +171,15 @@ static int ath79_gpio_irq_set_type(struc
+ 	return 0;
+ }
+ 
+-static struct irq_chip ath79_gpio_irqchip = {
++static const struct irq_chip ath79_gpio_irqchip = {
+ 	.name = "gpio-ath79",
+ 	.irq_enable = ath79_gpio_irq_enable,
+ 	.irq_disable = ath79_gpio_irq_disable,
+ 	.irq_mask = ath79_gpio_irq_mask,
+ 	.irq_unmask = ath79_gpio_irq_unmask,
+ 	.irq_set_type = ath79_gpio_irq_set_type,
++	.flags = IRQCHIP_IMMUTABLE,
++	GPIOCHIP_IRQ_RESOURCE_HELPERS,
+ };
+ 
+ static void ath79_gpio_irq_handler(struct irq_desc *desc)
+@@ -274,7 +278,7 @@ static int ath79_gpio_probe(struct platf
+ 	/* Optional interrupt setup */
+ 	if (!np || of_property_read_bool(np, "interrupt-controller")) {
+ 		girq = &ctrl->gc.irq;
+-		girq->chip = &ath79_gpio_irqchip;
++		gpio_irq_chip_set_chip(girq, &ath79_gpio_irqchip);
+ 		girq->parent_handler = ath79_gpio_irq_handler;
+ 		girq->num_parents = 1;
+ 		girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
diff --git a/target/linux/ath79/patches-6.1/100-reset-ath79-read-back-reset-register.patch b/target/linux/ath79/patches-6.1/100-reset-ath79-read-back-reset-register.patch
new file mode 100644
index 0000000000..7aa501514d
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/100-reset-ath79-read-back-reset-register.patch
@@ -0,0 +1,33 @@
+From 661edfc3dab943a67c8821353b63cc23057f7ce9 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail at david-bauer.net>
+Date: Tue, 9 Jan 2024 20:48:46 +0100
+Subject: [PATCH] reset: ath79: read back reset register
+
+Read back the reset register in order to flush the cache. This fixes
+spurious reboot hangs on TP-Link TL-WDR3600 and TL-WDR4300 with Zentel
+DRAM chips.
+
+This issue was fixed in the past, but switching to the reset-driver
+specific implementation removed the old fix.
+
+Link: https://github.com/freifunk-gluon/gluon/issues/2904
+Link: https://github.com/openwrt/openwrt/issues/13043
+Link: https://dev.archive.openwrt.org/ticket/17839
+Link: f8a7bfe1cb2c ("MIPS: ath79: fix system restart")
+
+Signed-off-by: David Bauer <mail at david-bauer.net>
+---
+ drivers/reset/reset-ath79.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/reset/reset-ath79.c
++++ b/drivers/reset/reset-ath79.c
+@@ -37,6 +37,8 @@ static int ath79_reset_update(struct res
+ 	else
+ 		val &= ~BIT(id);
+ 	writel(val, ath79_reset->base);
++	/* Flush cache */
++	readl(ath79_reset->base);
+ 	spin_unlock_irqrestore(&ath79_reset->lock, flags);
+ 
+ 	return 0;
diff --git a/target/linux/ath79/patches-6.1/300-irqchip-irq-ath79-intc-add-irq-cascade-driver-for-QC.patch b/target/linux/ath79/patches-6.1/300-irqchip-irq-ath79-intc-add-irq-cascade-driver-for-QC.patch
new file mode 100644
index 0000000000..ceda511c21
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/300-irqchip-irq-ath79-intc-add-irq-cascade-driver-for-QC.patch
@@ -0,0 +1,168 @@
+From f3eacff2310a60348a755c50a8da6fc251fc8587 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Tue, 6 Mar 2018 09:55:13 +0100
+Subject: [PATCH 07/33] irqchip/irq-ath79-intc: add irq cascade driver for
+ QCA9556 SoCs
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/irqchip/Makefile         |   1 +
+ drivers/irqchip/irq-ath79-intc.c | 142 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 143 insertions(+)
+ create mode 100644 drivers/irqchip/irq-ath79-intc.c
+
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -4,6 +4,7 @@ obj-$(CONFIG_IRQCHIP)			+= irqchip.o
+ obj-$(CONFIG_AL_FIC)			+= irq-al-fic.o
+ obj-$(CONFIG_ALPINE_MSI)		+= irq-alpine-msi.o
+ obj-$(CONFIG_ATH79)			+= irq-ath79-cpu.o
++obj-$(CONFIG_ATH79)			+= irq-ath79-intc.o
+ obj-$(CONFIG_ATH79)			+= irq-ath79-misc.o
+ obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2835.o
+ obj-$(CONFIG_ARCH_BCM2835)		+= irq-bcm2836.o
+--- /dev/null
++++ b/drivers/irqchip/irq-ath79-intc.c
+@@ -0,0 +1,142 @@
++/*
++ *  Atheros AR71xx/AR724x/AR913x specific interrupt handling
++ *
++ *  Copyright (C) 2018 John Crispin <john at phrozen.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.
++ */
++
++#include <linux/interrupt.h>
++#include <linux/irqchip.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/irqdomain.h>
++
++#include <asm/irq_cpu.h>
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++
++#define ATH79_MAX_INTC_CASCADE	3
++
++struct ath79_intc {
++	struct irq_chip chip;
++	u32 irq;
++	u32 pending_mask;
++	u32 int_status;
++	u32 irq_mask[ATH79_MAX_INTC_CASCADE];
++	u32 irq_wb_chan[ATH79_MAX_INTC_CASCADE];
++};
++
++static void ath79_intc_irq_handler(struct irq_desc *desc)
++{
++	struct irq_domain *domain = irq_desc_get_handler_data(desc);
++	struct ath79_intc *intc = domain->host_data;
++	u32 pending;
++
++	pending = ath79_reset_rr(intc->int_status);
++	pending &= intc->pending_mask;
++
++	if (pending) {
++		int i;
++
++		for (i = 0; i < domain->hwirq_max; i++)
++			if (pending & intc->irq_mask[i]) {
++				if (intc->irq_wb_chan[i] != 0xffffffff)
++					ath79_ddr_wb_flush(intc->irq_wb_chan[i]);
++				generic_handle_irq(irq_find_mapping(domain, i));
++			}
++	} else {
++		spurious_interrupt();
++	}
++}
++
++static void ath79_intc_irq_enable(struct irq_data *d)
++{
++	struct ath79_intc *intc = d->domain->host_data;
++	enable_irq(intc->irq);
++}
++
++static void ath79_intc_irq_disable(struct irq_data *d)
++{
++	struct ath79_intc *intc = d->domain->host_data;
++	disable_irq(intc->irq);
++}
++
++static int ath79_intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
++{
++	struct ath79_intc *intc = d->host_data;
++
++	irq_set_chip_and_handler(irq, &intc->chip, handle_level_irq);
++
++	return 0;
++}
++
++static const struct irq_domain_ops ath79_irq_domain_ops = {
++	.xlate = irq_domain_xlate_onecell,
++	.map = ath79_intc_map,
++};
++
++static int __init ath79_intc_of_init(
++	struct device_node *node, struct device_node *parent)
++{
++	struct irq_domain *domain;
++	struct ath79_intc *intc;
++	int cnt, cntwb, i, err;
++
++	cnt = of_property_count_u32_elems(node, "qca,pending-bits");
++	if (cnt > ATH79_MAX_INTC_CASCADE)
++		panic("Too many INTC pending bits\n");
++
++	intc = kzalloc(sizeof(*intc), GFP_KERNEL);
++	if (!intc)
++		panic("Failed to allocate INTC memory\n");
++	intc->chip = dummy_irq_chip;
++	intc->chip.name = "INTC";
++	intc->chip.irq_disable = ath79_intc_irq_disable;
++	intc->chip.irq_enable = ath79_intc_irq_enable;
++
++	if (of_property_read_u32(node, "qca,int-status-addr", &intc->int_status) < 0) {
++		panic("Missing address of interrupt status register\n");
++	}
++
++	of_property_read_u32_array(node, "qca,pending-bits", intc->irq_mask, cnt);
++	for (i = 0; i < cnt; i++) {
++		intc->pending_mask |= intc->irq_mask[i];
++		intc->irq_wb_chan[i] = 0xffffffff;
++	}
++
++	cntwb = of_count_phandle_with_args(
++		node, "qca,ddr-wb-channels", "#qca,ddr-wb-channel-cells");
++
++	for (i = 0; i < cntwb; i++) {
++		struct of_phandle_args args;
++		u32 irq = i;
++
++		of_property_read_u32_index(
++			node, "qca,ddr-wb-channel-interrupts", i, &irq);
++		if (irq >= ATH79_MAX_INTC_CASCADE)
++			continue;
++
++		err = of_parse_phandle_with_args(
++			node, "qca,ddr-wb-channels",
++			"#qca,ddr-wb-channel-cells",
++			i, &args);
++		if (err)
++			return err;
++
++		intc->irq_wb_chan[irq] = args.args[0];
++	}
++
++	intc->irq = irq_of_parse_and_map(node, 0);
++	if (!intc->irq)
++		panic("Failed to get INTC IRQ");
++
++	domain = irq_domain_add_linear(node, cnt, &ath79_irq_domain_ops, intc);
++	irq_set_chained_handler_and_data(intc->irq, ath79_intc_irq_handler, domain);
++
++	return 0;
++}
++IRQCHIP_DECLARE(ath79_intc, "qca,ar9340-intc",
++		ath79_intc_of_init);
diff --git a/target/linux/ath79/patches-6.1/301-irqchip-irq-ath79-cpu-drop-OF-init-helper.patch b/target/linux/ath79/patches-6.1/301-irqchip-irq-ath79-cpu-drop-OF-init-helper.patch
new file mode 100644
index 0000000000..13117d9a8e
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/301-irqchip-irq-ath79-cpu-drop-OF-init-helper.patch
@@ -0,0 +1,23 @@
+From e029f998594f151008ecbfa024e2957edd2a5189 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Tue, 6 Mar 2018 09:58:19 +0100
+Subject: [PATCH 08/33] irqchip/irq-ath79-cpu: drop !OF init helper
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/irqchip/irq-ath79-cpu.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/drivers/irqchip/irq-ath79-cpu.c
++++ b/drivers/irqchip/irq-ath79-cpu.c
+@@ -85,10 +85,3 @@ static int __init ar79_cpu_intc_of_init(
+ }
+ IRQCHIP_DECLARE(ar79_cpu_intc, "qca,ar7100-cpu-intc",
+ 		ar79_cpu_intc_of_init);
+-
+-void __init ath79_cpu_irq_init(unsigned irq_wb_chan2, unsigned irq_wb_chan3)
+-{
+-	irq_wb_chan[2] = irq_wb_chan2;
+-	irq_wb_chan[3] = irq_wb_chan3;
+-	mips_cpu_irq_init();
+-}
diff --git a/target/linux/ath79/patches-6.1/310-dt-bindings-PCI-qcom-ar7100-adds-binding-doc.patch b/target/linux/ath79/patches-6.1/310-dt-bindings-PCI-qcom-ar7100-adds-binding-doc.patch
new file mode 100644
index 0000000000..cf0a75c791
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/310-dt-bindings-PCI-qcom-ar7100-adds-binding-doc.patch
@@ -0,0 +1,57 @@
+From 4a4f869ec58ed8910b9b2e68d0eee50957e9bb20 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Mon, 25 Jun 2018 15:52:10 +0200
+Subject: [PATCH 17/33] dt-bindings: PCI: qcom,ar7100: adds binding doc
+
+With the driver being converted from platform_data to pure OF, we need to
+also add some docs.
+
+Cc: Rob Herring <robh+dt at kernel.org>
+Cc: devicetree at vger.kernel.org
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ .../devicetree/bindings/pci/qcom,ar7100-pci.txt    | 38 ++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pci/qcom,ar7100-pci.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/qcom,ar7100-pci.txt
+@@ -0,0 +1,38 @@
++* Qualcomm Atheros AR7100 PCI express root complex
++
++Required properties:
++- compatible: should contain "qcom,ar7100-pci" to identify the core.
++- reg: Should contain the register ranges as listed in the reg-names property.
++- reg-names: Definition: Must include the following entries
++	- "cfg_base"	IO Memory
++- #address-cells: set to <3>
++- #size-cells: set to <2>
++- ranges: ranges for the PCI memory and I/O regions
++- interrupt-map-mask and interrupt-map: standard PCI
++	properties to define the mapping of the PCIe interface to interrupt
++	numbers.
++- #interrupt-cells: set to <1>
++- interrupt-controller: define to enable the builtin IRQ cascade.
++
++Optional properties:
++- interrupt-parent: phandle to the MIPS IRQ controller
++
++* Example for ar7100
++	pcie at 180c0000 {
++		compatible = "qca,ar7100-pci";
++		#address-cells = <3>;
++		#size-cells = <2>;
++		bus-range = <0x0 0x0>;
++		reg = <0x17010000 0x100>;
++		reg-names = "cfg_base";
++		ranges = <0x2000000 0 0x10000000 0x10000000 0 0x07000000
++			  0x1000000 0 0x00000000 0x00000000 0 0x00000001>;
++		interrupt-parent = <&cpuintc>;
++		interrupts = <2>;
++
++		interrupt-controller;
++		#interrupt-cells = <1>;
++
++		interrupt-map-mask = <0 0 0 1>;
++		interrupt-map = <0 0 0 0 &pcie0 0>;
++	};
diff --git a/target/linux/ath79/patches-6.1/311-MIPS-pci-ar71xx-convert-to-OF.patch b/target/linux/ath79/patches-6.1/311-MIPS-pci-ar71xx-convert-to-OF.patch
new file mode 100644
index 0000000000..9a315aed0b
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/311-MIPS-pci-ar71xx-convert-to-OF.patch
@@ -0,0 +1,206 @@
+From 1855ab6b1d27f5b38a648baf57ff6a534afec26d Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Sat, 23 Jun 2018 15:07:23 +0200
+Subject: [PATCH 18/33] MIPS: pci-ar71xx: convert to OF
+
+With the ath79 target getting converted to pure OF, we can drop all the
+platform data code and add the missing OF bits to the driver. We also add
+a irq domain for the PCI/e controllers cascade, thus making it usable from
+dts files.
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ arch/mips/pci/pci-ar71xx.c | 82 +++++++++++++++++++++++-----------------------
+ 1 file changed, 41 insertions(+), 41 deletions(-)
+
+--- a/arch/mips/pci/pci-ar71xx.c
++++ b/arch/mips/pci/pci-ar71xx.c
+@@ -15,8 +15,11 @@
+ #include <linux/pci.h>
+ #include <linux/pci_regs.h>
+ #include <linux/interrupt.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <linux/init.h>
+ #include <linux/platform_device.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
+ 
+ #include <asm/mach-ath79/ar71xx_regs.h>
+ #include <asm/mach-ath79/ath79.h>
+@@ -46,12 +49,13 @@
+ #define AR71XX_PCI_IRQ_COUNT		5
+ 
+ struct ar71xx_pci_controller {
++	struct device_node *np;
+ 	void __iomem *cfg_base;
+ 	int irq;
+-	int irq_base;
+ 	struct pci_controller pci_ctrl;
+ 	struct resource io_res;
+ 	struct resource mem_res;
++	struct irq_domain *domain;
+ };
+ 
+ /* Byte lane enable bits */
+@@ -225,29 +229,30 @@ static struct pci_ops ar71xx_pci_ops = {
+ 
+ static void ar71xx_pci_irq_handler(struct irq_desc *desc)
+ {
+-	struct ar71xx_pci_controller *apc;
+ 	void __iomem *base = ath79_reset_base;
++	struct irq_chip *chip = irq_desc_get_chip(desc);
++	struct ar71xx_pci_controller *apc = irq_desc_get_handler_data(desc);
+ 	u32 pending;
+ 
+-	apc = irq_desc_get_handler_data(desc);
+-
++	chained_irq_enter(chip, desc);
+ 	pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
+ 		  __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ 
+ 	if (pending & AR71XX_PCI_INT_DEV0)
+-		generic_handle_irq(apc->irq_base + 0);
++		generic_handle_irq(irq_linear_revmap(apc->domain, 1));
+ 
+ 	else if (pending & AR71XX_PCI_INT_DEV1)
+-		generic_handle_irq(apc->irq_base + 1);
++		generic_handle_irq(irq_linear_revmap(apc->domain, 2));
+ 
+ 	else if (pending & AR71XX_PCI_INT_DEV2)
+-		generic_handle_irq(apc->irq_base + 2);
++		generic_handle_irq(irq_linear_revmap(apc->domain, 3));
+ 
+ 	else if (pending & AR71XX_PCI_INT_CORE)
+-		generic_handle_irq(apc->irq_base + 4);
++		generic_handle_irq(irq_linear_revmap(apc->domain, 4));
+ 
+ 	else
+ 		spurious_interrupt();
++	chained_irq_exit(chip, desc);
+ }
+ 
+ static void ar71xx_pci_irq_unmask(struct irq_data *d)
+@@ -258,7 +263,7 @@ static void ar71xx_pci_irq_unmask(struct
+ 	u32 t;
+ 
+ 	apc = irq_data_get_irq_chip_data(d);
+-	irq = d->irq - apc->irq_base;
++	irq = irq_linear_revmap(apc->domain, d->irq);
+ 
+ 	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ 	__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+@@ -275,7 +280,7 @@ static void ar71xx_pci_irq_mask(struct i
+ 	u32 t;
+ 
+ 	apc = irq_data_get_irq_chip_data(d);
+-	irq = d->irq - apc->irq_base;
++	irq = irq_linear_revmap(apc->domain, d->irq);
+ 
+ 	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ 	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+@@ -291,24 +296,31 @@ static struct irq_chip ar71xx_pci_irq_ch
+ 	.irq_mask_ack	= ar71xx_pci_irq_mask,
+ };
+ 
++static int ar71xx_pci_irq_map(struct irq_domain *d,
++			      unsigned int irq, irq_hw_number_t hw)
++{
++	struct ar71xx_pci_controller *apc = d->host_data;
++
++	irq_set_chip_and_handler(irq, &ar71xx_pci_irq_chip, handle_level_irq);
++	irq_set_chip_data(irq, apc);
++
++	return 0;
++}
++
++static const struct irq_domain_ops ar71xx_pci_domain_ops = {
++	.xlate = irq_domain_xlate_onecell,
++	.map = ar71xx_pci_irq_map,
++};
++
+ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
+ {
+ 	void __iomem *base = ath79_reset_base;
+-	int i;
+ 
+ 	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+ 	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
+ 
+-	BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT);
+-
+-	apc->irq_base = ATH79_PCI_IRQ_BASE;
+-	for (i = apc->irq_base;
+-	     i < apc->irq_base + AR71XX_PCI_IRQ_COUNT; i++) {
+-		irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip,
+-					 handle_level_irq);
+-		irq_set_chip_data(i, apc);
+-	}
+-
++	apc->domain = irq_domain_add_linear(apc->np, AR71XX_PCI_IRQ_COUNT,
++					    &ar71xx_pci_domain_ops, apc);
+ 	irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler,
+ 					 apc);
+ }
+@@ -325,10 +337,14 @@ static void ar71xx_pci_reset(void)
+ 	mdelay(100);
+ }
+ 
++static const struct of_device_id ar71xx_pci_ids[] = {
++	{ .compatible = "qca,ar7100-pci" },
++	{},
++};
++
+ static int ar71xx_pci_probe(struct platform_device *pdev)
+ {
+ 	struct ar71xx_pci_controller *apc;
+-	struct resource *res;
+ 	u32 t;
+ 
+ 	apc = devm_kzalloc(&pdev->dev, sizeof(struct ar71xx_pci_controller),
+@@ -345,26 +361,6 @@ static int ar71xx_pci_probe(struct platf
+ 	if (apc->irq < 0)
+ 		return -EINVAL;
+ 
+-	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base");
+-	if (!res)
+-		return -EINVAL;
+-
+-	apc->io_res.parent = res;
+-	apc->io_res.name = "PCI IO space";
+-	apc->io_res.start = res->start;
+-	apc->io_res.end = res->end;
+-	apc->io_res.flags = IORESOURCE_IO;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base");
+-	if (!res)
+-		return -EINVAL;
+-
+-	apc->mem_res.parent = res;
+-	apc->mem_res.name = "PCI memory space";
+-	apc->mem_res.start = res->start;
+-	apc->mem_res.end = res->end;
+-	apc->mem_res.flags = IORESOURCE_MEM;
+-
+ 	ar71xx_pci_reset();
+ 
+ 	/* setup COMMAND register */
+@@ -377,9 +373,11 @@ static int ar71xx_pci_probe(struct platf
+ 
+ 	ar71xx_pci_irq_init(apc);
+ 
++	apc->np = pdev->dev.of_node;
+ 	apc->pci_ctrl.pci_ops = &ar71xx_pci_ops;
+ 	apc->pci_ctrl.mem_resource = &apc->mem_res;
+ 	apc->pci_ctrl.io_resource = &apc->io_res;
++	pci_load_of_ranges(&apc->pci_ctrl, pdev->dev.of_node);
+ 
+ 	register_pci_controller(&apc->pci_ctrl);
+ 
+@@ -390,6 +388,7 @@ static struct platform_driver ar71xx_pci
+ 	.probe = ar71xx_pci_probe,
+ 	.driver = {
+ 		.name = "ar71xx-pci",
++		.of_match_table = of_match_ptr(ar71xx_pci_ids),
+ 	},
+ };
+ 
diff --git a/target/linux/ath79/patches-6.1/312-dt-bindings-PCI-qcom-ar7240-adds-binding-doc.patch b/target/linux/ath79/patches-6.1/312-dt-bindings-PCI-qcom-ar7240-adds-binding-doc.patch
new file mode 100644
index 0000000000..a32c9bdcde
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/312-dt-bindings-PCI-qcom-ar7240-adds-binding-doc.patch
@@ -0,0 +1,61 @@
+From ea27764bc3ef2a05decf3ae05edffc289cd0d93c Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Mon, 25 Jun 2018 15:52:02 +0200
+Subject: [PATCH 19/33] dt-bindings: PCI: qcom,ar7240: adds binding doc
+
+With the driver being converted from platform_data to pure OF, we need to
+also add some docs.
+
+Cc: Rob Herring <robh+dt at kernel.org>
+Cc: devicetree at vger.kernel.org
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ .../devicetree/bindings/pci/qcom,ar7240-pci.txt    | 42 ++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/pci/qcom,ar7240-pci.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pci/qcom,ar7240-pci.txt
+@@ -0,0 +1,42 @@
++* Qualcomm Atheros AR724X PCI express root complex
++
++Required properties:
++- compatible: should contain "qcom,ar7240-pci" to identify the core.
++- reg: Should contain the register ranges as listed in the reg-names property.
++- reg-names: Definition: Must include the following entries
++	- "crp_base"	Configuration registers
++	- "ctrl_base"	Control registers
++	- "cfg_base"	IO Memory
++- #address-cells: set to <3>
++- #size-cells: set to <2>
++- ranges: ranges for the PCI memory and I/O regions
++- interrupt-map-mask and interrupt-map: standard PCI
++	properties to define the mapping of the PCIe interface to interrupt
++	numbers.
++- #interrupt-cells: set to <1>
++- interrupt-parent: phandle to the MIPS IRQ controller
++
++Optional properties:
++- interrupt-controller: define to enable the builtin IRQ cascade.
++
++* Example for qca9557
++	pcie at 180c0000 {
++		compatible = "qcom,ar7240-pci";
++		#address-cells = <3>;
++		#size-cells = <2>;
++		bus-range = <0x0 0x0>;
++		reg = <0x180c0000 0x1000>,
++		      <0x180f0000 0x100>,
++		      <0x14000000 0x1000>;
++		reg-names = "crp_base", "ctrl_base", "cfg_base";
++		ranges = <0x2000000 0 0x10000000 0x10000000 0 0x04000000
++			  0x1000000 0 0x00000000 0x00000000 0 0x00000001>;
++		interrupt-parent = <&intc2>;
++		interrupts = <1>;
++
++		interrupt-controller;
++		#interrupt-cells = <1>;
++
++		interrupt-map-mask = <0 0 0 1>;
++		interrupt-map = <0 0 0 0 &pcie0 0>;
++	};
diff --git a/target/linux/ath79/patches-6.1/313-MIPS-pci-ar724x-convert-to-OF.patch b/target/linux/ath79/patches-6.1/313-MIPS-pci-ar724x-convert-to-OF.patch
new file mode 100644
index 0000000000..7927c1cbf5
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/313-MIPS-pci-ar724x-convert-to-OF.patch
@@ -0,0 +1,213 @@
+From a522ee0199d5d3ea114ca2e211f6ac398d3e8e0b Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Sat, 23 Jun 2018 15:07:37 +0200
+Subject: [PATCH 20/33] MIPS: pci-ar724x: convert to OF
+
+With the ath79 target getting converted to pure OF, we can drop all the
+platform data code and add the missing OF bits to the driver. We also add
+a irq domain for the PCI/e controllers cascade, thus making it usable from
+dts files.
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ arch/mips/pci/pci-ar724x.c | 88 ++++++++++++++++++++++------------------------
+ 1 file changed, 42 insertions(+), 46 deletions(-)
+
+--- a/arch/mips/pci/pci-ar724x.c
++++ b/arch/mips/pci/pci-ar724x.c
+@@ -11,8 +11,11 @@
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/platform_device.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <asm/mach-ath79/ath79.h>
+ #include <asm/mach-ath79/ar71xx_regs.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
+ 
+ #define AR724X_PCI_REG_APP		0x00
+ #define AR724X_PCI_REG_RESET		0x18
+@@ -42,17 +45,20 @@ struct ar724x_pci_controller {
+ 	void __iomem *crp_base;
+ 
+ 	int irq;
+-	int irq_base;
+ 
+ 	bool link_up;
+ 	bool bar0_is_cached;
+ 	u32  bar0_value;
+ 
++	struct device_node *np;
+ 	struct pci_controller pci_controller;
++	struct irq_domain *domain;
+ 	struct resource io_res;
+ 	struct resource mem_res;
+ };
+ 
++static struct irq_chip ar724x_pci_irq_chip;
++
+ static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc)
+ {
+ 	u32 reset;
+@@ -228,35 +234,31 @@ static struct pci_ops ar724x_pci_ops = {
+ 
+ static void ar724x_pci_irq_handler(struct irq_desc *desc)
+ {
+-	struct ar724x_pci_controller *apc;
+-	void __iomem *base;
++	struct irq_chip *chip = irq_desc_get_chip(desc);
++	struct ar724x_pci_controller *apc = irq_desc_get_handler_data(desc);
+ 	u32 pending;
+ 
+-	apc = irq_desc_get_handler_data(desc);
+-	base = apc->ctrl_base;
+-
+-	pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
+-		  __raw_readl(base + AR724X_PCI_REG_INT_MASK);
++	chained_irq_enter(chip, desc);
++	pending = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_INT_STATUS) &
++		  __raw_readl(apc->ctrl_base + AR724X_PCI_REG_INT_MASK);
+ 
+ 	if (pending & AR724X_PCI_INT_DEV0)
+-		generic_handle_irq(apc->irq_base + 0);
+-
++		generic_handle_irq(irq_linear_revmap(apc->domain, 1));
+ 	else
+ 		spurious_interrupt();
++	chained_irq_exit(chip, desc);
+ }
+ 
+ static void ar724x_pci_irq_unmask(struct irq_data *d)
+ {
+ 	struct ar724x_pci_controller *apc;
+ 	void __iomem *base;
+-	int offset;
+ 	u32 t;
+ 
+ 	apc = irq_data_get_irq_chip_data(d);
+ 	base = apc->ctrl_base;
+-	offset = apc->irq_base - d->irq;
+ 
+-	switch (offset) {
++	switch (irq_linear_revmap(apc->domain, d->irq)) {
+ 	case 0:
+ 		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+ 		__raw_writel(t | AR724X_PCI_INT_DEV0,
+@@ -270,14 +272,12 @@ static void ar724x_pci_irq_mask(struct i
+ {
+ 	struct ar724x_pci_controller *apc;
+ 	void __iomem *base;
+-	int offset;
+ 	u32 t;
+ 
+ 	apc = irq_data_get_irq_chip_data(d);
+ 	base = apc->ctrl_base;
+-	offset = apc->irq_base - d->irq;
+ 
+-	switch (offset) {
++	switch (irq_linear_revmap(apc->domain, d->irq)) {
+ 	case 0:
+ 		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
+ 		__raw_writel(t & ~AR724X_PCI_INT_DEV0,
+@@ -302,26 +302,34 @@ static struct irq_chip ar724x_pci_irq_ch
+ 	.irq_mask_ack	= ar724x_pci_irq_mask,
+ };
+ 
++static int ar724x_pci_irq_map(struct irq_domain *d,
++			      unsigned int irq, irq_hw_number_t hw)
++{
++	struct ar724x_pci_controller *apc = d->host_data;
++
++	irq_set_chip_and_handler(irq, &ar724x_pci_irq_chip, handle_level_irq);
++	irq_set_chip_data(irq, apc);
++
++	return 0;
++}
++
++static const struct irq_domain_ops ar724x_pci_domain_ops = {
++	.xlate = irq_domain_xlate_onecell,
++	.map = ar724x_pci_irq_map,
++};
++
+ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc,
+ 				int id)
+ {
+ 	void __iomem *base;
+-	int i;
+ 
+ 	base = apc->ctrl_base;
+ 
+ 	__raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
+ 	__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
+ 
+-	apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT);
+-
+-	for (i = apc->irq_base;
+-	     i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) {
+-		irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
+-					 handle_level_irq);
+-		irq_set_chip_data(i, apc);
+-	}
+-
++	apc->domain = irq_domain_add_linear(apc->np, 2,
++					    &ar724x_pci_domain_ops, apc);
+ 	irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler,
+ 					 apc);
+ }
+@@ -360,7 +368,6 @@ static void ar724x_pci_hw_init(struct ar
+ static int ar724x_pci_probe(struct platform_device *pdev)
+ {
+ 	struct ar724x_pci_controller *apc;
+-	struct resource *res;
+ 	int id;
+ 
+ 	id = pdev->id;
+@@ -388,29 +395,11 @@ static int ar724x_pci_probe(struct platf
+ 	if (apc->irq < 0)
+ 		return -EINVAL;
+ 
+-	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base");
+-	if (!res)
+-		return -EINVAL;
+-
+-	apc->io_res.parent = res;
+-	apc->io_res.name = "PCI IO space";
+-	apc->io_res.start = res->start;
+-	apc->io_res.end = res->end;
+-	apc->io_res.flags = IORESOURCE_IO;
+-
+-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base");
+-	if (!res)
+-		return -EINVAL;
+-
+-	apc->mem_res.parent = res;
+-	apc->mem_res.name = "PCI memory space";
+-	apc->mem_res.start = res->start;
+-	apc->mem_res.end = res->end;
+-	apc->mem_res.flags = IORESOURCE_MEM;
+-
++	apc->np = pdev->dev.of_node;
+ 	apc->pci_controller.pci_ops = &ar724x_pci_ops;
+ 	apc->pci_controller.io_resource = &apc->io_res;
+ 	apc->pci_controller.mem_resource = &apc->mem_res;
++	pci_load_of_ranges(&apc->pci_controller, pdev->dev.of_node);
+ 
+ 	/*
+ 	 * Do the full PCIE Root Complex Initialization Sequence if the PCIe
+@@ -432,10 +421,16 @@ static int ar724x_pci_probe(struct platf
+ 	return 0;
+ }
+ 
++static const struct of_device_id ar724x_pci_ids[] = {
++	{ .compatible = "qcom,ar7240-pci" },
++	{},
++};
++
+ static struct platform_driver ar724x_pci_driver = {
+ 	.probe = ar724x_pci_probe,
+ 	.driver = {
+ 		.name = "ar724x-pci",
++		.of_match_table = of_match_ptr(ar724x_pci_ids),
+ 	},
+ };
+ 
diff --git a/target/linux/ath79/patches-6.1/314-MIPS-ath79-remove-irq-code-from-pci.patch b/target/linux/ath79/patches-6.1/314-MIPS-ath79-remove-irq-code-from-pci.patch
new file mode 100644
index 0000000000..01549eec68
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/314-MIPS-ath79-remove-irq-code-from-pci.patch
@@ -0,0 +1,149 @@
+From: John Crispin <john at phrozen.org>
+Subject: ath79: fix remove irq code from pci driver patch
+
+This patch got mangled in the void while rebasing it.
+
+Submitted-by: John Crispin <john at phrozen.org>
+---
+ arch/mips/pci/pci-ar71xx.c                    | 107 ------------------
+ 1 file changed, 141 deletions(-)
+
+--- a/arch/mips/pci/pci-ar71xx.c
++++ b/arch/mips/pci/pci-ar71xx.c
+@@ -51,11 +51,9 @@
+ struct ar71xx_pci_controller {
+ 	struct device_node *np;
+ 	void __iomem *cfg_base;
+-	int irq;
+ 	struct pci_controller pci_ctrl;
+ 	struct resource io_res;
+ 	struct resource mem_res;
+-	struct irq_domain *domain;
+ };
+ 
+ /* Byte lane enable bits */
+@@ -227,104 +225,6 @@ static struct pci_ops ar71xx_pci_ops = {
+ 	.write	= ar71xx_pci_write_config,
+ };
+ 
+-static void ar71xx_pci_irq_handler(struct irq_desc *desc)
+-{
+-	void __iomem *base = ath79_reset_base;
+-	struct irq_chip *chip = irq_desc_get_chip(desc);
+-	struct ar71xx_pci_controller *apc = irq_desc_get_handler_data(desc);
+-	u32 pending;
+-
+-	chained_irq_enter(chip, desc);
+-	pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) &
+-		  __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-	if (pending & AR71XX_PCI_INT_DEV0)
+-		generic_handle_irq(irq_linear_revmap(apc->domain, 1));
+-
+-	else if (pending & AR71XX_PCI_INT_DEV1)
+-		generic_handle_irq(irq_linear_revmap(apc->domain, 2));
+-
+-	else if (pending & AR71XX_PCI_INT_DEV2)
+-		generic_handle_irq(irq_linear_revmap(apc->domain, 3));
+-
+-	else if (pending & AR71XX_PCI_INT_CORE)
+-		generic_handle_irq(irq_linear_revmap(apc->domain, 4));
+-
+-	else
+-		spurious_interrupt();
+-	chained_irq_exit(chip, desc);
+-}
+-
+-static void ar71xx_pci_irq_unmask(struct irq_data *d)
+-{
+-	struct ar71xx_pci_controller *apc;
+-	unsigned int irq;
+-	void __iomem *base = ath79_reset_base;
+-	u32 t;
+-
+-	apc = irq_data_get_irq_chip_data(d);
+-	irq = irq_linear_revmap(apc->domain, d->irq);
+-
+-	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-	__raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-	/* flush write */
+-	__raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-}
+-
+-static void ar71xx_pci_irq_mask(struct irq_data *d)
+-{
+-	struct ar71xx_pci_controller *apc;
+-	unsigned int irq;
+-	void __iomem *base = ath79_reset_base;
+-	u32 t;
+-
+-	apc = irq_data_get_irq_chip_data(d);
+-	irq = irq_linear_revmap(apc->domain, d->irq);
+-
+-	t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-	__raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-
+-	/* flush write */
+-	__raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-}
+-
+-static struct irq_chip ar71xx_pci_irq_chip = {
+-	.name		= "AR71XX PCI",
+-	.irq_mask	= ar71xx_pci_irq_mask,
+-	.irq_unmask	= ar71xx_pci_irq_unmask,
+-	.irq_mask_ack	= ar71xx_pci_irq_mask,
+-};
+-
+-static int ar71xx_pci_irq_map(struct irq_domain *d,
+-			      unsigned int irq, irq_hw_number_t hw)
+-{
+-	struct ar71xx_pci_controller *apc = d->host_data;
+-
+-	irq_set_chip_and_handler(irq, &ar71xx_pci_irq_chip, handle_level_irq);
+-	irq_set_chip_data(irq, apc);
+-
+-	return 0;
+-}
+-
+-static const struct irq_domain_ops ar71xx_pci_domain_ops = {
+-	.xlate = irq_domain_xlate_onecell,
+-	.map = ar71xx_pci_irq_map,
+-};
+-
+-static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc)
+-{
+-	void __iomem *base = ath79_reset_base;
+-
+-	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE);
+-	__raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS);
+-
+-	apc->domain = irq_domain_add_linear(apc->np, AR71XX_PCI_IRQ_COUNT,
+-					    &ar71xx_pci_domain_ops, apc);
+-	irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler,
+-					 apc);
+-}
+-
+ static void ar71xx_pci_reset(void)
+ {
+ 	ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE);
+@@ -357,10 +257,6 @@ static int ar71xx_pci_probe(struct platf
+ 	if (IS_ERR(apc->cfg_base))
+ 		return PTR_ERR(apc->cfg_base);
+ 
+-	apc->irq = platform_get_irq(pdev, 0);
+-	if (apc->irq < 0)
+-		return -EINVAL;
+-
+ 	ar71xx_pci_reset();
+ 
+ 	/* setup COMMAND register */
+@@ -371,8 +267,6 @@ static int ar71xx_pci_probe(struct platf
+ 	/* clear bus errors */
+ 	ar71xx_pci_check_error(apc, 1);
+ 
+-	ar71xx_pci_irq_init(apc);
+-
+ 	apc->np = pdev->dev.of_node;
+ 	apc->pci_ctrl.pci_ops = &ar71xx_pci_ops;
+ 	apc->pci_ctrl.mem_resource = &apc->mem_res;
diff --git a/target/linux/ath79/patches-6.1/315-MIPS-pci-ar724x-add-QCA9550-reset-sequence.patch b/target/linux/ath79/patches-6.1/315-MIPS-pci-ar724x-add-QCA9550-reset-sequence.patch
new file mode 100644
index 0000000000..375dec8ba2
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/315-MIPS-pci-ar724x-add-QCA9550-reset-sequence.patch
@@ -0,0 +1,130 @@
+From: David Bauer <mail at david-bauer.net>
+Date: Sat, 11 Apr 2020 14:03:12 +0200
+Subject: MIPS: pci-ar724x: add QCA9550 reset sequence
+
+The QCA9550 family of SoCs have a slightly different reset
+sequence compared to older chips.
+
+Normally the bootloader performs this sequence, however
+some bootloader implementation expect the operating system
+to clear the reset.
+
+Also get the resets from OF to support handling of the second
+PCIe root-complex on the QCA9558.
+
+Signed-off-by: David Bauer <mail at david-bauer.net>
+
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -390,6 +390,7 @@
+ #define QCA955X_PLL_CPU_CONFIG_REG		0x00
+ #define QCA955X_PLL_DDR_CONFIG_REG		0x04
+ #define QCA955X_PLL_CLK_CTRL_REG		0x08
++#define QCA955X_PLL_PCIE_CONFIG_REG		0x0c
+ #define QCA955X_PLL_ETH_XMII_CONTROL_REG	0x28
+ #define QCA955X_PLL_ETH_SGMII_CONTROL_REG	0x48
+ #define QCA955X_PLL_ETH_SGMII_SERDES_REG	0x4c
+@@ -475,6 +476,9 @@
+ #define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL	BIT(21)
+ #define QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+ 
++#define QCA955X_PLL_PCIE_CONFIG_PLL_PWD			BIT(30)
++#define QCA955X_PLL_PCIE_CONFIG_PLL_BYPASS		BIT(16)
++
+ #define QCA956X_PLL_SWITCH_CLOCK_SPARE_I2C_CLK_SELB		BIT(5)
+ #define QCA956X_PLL_SWITCH_CLOCK_SPARE_MDIO_CLK_SEL0_1		BIT(6)
+ #define QCA956X_PLL_SWITCH_CLOCK_SPARE_UART1_CLK_SEL		BIT(7)
+--- a/arch/mips/pci/pci-ar724x.c
++++ b/arch/mips/pci/pci-ar724x.c
+@@ -8,6 +8,7 @@
+ 
+ #include <linux/irq.h>
+ #include <linux/pci.h>
++#include <linux/reset.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/platform_device.h>
+@@ -55,6 +56,9 @@ struct ar724x_pci_controller {
+ 	struct irq_domain *domain;
+ 	struct resource io_res;
+ 	struct resource mem_res;
++
++	struct reset_control *hc_reset;
++	struct reset_control *phy_reset;
+ };
+ 
+ static struct irq_chip ar724x_pci_irq_chip;
+@@ -340,18 +344,30 @@ static void ar724x_pci_hw_init(struct ar
+ 	int wait = 0;
+ 
+ 	/* deassert PCIe host controller and PCIe PHY reset */
+-	ath79_device_reset_clear(AR724X_RESET_PCIE);
+-	ath79_device_reset_clear(AR724X_RESET_PCIE_PHY);
++	reset_control_deassert(apc->hc_reset);
++	reset_control_deassert(apc->phy_reset);
+ 
+-	/* remove the reset of the PCIE PLL */
+-	ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
+-	ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_RESET;
+-	ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
+-
+-	/* deassert bypass for the PCIE PLL */
+-	ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
+-	ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_BYPASS;
+-	ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
++	if (of_device_is_compatible(apc->np, "qcom,qca9550-pci")) {
++		/* remove the reset of the PCIE PLL */
++		ppl = ath79_pll_rr(QCA955X_PLL_PCIE_CONFIG_REG);
++		ppl &= ~QCA955X_PLL_PCIE_CONFIG_PLL_PWD;
++		ath79_pll_wr(QCA955X_PLL_PCIE_CONFIG_REG, ppl);
++
++		/* deassert bypass for the PCIE PLL */
++		ppl = ath79_pll_rr(QCA955X_PLL_PCIE_CONFIG_REG);
++		ppl &= ~QCA955X_PLL_PCIE_CONFIG_PLL_BYPASS;
++		ath79_pll_wr(QCA955X_PLL_PCIE_CONFIG_REG, ppl);
++	} else {
++		/* remove the reset of the PCIE PLL */
++		ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
++		ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_RESET;
++		ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
++
++		/* deassert bypass for the PCIE PLL */
++		ppl = ath79_pll_rr(AR724X_PLL_REG_PCIE_CONFIG);
++		ppl &= ~AR724X_PLL_REG_PCIE_CONFIG_PPL_BYPASS;
++		ath79_pll_wr(AR724X_PLL_REG_PCIE_CONFIG, ppl);
++	}
+ 
+ 	/* set PCIE Application Control to ready */
+ 	app = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_APP);
+@@ -395,6 +411,14 @@ static int ar724x_pci_probe(struct platf
+ 	if (apc->irq < 0)
+ 		return -EINVAL;
+ 
++	apc->hc_reset = devm_reset_control_get_exclusive(&pdev->dev, "hc");
++	if (IS_ERR(apc->hc_reset))
++		return PTR_ERR(apc->hc_reset);
++
++	apc->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, "phy");
++	if (IS_ERR(apc->phy_reset))
++		return PTR_ERR(apc->phy_reset);
++
+ 	apc->np = pdev->dev.of_node;
+ 	apc->pci_controller.pci_ops = &ar724x_pci_ops;
+ 	apc->pci_controller.io_resource = &apc->io_res;
+@@ -405,7 +429,7 @@ static int ar724x_pci_probe(struct platf
+ 	 * Do the full PCIE Root Complex Initialization Sequence if the PCIe
+ 	 * host controller is in reset.
+ 	 */
+-	if (ath79_reset_rr(AR724X_RESET_REG_RESET_MODULE) & AR724X_RESET_PCIE)
++	if (reset_control_status(apc->hc_reset))
+ 		ar724x_pci_hw_init(apc);
+ 
+ 	apc->link_up = ar724x_pci_check_link(apc);
+@@ -423,6 +447,7 @@ static int ar724x_pci_probe(struct platf
+ 
+ static const struct of_device_id ar724x_pci_ids[] = {
+ 	{ .compatible = "qcom,ar7240-pci" },
++	{ .compatible = "qcom,qca9550-pci" },
+ 	{},
+ };
+ 
diff --git a/target/linux/ath79/patches-6.1/316-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch b/target/linux/ath79/patches-6.1/316-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch
new file mode 100644
index 0000000000..1e2715b84c
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/316-MIPS-ath79-swizzle-pci-address-for-ar71xx.patch
@@ -0,0 +1,109 @@
+From: Gabor Juhos <juhosg at openwrt.org>
+Subject: [PATCH] ar71xx: swizzle address for PCI byte/word access on AR71xx
+
+Closes #11683.
+
+SVN-Revision: 32639
+---
+ .../mips/include/asm/mach-ath79/mangle-port.h | 111 ++++++++++++++++++
+ 1 file changed, 111 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ath79/mangle-port.h
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ath79/mangle-port.h
+@@ -0,0 +1,37 @@
++/*
++ *  Copyright (C) 2012 Gabor Juhos <juhosg at openwrt.org>
++ *
++ *  This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
++ *      Copyright (C) 2003, 2004 Ralf Baechle
++ *
++ *  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_ATH79_MANGLE_PORT_H
++#define __ASM_MACH_ATH79_MANGLE_PORT_H
++
++#ifdef CONFIG_PCI_AR71XX
++extern unsigned long (ath79_pci_swizzle_b)(unsigned long port);
++extern unsigned long (ath79_pci_swizzle_w)(unsigned long port);
++#else
++#define ath79_pci_swizzle_b(port) (port)
++#define ath79_pci_swizzle_w(port) (port)
++#endif
++
++#define __swizzle_addr_b(port)	ath79_pci_swizzle_b(port)
++#define __swizzle_addr_w(port)	ath79_pci_swizzle_w(port)
++#define __swizzle_addr_l(port)	(port)
++#define __swizzle_addr_q(port)	(port)
++
++# define ioswabb(a, x)           (x)
++# define __mem_ioswabb(a, x)     (x)
++# define ioswabw(a, x)           (x)
++# define __mem_ioswabw(a, x)     cpu_to_le16(x)
++# define ioswabl(a, x)           (x)
++# define __mem_ioswabl(a, x)     cpu_to_le32(x)
++# define ioswabq(a, x)           (x)
++# define __mem_ioswabq(a, x)     cpu_to_le64(x)
++
++#endif /* __ASM_MACH_ATH79_MANGLE_PORT_H */
+--- a/arch/mips/pci/pci-ar71xx.c
++++ b/arch/mips/pci/pci-ar71xx.c
+@@ -68,6 +68,45 @@ static const u32 ar71xx_pci_read_mask[8]
+ 	0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0
+ };
+ 
++static unsigned long (*__ath79_pci_swizzle_b)(unsigned long port);
++static unsigned long (*__ath79_pci_swizzle_w)(unsigned long port);
++
++static inline bool ar71xx_is_pci_addr(unsigned long port)
++{
++	unsigned long phys = CPHYSADDR(port);
++
++	return (phys >= AR71XX_PCI_MEM_BASE &&
++		phys < AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE);
++}
++
++static unsigned long ar71xx_pci_swizzle_b(unsigned long port)
++{
++	return ar71xx_is_pci_addr(port) ? port ^ 3 : port;
++}
++
++static unsigned long ar71xx_pci_swizzle_w(unsigned long port)
++{
++	return ar71xx_is_pci_addr(port) ? port ^ 2 : port;
++}
++
++unsigned long ath79_pci_swizzle_b(unsigned long port)
++{
++	if (__ath79_pci_swizzle_b)
++		return __ath79_pci_swizzle_b(port);
++
++	return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_b);
++
++unsigned long ath79_pci_swizzle_w(unsigned long port)
++{
++	if (__ath79_pci_swizzle_w)
++		return __ath79_pci_swizzle_w(port);
++
++	return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_w);
++
+ static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
+ {
+ 	u32 t;
+@@ -275,6 +314,9 @@ static int ar71xx_pci_probe(struct platf
+ 
+ 	register_pci_controller(&apc->pci_ctrl);
+ 
++	__ath79_pci_swizzle_b = ar71xx_pci_swizzle_b;
++	__ath79_pci_swizzle_w = ar71xx_pci_swizzle_w;
++
+ 	return 0;
+ }
+ 
diff --git a/target/linux/ath79/patches-6.1/330-missing-registers.patch b/target/linux/ath79/patches-6.1/330-missing-registers.patch
new file mode 100644
index 0000000000..74789437ec
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/330-missing-registers.patch
@@ -0,0 +1,20 @@
+From: Christian Lamparter <chunkeey at gmail.com>
+Subject: [PATCH] ath79: gmac: add parsers for rxd(v)- and tx(d|en)-delay for
+
+    ath79: gmac: add parsers for rxd(v)- and tx(d|en)-delay for AR9344
+
+    Signed-off-by: Christian Lamparter <chunkeey at gmail.com>
+
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -1231,6 +1231,10 @@
+ #define AR934X_ETH_CFG_RDV_DELAY        BIT(16)
+ #define AR934X_ETH_CFG_RDV_DELAY_MASK   0x3
+ #define AR934X_ETH_CFG_RDV_DELAY_SHIFT  16
++#define AR934X_ETH_CFG_TXD_DELAY_MASK   0x3
++#define AR934X_ETH_CFG_TXD_DELAY_SHIFT  18
++#define AR934X_ETH_CFG_TXE_DELAY_MASK   0x3
++#define AR934X_ETH_CFG_TXE_DELAY_SHIFT  20
+ 
+ /*
+  * QCA953X GMAC Interface
diff --git a/target/linux/ath79/patches-6.1/331-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch b/target/linux/ath79/patches-6.1/331-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
new file mode 100644
index 0000000000..c2f228dfe1
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/331-MIPS-ath79-add-missing-QCA955x-GMAC-registers.patch
@@ -0,0 +1,90 @@
+From 60efe35257b063ce584968f9f80b437030ce6ba6 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail at david-bauer.net>
+Date: Mon, 18 Mar 2019 00:54:06 +0100
+Subject: [PATCH] MIPS: ath79: add missing QCA955x GMAC registers
+
+This adds missing GMAC register definitions for the Qualcomm Atheros
+QCA955X series MIPS SoCs.
+
+They originate from the platforms U-Boot code and the AVM FRITZ!WLAN
+Repeater 450E's GPL tarball.
+
+Signed-off-by: David Bauer <mail at david-bauer.net>
+---
+ .../mips/include/asm/mach-ath79/ar71xx_regs.h | 54 +++++++++++++++++++
+ 1 file changed, 54 insertions(+)
+
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -1251,7 +1251,12 @@
+  */
+ 
+ #define QCA955X_GMAC_REG_ETH_CFG	0x00
++#define QCA955X_GMAC_REG_SGMII_RESET	0x14
+ #define QCA955X_GMAC_REG_SGMII_SERDES	0x18
++#define QCA955X_GMAC_REG_MR_AN_CONTROL	0x1c
++#define QCA955X_GMAC_REG_MR_AN_STATUS	0x20
++#define QCA955X_GMAC_REG_SGMII_CONFIG	0x34
++#define QCA955X_GMAC_REG_SGMII_DEBUG	0x58
+ 
+ #define QCA955X_ETH_CFG_RGMII_EN	BIT(0)
+ #define QCA955X_ETH_CFG_MII_GE0		BIT(1)
+@@ -1273,9 +1278,58 @@
+ #define QCA955X_ETH_CFG_TXE_DELAY_MASK	0x3
+ #define QCA955X_ETH_CFG_TXE_DELAY_SHIFT	20
+ 
++#define QCA955X_SGMII_RESET_RX_CLK_N_RESET	0
++#define QCA955X_SGMII_RESET_RX_CLK_N		BIT(0)
++#define QCA955X_SGMII_RESET_TX_CLK_N		BIT(1)
++#define QCA955X_SGMII_RESET_RX_125M_N		BIT(2)
++#define QCA955X_SGMII_RESET_TX_125M_N		BIT(3)
++#define QCA955X_SGMII_RESET_HW_RX_125M_N	BIT(4)
++
+ #define QCA955X_SGMII_SERDES_LOCK_DETECT_STATUS	BIT(15)
+ #define QCA955X_SGMII_SERDES_RES_CALIBRATION_SHIFT 23
+ #define QCA955X_SGMII_SERDES_RES_CALIBRATION_MASK 0xf
++
++#define QCA955X_MR_AN_CONTROL_SPEED_SEL1	BIT(6)
++#define QCA955X_MR_AN_CONTROL_DUPLEX_MODE	BIT(8)
++#define QCA955X_MR_AN_CONTROL_RESTART_AN	BIT(9)
++#define QCA955X_MR_AN_CONTROL_POWER_DOWN	BIT(11)
++#define QCA955X_MR_AN_CONTROL_AN_ENABLE		BIT(12)
++#define QCA955X_MR_AN_CONTROL_SPEED_SEL0	BIT(13)
++#define QCA955X_MR_AN_CONTROL_LOOPBACK		BIT(14)
++#define QCA955X_MR_AN_CONTROL_PHY_RESET		BIT(15)
++
++#define QCA955X_MR_AN_STATUS_EXT_CAP		BIT(0)
++#define QCA955X_MR_AN_STATUS_LINK_UP		BIT(2)
++#define QCA955X_MR_AN_STATUS_AN_ABILITY		BIT(3)
++#define QCA955X_MR_AN_STATUS_REMOTE_FAULT	BIT(4)
++#define QCA955X_MR_AN_STATUS_AN_COMPLETE	BIT(5)
++#define QCA955X_MR_AN_STATUS_NO_PREAMBLE	BIT(6)
++#define QCA955X_MR_AN_STATUS_BASE_PAGE		BIT(7)
++
++#define QCA955X_SGMII_CONFIG_MODE_CTRL_SHIFT		0
++#define QCA955X_SGMII_CONFIG_MODE_CTRL_MASK		0x7
++#define QCA955X_SGMII_CONFIG_ENABLE_SGMII_TX_PAUSE	BIT(3)
++#define QCA955X_SGMII_CONFIG_MR_REG4_CHANGED		BIT(4)
++#define QCA955X_SGMII_CONFIG_FORCE_SPEED		BIT(5)
++#define QCA955X_SGMII_CONFIG_SPEED_SHIFT		6
++#define QCA955X_SGMII_CONFIG_SPEED_MASK			0xc0
++#define QCA955X_SGMII_CONFIG_REMOTE_PHY_LOOPBACK	BIT(8)
++#define QCA955X_SGMII_CONFIG_NEXT_PAGE_LOADED		BIT(9)
++#define QCA955X_SGMII_CONFIG_MDIO_ENABLE		BIT(10)
++#define QCA955X_SGMII_CONFIG_MDIO_PULSE			BIT(11)
++#define QCA955X_SGMII_CONFIG_MDIO_COMPLETE		BIT(12)
++#define QCA955X_SGMII_CONFIG_PRBS_ENABLE		BIT(13)
++#define QCA955X_SGMII_CONFIG_BERT_ENABLE		BIT(14)
++
++#define QCA955X_SGMII_DEBUG_TX_STATE_MASK	0xff
++#define QCA955X_SGMII_DEBUG_TX_STATE_SHIFT	0
++#define QCA955X_SGMII_DEBUG_RX_STATE_MASK	0xff00
++#define QCA955X_SGMII_DEBUG_RX_STATE_SHIFT	8
++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_MASK	0xff0000
++#define QCA955X_SGMII_DEBUG_RX_SYNC_STATE_SHIFT	16
++#define QCA955X_SGMII_DEBUG_ARB_STATE_MASK	0xf000000
++#define QCA955X_SGMII_DEBUG_ARB_STATE_SHIFT	24
++
+ /*
+  * QCA956X GMAC Interface
+  */
diff --git a/target/linux/ath79/patches-6.1/332-ath79-sgmii-config.patch b/target/linux/ath79/patches-6.1/332-ath79-sgmii-config.patch
new file mode 100644
index 0000000000..a6a50e4a8a
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/332-ath79-sgmii-config.patch
@@ -0,0 +1,30 @@
+From: David Bauer <mail at david-bauer.net>
+Subject: [PATCH] ath79: force SGMII SerDes mode to MAC operation
+
+The mode on the SGMII SerDes on the QCA9563 is 1000 Base-X by default.
+This only allows for 1000 Mbit/s links, however when used with an SGMII
+PHY in 100 Mbit/s link mode, the link remains dead.
+
+This strictly has nothing to do with the SerDes calibration, however it
+is done at the same point in the QCA reference U-Boot which is the
+blueprint for everything happening here. As the current state is more or
+less a hack, this should be fine.
+
+This fixes the issues outlined above on a TP-Link EAP-225 Outdoor.
+
+Reported-by: Tom Herbers <freifunk at tomherbers.de>
+Tested-by: Tom Herbers <freifunk at tomherbers.de>
+Submitted-by: David Bauer <mail at david-bauer.net>
+---
+ arch/mips/include/asm/mach-ath79/ar71xx_regs.h           | 1 +
+ 1 files changed, 1 insertion(+)
+
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -1380,5 +1380,6 @@
+ 
+ #define QCA956X_SGMII_CONFIG_MODE_CTRL_SHIFT	0
+ #define QCA956X_SGMII_CONFIG_MODE_CTRL_MASK	0x7
++#define QCA956X_SGMII_CONFIG_MODE_CTRL_SGMII_MAC	0x2
+ 
+ #endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/target/linux/ath79/patches-6.1/340-register_gpio_driver_earlier.patch b/target/linux/ath79/patches-6.1/340-register_gpio_driver_earlier.patch
new file mode 100644
index 0000000000..48ce7e1d71
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/340-register_gpio_driver_earlier.patch
@@ -0,0 +1,26 @@
+From: John Crispin <john at phrozen.org>
+Subject: ath79: Register GPIO driver earlier
+
+HACK: register the GPIO driver earlier to ensure that gpio_request calls
+from mach files succeed.
+
+Submitted-by: John Crispin <john at phrozen.org>
+---
+ drivers/gpio/gpio-ath79.c                     | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpio-ath79.c
++++ b/drivers/gpio/gpio-ath79.c
+@@ -301,7 +301,11 @@ static struct platform_driver ath79_gpio
+ 	.probe = ath79_gpio_probe,
+ };
+ 
+-module_platform_driver(ath79_gpio_driver);
++static int __init ath79_gpio_init(void)
++{
++	return platform_driver_register(&ath79_gpio_driver);
++}
++postcore_initcall(ath79_gpio_init);
+ 
+ MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X GPIO API support");
+ MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ath79/patches-6.1/350-MIPS-ath79-ath9k-exports.patch b/target/linux/ath79/patches-6.1/350-MIPS-ath79-ath9k-exports.patch
new file mode 100644
index 0000000000..e460fe58f3
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/350-MIPS-ath79-ath9k-exports.patch
@@ -0,0 +1,36 @@
+From: John Crispin <john at phrozen.org>
+Subject: [PATCH] ath79: make ahb wifi work
+
+Submitted-by: John Crispin <john at phrozen.org>
+---
+ arch/mips/ath79/common.c                      | 3 +++
+ mips/include/asm/mach-ath79/ath79.h           | 1+
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -31,11 +31,13 @@ EXPORT_SYMBOL_GPL(ath79_ddr_freq);
+ 
+ enum ath79_soc_type ath79_soc;
+ unsigned int ath79_soc_rev;
++EXPORT_SYMBOL_GPL(ath79_soc_rev);
+ 
+ void __iomem *ath79_pll_base;
+ void __iomem *ath79_reset_base;
+ EXPORT_SYMBOL_GPL(ath79_reset_base);
+-static void __iomem *ath79_ddr_base;
++void __iomem *ath79_ddr_base;
++EXPORT_SYMBOL_GPL(ath79_ddr_base);
+ static void __iomem *ath79_ddr_wb_flush_base;
+ static void __iomem *ath79_ddr_pci_win_base;
+ 
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -149,6 +149,7 @@ void ath79_ddr_wb_flush(unsigned int reg
+ void ath79_ddr_set_pci_windows(void);
+ 
+ extern void __iomem *ath79_pll_base;
++extern void __iomem *ath79_ddr_base;
+ extern void __iomem *ath79_reset_base;
+ 
+ static inline void ath79_pll_wr(unsigned reg, u32 val)
diff --git a/target/linux/ath79/patches-6.1/351-MIPS-ath79-common-exports.patch b/target/linux/ath79/patches-6.1/351-MIPS-ath79-common-exports.patch
new file mode 100644
index 0000000000..befcf2d50f
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/351-MIPS-ath79-common-exports.patch
@@ -0,0 +1,26 @@
+From: Luiz Angelo Daros de Luca <luizluca at gmail.com>
+Subject: [PATCH] ath79: export ath79_pll_base
+
+This symbol is declared as extern but nobody exported it.
+Any module including arch/mips/include/asm/mach-ath79/ath79.h
+will not build. Without this export, ag71xx.ko will not build
+as a module and the build will fail like this:
+
+ERROR: modpost: "ath79_pll_base" [drivers/net/ethernet/atheros/ag71xx/ag71xx.ko] undefined!
+
+The ath79_pll_base symbol is accessed in the ath79_pll_wr() inline function.
+
+---
+ arch/mips/ath79/common.c                      | 1 +
+ 1 file changed, 1 insertions(+)
+
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -34,6 +34,7 @@ unsigned int ath79_soc_rev;
+ EXPORT_SYMBOL_GPL(ath79_soc_rev);
+ 
+ void __iomem *ath79_pll_base;
++EXPORT_SYMBOL_GPL(ath79_pll_base);
+ void __iomem *ath79_reset_base;
+ EXPORT_SYMBOL_GPL(ath79_reset_base);
+ void __iomem *ath79_ddr_base;
diff --git a/target/linux/ath79/patches-6.1/360-MIPS-ath79-export-UART1-reference-clock.patch b/target/linux/ath79/patches-6.1/360-MIPS-ath79-export-UART1-reference-clock.patch
new file mode 100644
index 0000000000..b24ff21692
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/360-MIPS-ath79-export-UART1-reference-clock.patch
@@ -0,0 +1,67 @@
+From: Daniel Golle <daniel at makrotopia.org>
+Subject: [PATCH] ath79: add support for Atheros AR934x HS UART
+
+AR934x chips also got the 'old' qca,ar9330-uart in addition to the
+'new' ns16550a compatible one. Add support for UART1 clock selector as
+well as device-tree bindings in ar934x.dtsi to make use of that uart.
+
+Reported-by: Piotr Dymacz <pepe2k at gmail.com>
+Submitted-by: Daniel Golle <daniel at makrotopia.org>
+---
+ arch/mips/ath79/clock.c                       | 7 +++++++
+ .../mips/include/asm/mach-ath79/ar71xx_regs.h | 1 +
+ include/dt-bindings/clock/ath79-clk.h         | 3 ++-
+ 3 files changed, 10 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/ath79/clock.c
++++ b/arch/mips/ath79/clock.c
+@@ -40,6 +40,7 @@ static const char * const clk_names[ATH7
+ 	[ATH79_CLK_AHB] = "ahb",
+ 	[ATH79_CLK_REF] = "ref",
+ 	[ATH79_CLK_MDIO] = "mdio",
++	[ATH79_CLK_UART1] = "uart1",
+ };
+ 
+ static const char * __init ath79_clk_name(int type)
+@@ -344,6 +345,9 @@ static void __init ar934x_clocks_init(vo
+ 	if (clk_ctrl & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL)
+ 		ath79_set_clk(ATH79_CLK_MDIO, 100 * 1000 * 1000);
+ 
++	if (clk_ctrl & AR934X_PLL_SWITCH_CLOCK_CONTROL_UART1_CLK_SEL)
++		ath79_set_clk(ATH79_CLK_UART1, 100 * 1000 * 1000);
++
+ 	iounmap(dpll_base);
+ }
+ 
+@@ -649,6 +653,9 @@ static void __init ath79_clocks_init_dt(
+ 	if (!clks[ATH79_CLK_MDIO])
+ 		clks[ATH79_CLK_MDIO] = clks[ATH79_CLK_REF];
+ 
++	if (!clks[ATH79_CLK_UART1])
++		clks[ATH79_CLK_UART1] = clks[ATH79_CLK_REF];
++
+ 	if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) {
+ 		pr_err("%pOF: could not register clk provider\n", np);
+ 		goto err_iounmap;
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -348,6 +348,7 @@
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL	BIT(24)
+ 
+ #define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL	BIT(6)
++#define AR934X_PLL_SWITCH_CLOCK_CONTROL_UART1_CLK_SEL	BIT(7)
+ 
+ #define QCA953X_PLL_CPU_CONFIG_REG		0x00
+ #define QCA953X_PLL_DDR_CONFIG_REG		0x04
+--- a/include/dt-bindings/clock/ath79-clk.h
++++ b/include/dt-bindings/clock/ath79-clk.h
+@@ -11,7 +11,8 @@
+ #define ATH79_CLK_AHB		2
+ #define ATH79_CLK_REF		3
+ #define ATH79_CLK_MDIO		4
++#define ATH79_CLK_UART1		5
+ 
+-#define ATH79_CLK_END		5
++#define ATH79_CLK_END		6
+ 
+ #endif /* __DT_BINDINGS_ATH79_CLK_H */
diff --git a/target/linux/ath79/patches-6.1/370-MIPS-ath79-sanitize-symbols.patch b/target/linux/ath79/patches-6.1/370-MIPS-ath79-sanitize-symbols.patch
new file mode 100644
index 0000000000..eac17c2b50
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/370-MIPS-ath79-sanitize-symbols.patch
@@ -0,0 +1,93 @@
+From 3fc8585cf76022dba7496627074d42af88c30718 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Sat, 23 Jun 2018 15:16:55 +0200
+Subject: [PATCH 32/33] MIPS: ath79: sanitize symbols
+
+We no longer need to select which SoCs are supported as the whole arch
+code is always built. So lets drop all the SoC symbols
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ arch/mips/Kconfig       |  2 ++
+ arch/mips/ath79/Kconfig | 44 +++++---------------------------------------
+ arch/mips/pci/Makefile  |  2 +-
+ 3 files changed, 8 insertions(+), 40 deletions(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -257,6 +257,8 @@ config ATH79
+ 	select SYS_SUPPORTS_BIG_ENDIAN
+ 	select SYS_SUPPORTS_MIPS16
+ 	select SYS_SUPPORTS_ZBOOT_UART_PROM
++	select HAVE_PCI
++	select USB_ARCH_HAS_EHCI
+ 	select USE_OF
+ 	select USB_EHCI_ROOT_HUB_TT if USB_EHCI_HCD_PLATFORM
+ 	help
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -1,48 +1,14 @@
+ # SPDX-License-Identifier: GPL-2.0
+ if ATH79
+ 
+-config SOC_AR71XX
+-	select HAVE_PCI
+-	def_bool n
+-
+-config SOC_AR724X
+-	select HAVE_PCI
+-	select PCI_AR724X if PCI
+-	def_bool n
+-
+-config SOC_AR913X
+-	def_bool n
+-
+-config SOC_AR933X
+-	def_bool n
+-
+-config SOC_AR934X
+-	select HAVE_PCI
+-	select PCI_AR724X if PCI
+-	def_bool n
+-
+-config SOC_QCA955X
+-	select HAVE_PCI
+-	select PCI_AR724X if PCI
++config PCI_AR71XX
++	bool "PCI support for AR7100 type SoCs"
++	depends on PCI
+ 	def_bool n
+ 
+ config PCI_AR724X
+-	def_bool n
+-
+-config ATH79_DEV_GPIO_BUTTONS
+-	def_bool n
+-
+-config ATH79_DEV_LEDS_GPIO
+-	def_bool n
+-
+-config ATH79_DEV_SPI
+-	def_bool n
+-
+-config ATH79_DEV_USB
+-	def_bool n
+-
+-config ATH79_DEV_WMAC
+-	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X)
++	bool "PCI support for AR724x type SoCs"
++	depends on PCI
+ 	def_bool n
+ 
+ endif
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -19,7 +19,7 @@ obj-$(CONFIG_BCM63XX)		+= pci-bcm63xx.o
+ 					ops-bcm63xx.o
+ obj-$(CONFIG_MIPS_ALCHEMY)	+= pci-alchemy.o
+ obj-$(CONFIG_PCI_AR2315)	+= pci-ar2315.o
+-obj-$(CONFIG_SOC_AR71XX)	+= pci-ar71xx.o
++obj-$(CONFIG_PCI_AR71XX)	+= pci-ar71xx.o
+ obj-$(CONFIG_PCI_AR724X)	+= pci-ar724x.o
+ obj-$(CONFIG_PCI_XTALK_BRIDGE)	+= pci-xtalk-bridge.o
+ #
diff --git a/target/linux/ath79/patches-6.1/400-mtd-nor-support-mtd-name-from-device-tree.patch b/target/linux/ath79/patches-6.1/400-mtd-nor-support-mtd-name-from-device-tree.patch
new file mode 100644
index 0000000000..ebb240d4ae
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/400-mtd-nor-support-mtd-name-from-device-tree.patch
@@ -0,0 +1,53 @@
+From f32bc2aa01edcba2f2ed5db151cf183eac9ef919 Mon Sep 17 00:00:00 2001
+From: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma at imgtec.com>
+Date: Sat, 25 Feb 2017 16:42:50 +0000
+Subject: mtd: nor: support mtd name from device tree
+
+Signed-off-by: Abhimanyu Vishwakarma <Abhimanyu.Vishwakarma at imgtec.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/spi-nor/core.c
++++ b/drivers/mtd/spi-nor/core.c
+@@ -2964,12 +2964,19 @@ static void spi_nor_set_mtd_info(struct
+ {
+ 	struct mtd_info *mtd = &nor->mtd;
+ 	struct device *dev = nor->dev;
++	struct device_node *np = spi_nor_get_flash_node(nor);
++	const char __maybe_unused *of_mtd_name = NULL;
+ 
+ 	spi_nor_set_mtd_locking_ops(nor);
+ 	spi_nor_set_mtd_otp_ops(nor);
+ 
+ 	mtd->dev.parent = dev;
+-	if (!mtd->name)
++#ifdef CONFIG_MTD_OF_PARTS
++	of_property_read_string(np, "linux,mtd-name", &of_mtd_name);
++#endif
++	if (of_mtd_name)
++		mtd->name = of_mtd_name;
++	else if (!mtd->name)
+ 		mtd->name = dev_name(dev);
+ 	mtd->type = MTD_NORFLASH;
+ 	mtd->flags = MTD_CAP_NORFLASH;
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -863,6 +863,17 @@ out_error:
+  */
+ static void mtd_set_dev_defaults(struct mtd_info *mtd)
+ {
++#ifdef CONFIG_MTD_OF_PARTS
++	const char __maybe_unused *of_mtd_name = NULL;
++	struct device_node *np;
++
++	np = mtd_get_of_node(mtd);
++	if (np && !mtd->name) {
++		of_property_read_string(np, "linux,mtd-name", &of_mtd_name);
++		if (of_mtd_name)
++			mtd->name = of_mtd_name;
++	} else
++#endif
+ 	if (mtd->dev.parent) {
+ 		if (!mtd->owner && mtd->dev.parent->driver)
+ 			mtd->owner = mtd->dev.parent->driver->owner;
diff --git a/target/linux/ath79/patches-6.1/410-mtd-cybertan-trx-parser.patch b/target/linux/ath79/patches-6.1/410-mtd-cybertan-trx-parser.patch
new file mode 100644
index 0000000000..d0e8aec0d5
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/410-mtd-cybertan-trx-parser.patch
@@ -0,0 +1,45 @@
+From: Christian Lamparter <chunkeey at gmail.com>
+Subject: [PATCH] ath79: port cybertan_part from ar71xx
+
+This patch ports the cybertan_part code from ar71xx and converts the
+driver to a DT-supported mtd parser. As a result, it will no longer
+add the u-boot, nvram and art partitions, which were never part of
+the special Cybertan header.
+
+Instead these partitions have to be specified in the DT, which has the
+upside of making it possible to add properties (i.e.: read-only), labels
+and references to these important partitions.
+
+Submitted-by: Christian Lamparter <chunkeey at gmail.com>
+---
+ drivers/mtd/parsers/Makefile                  | 1 +
+ drivers/mtd/parsers/Kconfig                   | 8 ++++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/mtd/parsers/Makefile
++++ b/drivers/mtd/parsers/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_MTD_OF_PARTS)		+= ofpart.o
+ ofpart-y				+= ofpart_core.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o
+ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
++obj-$(CONFIG_MTD_PARSER_CYBERTAN)	+= parser_cybertan.o
+ obj-$(CONFIG_MTD_PARSER_IMAGETAG)	+= parser_imagetag.o
+ obj-$(CONFIG_MTD_AFS_PARTS)		+= afs.o
+ obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER)	+= tplink_safeloader.o
+--- a/drivers/mtd/parsers/Kconfig
++++ b/drivers/mtd/parsers/Kconfig
+@@ -112,6 +112,14 @@ config MTD_OF_PARTS_LINKSYS_NS
+ 	  two "firmware" partitions. Currently used firmware has to be detected
+ 	  using CFE environment variable.
+ 
++config MTD_PARSER_CYBERTAN
++	tristate "Parser for Cybertan format partitions"
++	depends on MTD && (ATH79 || COMPILE_TEST)
++	help
++	  Cybertan has a proprietory header than encompasses a Broadcom trx
++	  header. This driver will parse the header and take care of the
++	  special offsets that result in the extra headers.
++
+ config MTD_PARSER_IMAGETAG
+ 	tristate "Parser for BCM963XX Image Tag format partitions"
+ 	depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
diff --git a/target/linux/ath79/patches-6.1/420-drivers-link-spi-before-mtd.patch b/target/linux/ath79/patches-6.1/420-drivers-link-spi-before-mtd.patch
new file mode 100644
index 0000000000..0cd96909eb
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/420-drivers-link-spi-before-mtd.patch
@@ -0,0 +1,20 @@
+From: Gabor Juhos <juhosg at openwrt.org>
+Subject: [PATCH] ar71xx: Link SPI before MTD
+
+SVN-Revision: 22863
+---
+ drivers/Makefile                              |   2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -80,8 +80,8 @@ obj-y				+= scsi/
+ obj-y				+= nvme/
+ obj-$(CONFIG_ATA)		+= ata/
+ obj-$(CONFIG_TARGET_CORE)	+= target/
+-obj-$(CONFIG_MTD)		+= mtd/
+ obj-$(CONFIG_SPI)		+= spi/
++obj-$(CONFIG_MTD)		+= mtd/
+ obj-$(CONFIG_SPMI)		+= spmi/
+ obj-$(CONFIG_HSI)		+= hsi/
+ obj-$(CONFIG_SLIMBUS)		+= slimbus/
diff --git a/target/linux/ath79/patches-6.1/430-mtd-ar934x-nand-driver.patch b/target/linux/ath79/patches-6.1/430-mtd-ar934x-nand-driver.patch
new file mode 100644
index 0000000000..184c39d469
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/430-mtd-ar934x-nand-driver.patch
@@ -0,0 +1,34 @@
+From: Gabor Juhos <juhosg at openwrt.org>
+Subject: ar71xx: ar934x_nfc: experimental NAND Flash Controller driver for AR934x
+
+SVN-Revision: 33385
+---
+ drivers/mtd/nand/raw/Kconfig                  | 8 ++++++++
+ drivers/mtd/nand/raw/Makefile                 | 1 +
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -557,4 +557,12 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
+ 	  load time (assuming you build diskonchip as a module) with the module
+ 	  parameter "inftl_bbt_write=1".
+ 
++config MTD_NAND_AR934X
++	tristate "Support for NAND controller on Qualcomm Atheros AR934x/QCA955x SoCs"
++	depends on ATH79 || COMPILE_TEST
++	depends on HAS_IOMEM
++	help
++	  Enables support for NAND controller on Qualcomm Atheros SoCs.
++	  This controller is found on AR934x and QCA955x SoCs.
++
+ endif # MTD_RAW_NAND
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -59,6 +59,7 @@ obj-$(CONFIG_MTD_NAND_INTEL_LGM)	+= inte
+ obj-$(CONFIG_MTD_NAND_ROCKCHIP)		+= rockchip-nand-controller.o
+ obj-$(CONFIG_MTD_NAND_PL35X)		+= pl35x-nand-controller.o
+ obj-$(CONFIG_MTD_NAND_RENESAS)		+= renesas-nand-controller.o
++obj-$(CONFIG_MTD_NAND_AR934X)		+= ar934x_nand.o
+ 
+ nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+ nand-objs += nand_onfi.o
diff --git a/target/linux/ath79/patches-6.1/700-phy-add-ath79-usb-phys.patch b/target/linux/ath79/patches-6.1/700-phy-add-ath79-usb-phys.patch
new file mode 100644
index 0000000000..21b655a109
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/700-phy-add-ath79-usb-phys.patch
@@ -0,0 +1,333 @@
+From 08c9d6ceef01893678a5d2e8a15517c745417f21 Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Tue, 6 Mar 2018 10:04:05 +0100
+Subject: [PATCH 04/27] phy: add ath79 usb phys
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/phy/Kconfig          |  16 ++++++
+ drivers/phy/Makefile         |   2 +
+ drivers/phy/phy-ar7100-usb.c | 124 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/phy/phy-ar7200-usb.c | 108 +++++++++++++++++++++++++++++++++++++
+ 4 files changed, 250 insertions(+)
+ create mode 100644 drivers/phy/phy-ar7100-usb.c
+ create mode 100644 drivers/phy/phy-ar7200-usb.c
+
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -24,6 +24,22 @@ config GENERIC_PHY_MIPI_DPHY
+ 	  Provides a number of helpers a core functions for MIPI D-PHY
+ 	  drivers to us.
+ 
++config PHY_AR7100_USB
++	tristate "Atheros AR7100 USB PHY driver"
++	depends on ATH79 || COMPILE_TEST
++	default y if USB_EHCI_HCD_PLATFORM
++	select GENERIC_PHY
++	help
++	  Enable this to support the USB PHY on Atheros AR7100 SoCs.
++
++config PHY_AR7200_USB
++	tristate "Atheros AR7200 USB PHY driver"
++	depends on ATH79 || COMPILE_TEST
++	default y if USB_EHCI_HCD_PLATFORM
++	select GENERIC_PHY
++	help
++	  Enable this to support the USB PHY on Atheros AR7200 SoCs.
++
+ config PHY_LPC18XX_USB_OTG
+ 	tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
+ 	depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -4,6 +4,8 @@
+ #
+ 
+ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
++obj-$(CONFIG_PHY_AR7100_USB)		+= phy-ar7100-usb.o
++obj-$(CONFIG_PHY_AR7200_USB)		+= phy-ar7200-usb.o
+ obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY)	+= phy-core-mipi-dphy.o
+ obj-$(CONFIG_PHY_CAN_TRANSCEIVER)	+= phy-can-transceiver.o
+ obj-$(CONFIG_PHY_LPC18XX_USB_OTG)	+= phy-lpc18xx-usb-otg.o
+--- /dev/null
++++ b/drivers/phy/phy-ar7100-usb.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright (C) 2018 John Crispin <john at phrozen.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/phy/phy.h>
++#include <linux/delay.h>
++#include <linux/reset.h>
++#include <linux/of_gpio.h>
++
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++
++struct ar7100_usb_phy {
++	struct reset_control	*rst_phy;
++	struct reset_control	*rst_host;
++	struct reset_control	*rst_ohci_dll;
++	void __iomem		*io_base;
++	struct phy		*phy;
++	int			gpio;
++};
++
++static int ar7100_usb_phy_power_off(struct phy *phy)
++{
++	struct ar7100_usb_phy *priv = phy_get_drvdata(phy);
++	int err = 0;
++
++	err |= reset_control_assert(priv->rst_host);
++	err |= reset_control_assert(priv->rst_phy);
++	err |= reset_control_assert(priv->rst_ohci_dll);
++
++	return err;
++}
++
++static int ar7100_usb_phy_power_on(struct phy *phy)
++{
++	struct ar7100_usb_phy *priv = phy_get_drvdata(phy);
++	int err = 0;
++
++	err |= ar7100_usb_phy_power_off(phy);
++	mdelay(100);
++	err |= reset_control_deassert(priv->rst_ohci_dll);
++	err |= reset_control_deassert(priv->rst_phy);
++	err |= reset_control_deassert(priv->rst_host);
++	mdelay(500);
++	iowrite32(0xf0000, priv->io_base + AR71XX_USB_CTRL_REG_CONFIG);
++	iowrite32(0x20c00, priv->io_base + AR71XX_USB_CTRL_REG_FLADJ);
++
++	return err;
++}
++
++static const struct phy_ops ar7100_usb_phy_ops = {
++	.power_on	= ar7100_usb_phy_power_on,
++	.power_off	= ar7100_usb_phy_power_off,
++	.owner		= THIS_MODULE,
++};
++
++static int ar7100_usb_phy_probe(struct platform_device *pdev)
++{
++	struct phy_provider *phy_provider;
++	struct resource *res;
++	struct ar7100_usb_phy *priv;
++
++	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	priv->io_base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(priv->io_base))
++		return PTR_ERR(priv->io_base);
++
++	priv->rst_phy = devm_reset_control_get(&pdev->dev, "usb-phy");
++	if (IS_ERR(priv->rst_phy)) {
++		dev_err(&pdev->dev, "phy reset is missing\n");
++		return PTR_ERR(priv->rst_phy);
++	}
++
++	priv->rst_host = devm_reset_control_get(&pdev->dev, "usb-host");
++	if (IS_ERR(priv->rst_host)) {
++		dev_err(&pdev->dev, "host reset is missing\n");
++		return PTR_ERR(priv->rst_host);
++	}
++
++	priv->rst_ohci_dll = devm_reset_control_get(&pdev->dev, "usb-ohci-dll");
++	if (IS_ERR(priv->rst_ohci_dll)) {
++		dev_err(&pdev->dev, "ohci-dll reset is missing\n");
++		return PTR_ERR(priv->rst_host);
++	}
++
++	priv->phy = devm_phy_create(&pdev->dev, NULL, &ar7100_usb_phy_ops);
++	if (IS_ERR(priv->phy)) {
++		dev_err(&pdev->dev, "failed to create PHY\n");
++		return PTR_ERR(priv->phy);
++	}
++
++	priv->gpio = of_get_gpio(pdev->dev.of_node, 0);
++	if (priv->gpio >= 0) {
++		int ret = devm_gpio_request(&pdev->dev, priv->gpio, dev_name(&pdev->dev));
++
++		if (ret) {
++			dev_err(&pdev->dev, "failed to request gpio\n");
++			return ret;
++		}
++		gpio_export_with_name(priv->gpio, 0, dev_name(&pdev->dev));
++		gpio_set_value(priv->gpio, 1);
++	}
++
++	phy_set_drvdata(priv->phy, priv);
++
++	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
++
++
++	return PTR_ERR_OR_ZERO(phy_provider);
++}
++
++static const struct of_device_id ar7100_usb_phy_of_match[] = {
++	{ .compatible = "qca,ar7100-usb-phy" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, ar7100_usb_phy_of_match);
++
++static struct platform_driver ar7100_usb_phy_driver = {
++	.probe	= ar7100_usb_phy_probe,
++	.driver = {
++		.of_match_table	= ar7100_usb_phy_of_match,
++		.name		= "ar7100-usb-phy",
++	}
++};
++module_platform_driver(ar7100_usb_phy_driver);
++
++MODULE_DESCRIPTION("ATH79 USB PHY driver");
++MODULE_AUTHOR("Alban Bedel <albeu at free.fr>");
++MODULE_LICENSE("GPL");
+--- /dev/null
++++ b/drivers/phy/phy-ar7200-usb.c
+@@ -0,0 +1,136 @@
++/*
++ * Copyright (C) 2015 Alban Bedel <albeu at free.fr>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/phy/phy.h>
++#include <linux/reset.h>
++#include <linux/of_gpio.h>
++
++struct ar7200_usb_phy {
++	struct reset_control	*rst_phy;
++	struct reset_control	*rst_phy_analog;
++	struct reset_control	*suspend_override;
++	struct phy		*phy;
++	int			gpio;
++};
++
++static int ar7200_usb_phy_power_on(struct phy *phy)
++{
++	struct ar7200_usb_phy *priv = phy_get_drvdata(phy);
++	int err = 0;
++
++	if (priv->suspend_override)
++		err = reset_control_assert(priv->suspend_override);
++	if (priv->rst_phy)
++		err |= reset_control_deassert(priv->rst_phy);
++	if (priv->rst_phy_analog)
++		err |= reset_control_deassert(priv->rst_phy_analog);
++
++	return err;
++}
++
++static int ar7200_usb_phy_power_off(struct phy *phy)
++{
++	struct ar7200_usb_phy *priv = phy_get_drvdata(phy);
++	int err = 0;
++
++	if (priv->suspend_override)
++		err = reset_control_deassert(priv->suspend_override);
++	if (priv->rst_phy)
++		err |= reset_control_assert(priv->rst_phy);
++	if (priv->rst_phy_analog)
++		err |= reset_control_assert(priv->rst_phy_analog);
++
++	return err;
++}
++
++static const struct phy_ops ar7200_usb_phy_ops = {
++	.power_on	= ar7200_usb_phy_power_on,
++	.power_off	= ar7200_usb_phy_power_off,
++	.owner		= THIS_MODULE,
++};
++
++static int ar7200_usb_phy_probe(struct platform_device *pdev)
++{
++	struct phy_provider *phy_provider;
++	struct ar7200_usb_phy *priv;
++
++	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	priv->rst_phy = devm_reset_control_get(&pdev->dev, "usb-phy");
++	if (IS_ERR(priv->rst_phy)) {
++		if (PTR_ERR(priv->rst_phy) != -EPROBE_DEFER)
++			dev_err(&pdev->dev, "phy reset is missing\n");
++		return PTR_ERR(priv->rst_phy);
++	}
++
++	priv->rst_phy_analog = devm_reset_control_get_optional(
++		&pdev->dev, "usb-phy-analog");
++	if (IS_ERR(priv->rst_phy_analog)) {
++		if (PTR_ERR(priv->rst_phy_analog) == -ENOENT)
++			priv->rst_phy_analog = NULL;
++		else
++			return PTR_ERR(priv->rst_phy_analog);
++	}
++
++	priv->suspend_override = devm_reset_control_get_optional(
++		&pdev->dev, "usb-suspend-override");
++	if (IS_ERR(priv->suspend_override)) {
++		if (PTR_ERR(priv->suspend_override) == -ENOENT)
++			priv->suspend_override = NULL;
++		else
++			return PTR_ERR(priv->suspend_override);
++	}
++
++	priv->phy = devm_phy_create(&pdev->dev, NULL, &ar7200_usb_phy_ops);
++	if (IS_ERR(priv->phy)) {
++		dev_err(&pdev->dev, "failed to create PHY\n");
++		return PTR_ERR(priv->phy);
++	}
++
++	priv->gpio = of_get_gpio(pdev->dev.of_node, 0);
++	if (priv->gpio >= 0) {
++		int ret = devm_gpio_request(&pdev->dev, priv->gpio, dev_name(&pdev->dev));
++
++		if (ret) {
++			dev_err(&pdev->dev, "failed to request gpio\n");
++			return ret;
++		}
++		gpio_export_with_name(priv->gpio, 0, dev_name(&pdev->dev));
++		gpio_set_value(priv->gpio, 1);
++	}
++
++	phy_set_drvdata(priv->phy, priv);
++
++	phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
++
++	return PTR_ERR_OR_ZERO(phy_provider);
++}
++
++static const struct of_device_id ar7200_usb_phy_of_match[] = {
++	{ .compatible = "qca,ar7200-usb-phy" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, ar7200_usb_phy_of_match);
++
++static struct platform_driver ar7200_usb_phy_driver = {
++	.probe	= ar7200_usb_phy_probe,
++	.driver = {
++		.of_match_table	= ar7200_usb_phy_of_match,
++		.name		= "ar7200-usb-phy",
++	}
++};
++module_platform_driver(ar7200_usb_phy_driver);
++
++MODULE_DESCRIPTION("ATH79 USB PHY driver");
++MODULE_AUTHOR("Alban Bedel <albeu at free.fr>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/ath79/patches-6.1/701-usb-add-more-OF-quirk-properties.patch b/target/linux/ath79/patches-6.1/701-usb-add-more-OF-quirk-properties.patch
new file mode 100644
index 0000000000..293a359884
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/701-usb-add-more-OF-quirk-properties.patch
@@ -0,0 +1,24 @@
+From 2201818e5bd33f389beceb3943fdfcf5a698fc5b Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Tue, 6 Mar 2018 10:01:43 +0100
+Subject: [PATCH 05/27] usb: add more OF/quirk properties
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/usb/host/ehci-platform.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -274,6 +274,11 @@ static int ehci_platform_probe(struct pl
+ 	ehci = hcd_to_ehci(hcd);
+ 
+ 	if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
++		of_property_read_u32(dev->dev.of_node, "caps-offset", &pdata->caps_offset);
++
++		if (of_property_read_bool(dev->dev.of_node, "has-synopsys-hc-bug"))
++			pdata->has_synopsys_hc_bug = 1;
++
+ 		if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
+ 			ehci->big_endian_mmio = 1;
+ 
diff --git a/target/linux/ath79/patches-6.1/710-net-use-downstream-ag71xx.patch b/target/linux/ath79/patches-6.1/710-net-use-downstream-ag71xx.patch
new file mode 100644
index 0000000000..54e64fb11c
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/710-net-use-downstream-ag71xx.patch
@@ -0,0 +1,42 @@
+From: John Crispin <john at phrozen.org>
+Subject: [PATCH] ath79: add new OF only target for QCA MIPS silicon
+
+This target aims to replace ar71xx mid-term. The big part that is still
+missing is making the MMIO/AHB wifi work using OF. NAND and mikrotik
+subtargets will follow.
+
+Submitted-by: John Crispin <john at phrozen.org>
+---
+ drivers/net/ethernet/atheros/Kconfig          | 8 +-------
+ drivers/net/ethernet/atheros/Makefile         | 2 +-
+ 2 files changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/atheros/Kconfig
++++ b/drivers/net/ethernet/atheros/Kconfig
+@@ -17,14 +17,7 @@ config NET_VENDOR_ATHEROS
+ 
+ if NET_VENDOR_ATHEROS
+ 
+-config AG71XX
+-	tristate "Atheros AR7XXX/AR9XXX built-in ethernet mac support"
+-	depends on ATH79
+-	select PHYLINK
+-	imply NET_SELFTESTS
+-	help
+-	  If you wish to compile a kernel for AR7XXX/91XXX and enable
+-	  ethernet support, then you should always answer Y to this.
++source "drivers/net/ethernet/atheros/ag71xx/Kconfig"
+ 
+ config ATL2
+ 	tristate "Atheros L2 Fast Ethernet support"
+--- a/drivers/net/ethernet/atheros/Makefile
++++ b/drivers/net/ethernet/atheros/Makefile
+@@ -3,7 +3,7 @@
+ # Makefile for the Atheros network device drivers.
+ #
+ 
+-obj-$(CONFIG_AG71XX) += ag71xx.o
++obj-$(CONFIG_AG71XX) += ag71xx/
+ obj-$(CONFIG_ATL1) += atlx/
+ obj-$(CONFIG_ATL2) += atlx/
+ obj-$(CONFIG_ATL1E) += atl1e/
diff --git a/target/linux/ath79/patches-6.1/720-mdio_bitbang_ignore_ta_value.patch b/target/linux/ath79/patches-6.1/720-mdio_bitbang_ignore_ta_value.patch
new file mode 100644
index 0000000000..5363bb37b0
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/720-mdio_bitbang_ignore_ta_value.patch
@@ -0,0 +1,44 @@
+From: Jonas Gorski <jogo at openwrt.org>
+Subject: ar71xx: add a workaround for ar8316 not always driving the TA bit to low
+
+AR8316 behind a GPIO bitbanged MDIO bus fails to drive the turnaround bit
+to low despite returning a valid value. Ignore it and just use the
+returned value anyway.
+
+SVN-Revision: 28422
+---
+ drivers/net/mdio/mdio-bitbang.c               | 16 ++-----------------
+ 1 file changed, 2 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/mdio/mdio-bitbang.c
++++ b/drivers/net/mdio/mdio-bitbang.c
+@@ -152,7 +152,7 @@ static int mdiobb_cmd_addr(struct mdiobb
+ int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+ {
+ 	struct mdiobb_ctrl *ctrl = bus->priv;
+-	int ret, i;
++	int ret;
+ 
+ 	if (reg & MII_ADDR_C45) {
+ 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+@@ -162,19 +162,7 @@ int mdiobb_read(struct mii_bus *bus, int
+ 
+ 	ctrl->ops->set_mdio_dir(ctrl, 0);
+ 
+-	/* check the turnaround bit: the PHY should be driving it to zero, if this
+-	 * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that
+-	 */
+-	if (mdiobb_get_bit(ctrl) != 0 &&
+-	    !(bus->phy_ignore_ta_mask & (1 << phy))) {
+-		/* PHY didn't drive TA low -- flush any bits it
+-		 * may be trying to send.
+-		 */
+-		for (i = 0; i < 32; i++)
+-			mdiobb_get_bit(ctrl);
+-
+-		return 0xffff;
+-	}
++	mdiobb_get_bit(ctrl);
+ 
+ 	ret = mdiobb_get_num(ctrl, 16);
+ 	mdiobb_get_bit(ctrl);
diff --git a/target/linux/ath79/patches-6.1/721-phy-mdio-bitbang-prevent-rescheduling-during-command.patch b/target/linux/ath79/patches-6.1/721-phy-mdio-bitbang-prevent-rescheduling-during-command.patch
new file mode 100644
index 0000000000..e37d9a1f63
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/721-phy-mdio-bitbang-prevent-rescheduling-during-command.patch
@@ -0,0 +1,61 @@
+From 66e584435ac0de6e0abeb6d7166fe4fe25d6bb73 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Tue, 16 Jun 2015 13:15:08 +0200
+Subject: [PATCH] phy/mdio-bitbang: prevent rescheduling during command
+
+It seems some phys have some maximum timings for accessing the MDIO line,
+resulting in bit errors under cpu stress. Prevent this from happening by
+disabling interrupts when sending commands.
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+---
+ drivers/net/mdio/mdio-bitbang.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/mdio/mdio-bitbang.c
++++ b/drivers/net/mdio/mdio-bitbang.c
+@@ -14,6 +14,7 @@
+  * Vitaly Bordug <vbordug at ru.mvista.com>
+  */
+ 
++#include <linux/irqflags.h>
+ #include <linux/delay.h>
+ #include <linux/mdio-bitbang.h>
+ #include <linux/module.h>
+@@ -153,7 +154,9 @@ int mdiobb_read(struct mii_bus *bus, int
+ {
+ 	struct mdiobb_ctrl *ctrl = bus->priv;
+ 	int ret;
++	unsigned long flags;
+ 
++	local_irq_save(flags);
+ 	if (reg & MII_ADDR_C45) {
+ 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+ 		mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+@@ -166,6 +169,7 @@ int mdiobb_read(struct mii_bus *bus, int
+ 
+ 	ret = mdiobb_get_num(ctrl, 16);
+ 	mdiobb_get_bit(ctrl);
++	local_irq_restore(flags);
+ 	return ret;
+ }
+ EXPORT_SYMBOL(mdiobb_read);
+@@ -173,7 +177,9 @@ EXPORT_SYMBOL(mdiobb_read);
+ int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+ {
+ 	struct mdiobb_ctrl *ctrl = bus->priv;
++	unsigned long flags;
+ 
++	local_irq_save(flags);
+ 	if (reg & MII_ADDR_C45) {
+ 		reg = mdiobb_cmd_addr(ctrl, phy, reg);
+ 		mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+@@ -188,6 +194,8 @@ int mdiobb_write(struct mii_bus *bus, in
+ 
+ 	ctrl->ops->set_mdio_dir(ctrl, 0);
+ 	mdiobb_get_bit(ctrl);
++	local_irq_restore(flags);
++
+ 	return 0;
+ }
+ EXPORT_SYMBOL(mdiobb_write);
diff --git a/target/linux/ath79/patches-6.1/730-ar8216-make-reg-access-atomic.patch b/target/linux/ath79/patches-6.1/730-ar8216-make-reg-access-atomic.patch
new file mode 100644
index 0000000000..02f763534e
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/730-ar8216-make-reg-access-atomic.patch
@@ -0,0 +1,59 @@
+From b3797d1a92afe97c173b00fdb7824cedba24eef0 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213 at gmail.com>
+Date: Sun, 20 Sep 2020 01:00:45 +0800
+Subject: [PATCH] ath79: ar8216: make switch register access atomic
+
+due to some unknown reason these register accesses sometimes fail
+on the integrated switch without this patch.
+
+THIS ONLY WORKS ON ATH79 AND MAY BREAK THE DRIVER ON OTHER PLATFORMS!
+The mdio bus on ath79 works in polling mode and doesn't rely on
+any interrupt. This patch breaks the driver on any mdio master
+with interrupts used.
+
+---
+--- a/drivers/net/phy/ar8216.c
++++ b/drivers/net/phy/ar8216.c
+@@ -252,6 +252,7 @@ ar8xxx_mii_write32(struct ar8xxx_priv *p
+ u32
+ ar8xxx_read(struct ar8xxx_priv *priv, int reg)
+ {
++	unsigned long flags;
+ 	struct mii_bus *bus = priv->mii_bus;
+ 	u16 r1, r2, page;
+ 	u32 val;
+@@ -259,11 +260,13 @@ ar8xxx_read(struct ar8xxx_priv *priv, in
+ 	split_addr((u32) reg, &r1, &r2, &page);
+ 
+ 	mutex_lock(&bus->mdio_lock);
++	local_irq_save(flags);
+ 
+ 	bus->write(bus, 0x18, 0, page);
+ 	wait_for_page_switch();
+ 	val = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
+ 
++	local_irq_restore(flags);
+ 	mutex_unlock(&bus->mdio_lock);
+ 
+ 	return val;
+@@ -272,17 +275,20 @@ ar8xxx_read(struct ar8xxx_priv *priv, in
+ void
+ ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val)
+ {
++	unsigned long flags;
+ 	struct mii_bus *bus = priv->mii_bus;
+ 	u16 r1, r2, page;
+ 
+ 	split_addr((u32) reg, &r1, &r2, &page);
+ 
+ 	mutex_lock(&bus->mdio_lock);
++	local_irq_save(flags);
+ 
+ 	bus->write(bus, 0x18, 0, page);
+ 	wait_for_page_switch();
+ 	ar8xxx_mii_write32(priv, 0x10 | r2, r1, val);
+ 
++	local_irq_restore(flags);
+ 	mutex_unlock(&bus->mdio_lock);
+ }
+ 
diff --git a/target/linux/ath79/patches-6.1/800-leds-add-reset-controller-based-driver.patch b/target/linux/ath79/patches-6.1/800-leds-add-reset-controller-based-driver.patch
new file mode 100644
index 0000000000..0002b9b95b
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/800-leds-add-reset-controller-based-driver.patch
@@ -0,0 +1,186 @@
+From ecbd9c87f073f097d9fe56390353e64e963e866a Mon Sep 17 00:00:00 2001
+From: John Crispin <john at phrozen.org>
+Date: Tue, 6 Mar 2018 10:03:03 +0100
+Subject: [PATCH 03/27] leds: add reset-controller based driver
+
+Signed-off-by: John Crispin <john at phrozen.org>
+---
+ drivers/leds/Kconfig      |  11 ++++
+ drivers/leds/Makefile     |   1 +
+ drivers/leds/leds-reset.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 149 insertions(+)
+ create mode 100644 drivers/leds/leds-reset.c
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -874,6 +874,17 @@ source "drivers/leds/flash/Kconfig"
+ comment "RGB LED drivers"
+ source "drivers/leds/rgb/Kconfig"
+ 
++config LEDS_RESET
++	tristate "LED support for reset-controller API"
++	depends on LEDS_CLASS
++	depends on RESET_CONTROLLER
++	help
++	  This option enables support for LEDs connected to pins driven by reset
++	  controllers. Yes, DNI actual built HW like that.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called leds-reset.
++
+ comment "LED Triggers"
+ source "drivers/leds/trigger/Kconfig"
+ 
+--- /dev/null
++++ b/drivers/leds/leds-reset.c
+@@ -0,0 +1,140 @@
++/*
++ * Copyright (C) 2018 John Crispin <john at phrozen.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.
++ *
++ */
++#include <linux/err.h>
++#include <linux/reset.h>
++#include <linux/kernel.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++
++struct reset_led_data {
++	struct led_classdev cdev;
++	struct reset_control *rst;
++};
++
++static inline struct reset_led_data *
++			cdev_to_reset_led_data(struct led_classdev *led_cdev)
++{
++	return container_of(led_cdev, struct reset_led_data, cdev);
++}
++
++static void reset_led_set(struct led_classdev *led_cdev,
++	enum led_brightness value)
++{
++	struct reset_led_data *led_dat = cdev_to_reset_led_data(led_cdev);
++
++	if (value == LED_OFF)
++		reset_control_assert(led_dat->rst);
++	else
++		reset_control_deassert(led_dat->rst);
++}
++
++struct reset_leds_priv {
++	int num_leds;
++	struct reset_led_data leds[];
++};
++
++static inline int sizeof_reset_leds_priv(int num_leds)
++{
++	return sizeof(struct reset_leds_priv) +
++		(sizeof(struct reset_led_data) * num_leds);
++}
++
++static struct reset_leds_priv *reset_leds_create(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	struct fwnode_handle *child;
++	struct reset_leds_priv *priv;
++	int count, ret;
++
++	count = device_get_child_node_count(dev);
++	if (!count)
++		return ERR_PTR(-ENODEV);
++
++	priv = devm_kzalloc(dev, sizeof_reset_leds_priv(count), GFP_KERNEL);
++	if (!priv)
++		return ERR_PTR(-ENOMEM);
++
++	device_for_each_child_node(dev, child) {
++		struct reset_led_data *led = &priv->leds[priv->num_leds];
++		struct device_node *np = to_of_node(child);
++
++		ret = fwnode_property_read_string(child, "label", &led->cdev.name);
++		if (!led->cdev.name) {
++			fwnode_handle_put(child);
++			return ERR_PTR(-EINVAL);
++		}
++		led->rst = __of_reset_control_get(np, NULL, 0, 0, 0, true);
++		if (IS_ERR(led->rst))
++			return ERR_PTR(-EINVAL);
++
++		fwnode_property_read_string(child, "linux,default-trigger",
++						&led->cdev.default_trigger);
++
++		led->cdev.brightness_set = reset_led_set;
++		ret = devm_led_classdev_register(&pdev->dev, &led->cdev);
++		if (ret < 0)
++			return ERR_PTR(ret);
++		led->cdev.dev->of_node = np;
++		priv->num_leds++;
++	}
++
++	return priv;
++}
++
++static const struct of_device_id of_reset_leds_match[] = {
++	{ .compatible = "reset-leds", },
++	{},
++};
++
++MODULE_DEVICE_TABLE(of, of_reset_leds_match);
++
++static int reset_led_probe(struct platform_device *pdev)
++{
++	struct reset_leds_priv *priv;
++
++	priv = reset_leds_create(pdev);
++	if (IS_ERR(priv))
++		return PTR_ERR(priv);
++
++	platform_set_drvdata(pdev, priv);
++
++	return 0;
++}
++
++static void reset_led_shutdown(struct platform_device *pdev)
++{
++	struct reset_leds_priv *priv = platform_get_drvdata(pdev);
++	int i;
++
++	for (i = 0; i < priv->num_leds; i++) {
++		struct reset_led_data *led = &priv->leds[i];
++
++		if (!(led->cdev.flags & LED_RETAIN_AT_SHUTDOWN))
++			reset_led_set(&led->cdev, LED_OFF);
++	}
++}
++
++static struct platform_driver reset_led_driver = {
++	.probe		= reset_led_probe,
++	.shutdown	= reset_led_shutdown,
++	.driver		= {
++		.name	= "leds-reset",
++		.of_match_table = of_reset_leds_match,
++	},
++};
++
++module_platform_driver(reset_led_driver);
++
++MODULE_AUTHOR("John Crispin <john at phrozen.org>");
++MODULE_DESCRIPTION("reset controller LED driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:leds-reset");
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TURRIS_OMNIA)		+= leds
+ obj-$(CONFIG_LEDS_WM831X_STATUS)	+= leds-wm831x-status.o
+ obj-$(CONFIG_LEDS_WM8350)		+= leds-wm8350.o
+ obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
++obj-$(CONFIG_LEDS_RESET)		+= leds-reset.o
+ 
+ # LED SPI Drivers
+ obj-$(CONFIG_LEDS_CR0014114)		+= leds-cr0014114.o
diff --git a/target/linux/ath79/patches-6.1/810-ath79-ignore-the-abused-interrupt-map-on-pcie-node.patch b/target/linux/ath79/patches-6.1/810-ath79-ignore-the-abused-interrupt-map-on-pcie-node.patch
new file mode 100644
index 0000000000..980c265fe6
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/810-ath79-ignore-the-abused-interrupt-map-on-pcie-node.patch
@@ -0,0 +1,33 @@
+From: Shiji Yang <yangshiji66 at outlook.com>
+Date: Wed, 31 May 2023 00:15:23 +0000
+Subject: [PATCH] ath79: ignore the abused interrupt-map on pcie node
+
+ath79 PCIe interrupt controller has stopped working correctly. This
+is because the DT exposing a non-sensical interrupt-map property,
+and their drivers relying on the kernel ignoring this property[1].
+
+This patch fix the pcie init error:
+ath9k 0000:00:00.0: of_irq_parse_pci: failed with rc=-14
+
+Notice:
+This is just a workaround, not a fix. PCIe driver and related dts
+node need to be rewritten.
+
+[1] https://lore.kernel.org/all/20211201114102.13446-1-maz@kernel.org/
+
+Signed-off-by: Shiji Yang <yangshiji66 at outlook.com>
+---
+ drivers/of/irq.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/of/irq.c
++++ b/drivers/of/irq.c
+@@ -86,6 +86,8 @@ EXPORT_SYMBOL_GPL(of_irq_find_parent);
+  * drawing board.
+  */
+ static const char * const of_irq_imap_abusers[] = {
++	"qca,ar7100-pci",
++	"qcom,ar7240-pci",
+ 	"CBEA,platform-spider-pic",
+ 	"sti,platform-spider-pic",
+ 	"realtek,rtl-intc",
diff --git a/target/linux/ath79/patches-6.1/900-unaligned_access_hacks.patch b/target/linux/ath79/patches-6.1/900-unaligned_access_hacks.patch
new file mode 100644
index 0000000000..6c97bc307c
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/900-unaligned_access_hacks.patch
@@ -0,0 +1,909 @@
+From: Felix Fietkau <nbd at openwrt.org>
+Subject: [PATCH] ar71xx: fix unaligned access in a few more places
+
+SVN-Revision: 35130
+---
+ arch/mips/include/asm/checksum.h              | 83 +++---------------
+ include/uapi/linux/ip.h                       |  2 +-
+ include/uapi/linux/ipv6.h                     |  2 +-
+ include/uapi/linux/tcp.h                      |  4 ++--
+ include/uapi/linux/udp.h                      |  2 +-
+ net/netfilter/nf_conntrack_core.c             |  4 ++--
+ include/uapi/linux/icmp.h                     |  2 +-
+ include/uapi/linux/in6.h                      |  2 +-
+ net/ipv6/tcp_ipv6.c                           |  9 +++--
+ net/ipv6/datagram.c                           |  6 ++--
+ net/ipv6/exthdrs.c                            |  2 +-
+ include/linux/types.h                         |  5 +++
+ net/ipv4/af_inet.c                            |  4 ++--
+ net/ipv4/tcp_output.c                         | 69 +++++++++--------
+ include/uapi/linux/igmp.h                     |  8 +++---
+ net/core/flow_dissector.c                     |  2 +-
+ include/uapi/linux/icmpv6.h                   |  2 +-
+ include/net/ndisc.h                           | 10 ++++----
+ net/sched/cls_u32.c                           |  6 +++---
+ net/ipv6/ip6_offload.c                        |  2 +-
+ include/net/addrconf.h                        |  2 +-
+ include/net/inet_ecn.h                        |  4 ++--
+ include/net/ipv6.h                            | 23 +++++----
+ include/net/secure_seq.h                      |  1 +
+ include/uapi/linux/in.h                       |  2 +-
+ net/ipv6/ip6_fib.h                            |  2 +-
+ net/netfilter/nf_conntrack_proto_tcp.c        |  2 +-
+ net/xfrm/xfrm_input.c                         |  4 ++--
+ net/ipv4/tcp_input.c                          | 12 ++++---
+ include/uapi/linux/if_pppox.h                 |  1 +
+ net/ipv6/netfilter/nf_log_ipv6.c              |  4 ++--
+ include/net/neighbour.h                       |  6 +++--
+ include/uapi/linux/netfilter_arp/arp_tables.h |  2 +-
+ net/core/utils.c                              | 10 +++++--
+ include/linux/etherdevice.h                   | 11 ++++---
+ net/ipv4/tcp_offload.c                        |  6 +++---
+ net/ipv6/netfilter/ip6table_mangle.c          |  4 ++--
+ 37 file changed, 171 insertions(+), 141 deletions(-)
+
+--- a/arch/mips/include/asm/checksum.h
++++ b/arch/mips/include/asm/checksum.h
+@@ -100,26 +100,30 @@ static inline __sum16 ip_fast_csum(const
+ 	const unsigned int *stop = word + ihl;
+ 	unsigned int csum;
+ 	int carry;
++	unsigned int w;
+ 
+-	csum = word[0];
+-	csum += word[1];
+-	carry = (csum < word[1]);
++	csum = net_hdr_word(word++);
++
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	csum += word[2];
+-	carry = (csum < word[2]);
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	csum += word[3];
+-	carry = (csum < word[3]);
++	w = net_hdr_word(word++);
++	csum += w;
++	carry = (csum < w);
+ 	csum += carry;
+ 
+-	word += 4;
+ 	do {
+-		csum += *word;
+-		carry = (csum < *word);
++		w = net_hdr_word(word++);
++		csum += w;
++		carry = (csum < w);
+ 		csum += carry;
+-		word++;
+ 	} while (word != stop);
+ 
+ 	return csum_fold(csum);
+@@ -179,74 +183,6 @@ static inline __sum16 ip_compute_csum(co
+ 	return csum_fold(csum_partial(buff, len, 0));
+ }
+ 
+-#define _HAVE_ARCH_IPV6_CSUM
+-static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+-					  const struct in6_addr *daddr,
+-					  __u32 len, __u8 proto,
+-					  __wsum sum)
+-{
+-	__wsum tmp;
+-
+-	__asm__(
+-	"	.set	push		# csum_ipv6_magic\n"
+-	"	.set	noreorder	\n"
+-	"	.set	noat		\n"
+-	"	addu	%0, %5		# proto (long in network byte order)\n"
+-	"	sltu	$1, %0, %5	\n"
+-	"	addu	%0, $1		\n"
+-
+-	"	addu	%0, %6		# csum\n"
+-	"	sltu	$1, %0, %6	\n"
+-	"	lw	%1, 0(%2)	# four words source address\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 4(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 8(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 12(%2)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 0(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 4(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 8(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	lw	%1, 12(%3)	\n"
+-	"	addu	%0, $1		\n"
+-	"	addu	%0, %1		\n"
+-	"	sltu	$1, %0, %1	\n"
+-
+-	"	addu	%0, $1		# Add final carry\n"
+-	"	.set	pop"
+-	: "=&r" (sum), "=&r" (tmp)
+-	: "r" (saddr), "r" (daddr),
+-	  "0" (htonl(len)), "r" (htonl(proto)), "r" (sum)
+-	: "memory");
+-
+-	return csum_fold(sum);
+-}
+-
+ #include <asm-generic/checksum.h>
+ #endif /* CONFIG_GENERIC_CSUM */
+ 
+--- a/include/uapi/linux/ip.h
++++ b/include/uapi/linux/ip.h
+@@ -106,7 +106,7 @@ struct iphdr {
+ 		__be32	daddr;
+ 	);
+ 	/*The options start here. */
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ struct ip_auth_hdr {
+--- a/include/uapi/linux/ipv6.h
++++ b/include/uapi/linux/ipv6.h
+@@ -135,7 +135,7 @@ struct ipv6hdr {
+ 		struct	in6_addr	saddr;
+ 		struct	in6_addr	daddr;
+ 	);
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ /* index values for the variables in ipv6_devconf */
+--- a/include/uapi/linux/tcp.h
++++ b/include/uapi/linux/tcp.h
+@@ -55,7 +55,7 @@ struct tcphdr {
+ 	__be16	window;
+ 	__sum16	check;
+ 	__be16	urg_ptr;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /*
+  *	The union cast uses a gcc extension to avoid aliasing problems
+@@ -65,7 +65,7 @@ struct tcphdr {
+ union tcp_word_hdr {
+ 	struct tcphdr hdr;
+ 	__be32        words[5];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ #define tcp_flag_word(tp) (((union tcp_word_hdr *)(tp))->words[3])
+ 
+--- a/include/uapi/linux/udp.h
++++ b/include/uapi/linux/udp.h
+@@ -25,7 +25,7 @@ struct udphdr {
+ 	__be16	dest;
+ 	__be16	len;
+ 	__sum16	check;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /* UDP socket options */
+ #define UDP_CORK	1	/* Never send partially complete segments */
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -308,8 +308,8 @@ nf_ct_get_tuple(const struct sk_buff *sk
+ 
+ 	switch (l3num) {
+ 	case NFPROTO_IPV4:
+-		tuple->src.u3.ip = ap[0];
+-		tuple->dst.u3.ip = ap[1];
++		tuple->src.u3.ip = net_hdr_word(ap++);
++		tuple->dst.u3.ip = net_hdr_word(ap);
+ 		break;
+ 	case NFPROTO_IPV6:
+ 		memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6));
+--- a/include/uapi/linux/icmp.h
++++ b/include/uapi/linux/icmp.h
+@@ -102,7 +102,7 @@ struct icmphdr {
+ 	} frag;
+ 	__u8	reserved[4];
+   } un;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ /*
+--- a/include/uapi/linux/in6.h
++++ b/include/uapi/linux/in6.h
+@@ -43,7 +43,7 @@ struct in6_addr {
+ #define s6_addr16		in6_u.u6_addr16
+ #define s6_addr32		in6_u.u6_addr32
+ #endif
+-};
++} __attribute__((packed, aligned(2)));
+ #endif /* __UAPI_DEF_IN6_ADDR */
+ 
+ #if __UAPI_DEF_SOCKADDR_IN6
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -35,6 +35,7 @@
+ #include <linux/ipsec.h>
+ #include <linux/times.h>
+ #include <linux/slab.h>
++#include <asm/unaligned.h>
+ #include <linux/uaccess.h>
+ #include <linux/ipv6.h>
+ #include <linux/icmpv6.h>
+@@ -901,10 +902,10 @@ static void tcp_v6_send_response(const s
+ 	topt = (__be32 *)(t1 + 1);
+ 
+ 	if (tsecr) {
+-		*topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+-				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+-		*topt++ = htonl(tsval);
+-		*topt++ = htonl(tsecr);
++		put_unaligned_be32((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++				(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP, topt++);
++		put_unaligned_be32(tsval, topt++);
++		put_unaligned_be32(tsecr, topt++);
+ 	}
+ 
+ 	if (mrst)
+--- a/include/linux/ipv6.h
++++ b/include/linux/ipv6.h
+@@ -6,6 +6,7 @@
+ 
+ #define ipv6_optlen(p)  (((p)->hdrlen+1) << 3)
+ #define ipv6_authlen(p) (((p)->hdrlen+2) << 2)
++
+ /*
+  * This structure contains configuration options per IPv6 link.
+  */
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -497,7 +497,7 @@ int ipv6_recv_error(struct sock *sk, str
+ 				ipv6_iface_scope_id(&sin->sin6_addr,
+ 						    IP6CB(skb)->iif);
+ 		} else {
+-			ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
++			ipv6_addr_set_v4mapped(net_hdr_word(nh + serr->addr_offset),
+ 					       &sin->sin6_addr);
+ 			sin->sin6_scope_id = 0;
+ 		}
+@@ -851,12 +851,12 @@ int ip6_datagram_send_ctl(struct net *ne
+ 			}
+ 
+ 			if (fl6->flowlabel&IPV6_FLOWINFO_MASK) {
+-				if ((fl6->flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {
++				if ((fl6->flowlabel^net_hdr_word(CMSG_DATA(cmsg)))&~IPV6_FLOWINFO_MASK) {
+ 					err = -EINVAL;
+ 					goto exit_f;
+ 				}
+ 			}
+-			fl6->flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);
++			fl6->flowlabel = IPV6_FLOWINFO_MASK & net_hdr_word(CMSG_DATA(cmsg));
+ 			break;
+ 
+ 		case IPV6_2292HOPOPTS:
+--- a/net/ipv6/exthdrs.c
++++ b/net/ipv6/exthdrs.c
+@@ -1013,7 +1013,7 @@ static bool ipv6_hop_jumbo(struct sk_buf
+ 		goto drop;
+ 	}
+ 
+-	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
++	pkt_len = ntohl(net_hdr_word(nh + optoff + 2));
+ 	if (pkt_len <= IPV6_MAXPLEN) {
+ 		icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, optoff + 2,
+ 					 SKB_DROP_REASON_IP_INHDR);
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -232,5 +232,11 @@ typedef void (*swap_func_t)(void *a, voi
+ typedef int (*cmp_r_func_t)(const void *a, const void *b, const void *priv);
+ typedef int (*cmp_func_t)(const void *a, const void *b);
+ 
++struct net_hdr_word {
++       u32 words[1];
++} __attribute__((packed, aligned(2)));
++
++#define net_hdr_word(_p) (((struct net_hdr_word *) (_p))->words[0])
++
+ #endif /*  __ASSEMBLY__ */
+ #endif /* _LINUX_TYPES_H */
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1515,8 +1515,8 @@ struct sk_buff *inet_gro_receive(struct
+ 	if (unlikely(ip_fast_csum((u8 *)iph, 5)))
+ 		goto out;
+ 
+-	id = ntohl(*(__be32 *)&iph->id);
+-	flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF));
++	id = ntohl(net_hdr_word(&iph->id));
++	flush = (u16)((ntohl(net_hdr_word(iph)) ^ skb_gro_len(skb)) | (id & ~IP_DF));
+ 	id >>= 16;
+ 
+ 	list_for_each_entry(p, head, list) {
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -612,48 +612,53 @@ static void tcp_options_write(struct tcp
+ 	u16 options = opts->options;	/* mungable copy */
+ 
+ 	if (unlikely(OPTION_MD5 & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+-			       (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++			      (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
+ 		/* overload cookie hash location */
+ 		opts->hash_location = (__u8 *)ptr;
+ 		ptr += 4;
+ 	}
+ 
+ 	if (unlikely(opts->mss)) {
+-		*ptr++ = htonl((TCPOPT_MSS << 24) |
+-			       (TCPOLEN_MSS << 16) |
+-			       opts->mss);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) |
++			      opts->mss);
+ 	}
+ 
+ 	if (likely(OPTION_TS & options)) {
+ 		if (unlikely(OPTION_SACK_ADVERTISE & options)) {
+-			*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
+-				       (TCPOLEN_SACK_PERM << 16) |
+-				       (TCPOPT_TIMESTAMP << 8) |
+-				       TCPOLEN_TIMESTAMP);
++			net_hdr_word(ptr++) =
++				htonl((TCPOPT_SACK_PERM << 24) |
++				      (TCPOLEN_SACK_PERM << 16) |
++				      (TCPOPT_TIMESTAMP << 8) |
++				      TCPOLEN_TIMESTAMP);
+ 			options &= ~OPTION_SACK_ADVERTISE;
+ 		} else {
+-			*ptr++ = htonl((TCPOPT_NOP << 24) |
+-				       (TCPOPT_NOP << 16) |
+-				       (TCPOPT_TIMESTAMP << 8) |
+-				       TCPOLEN_TIMESTAMP);
++			net_hdr_word(ptr++) =
++				htonl((TCPOPT_NOP << 24) |
++				      (TCPOPT_NOP << 16) |
++				      (TCPOPT_TIMESTAMP << 8) |
++				      TCPOLEN_TIMESTAMP);
+ 		}
+-		*ptr++ = htonl(opts->tsval);
+-		*ptr++ = htonl(opts->tsecr);
++		net_hdr_word(ptr++) = htonl(opts->tsval);
++		net_hdr_word(ptr++) = htonl(opts->tsecr);
+ 	}
+ 
+ 	if (unlikely(OPTION_SACK_ADVERTISE & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) |
+-			       (TCPOPT_NOP << 16) |
+-			       (TCPOPT_SACK_PERM << 8) |
+-			       TCPOLEN_SACK_PERM);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_NOP << 16) |
++			      (TCPOPT_SACK_PERM << 8) |
++			      TCPOLEN_SACK_PERM);
+ 	}
+ 
+ 	if (unlikely(OPTION_WSCALE & options)) {
+-		*ptr++ = htonl((TCPOPT_NOP << 24) |
+-			       (TCPOPT_WINDOW << 16) |
+-			       (TCPOLEN_WINDOW << 8) |
+-			       opts->ws);
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_WINDOW << 16) |
++			      (TCPOLEN_WINDOW << 8) |
++			      opts->ws);
+ 	}
+ 
+ 	if (unlikely(opts->num_sack_blocks)) {
+@@ -661,16 +666,17 @@ static void tcp_options_write(struct tcp
+ 			tp->duplicate_sack : tp->selective_acks;
+ 		int this_sack;
+ 
+-		*ptr++ = htonl((TCPOPT_NOP  << 24) |
+-			       (TCPOPT_NOP  << 16) |
+-			       (TCPOPT_SACK <<  8) |
+-			       (TCPOLEN_SACK_BASE + (opts->num_sack_blocks *
++		net_hdr_word(ptr++) =
++			htonl((TCPOPT_NOP << 24) |
++			      (TCPOPT_NOP << 16) |
++			      (TCPOPT_SACK << 8) |
++			      (TCPOLEN_SACK_BASE + (opts->num_sack_blocks *
+ 						     TCPOLEN_SACK_PERBLOCK)));
+ 
+ 		for (this_sack = 0; this_sack < opts->num_sack_blocks;
+ 		     ++this_sack) {
+-			*ptr++ = htonl(sp[this_sack].start_seq);
+-			*ptr++ = htonl(sp[this_sack].end_seq);
++			net_hdr_word(ptr++) = htonl(sp[this_sack].start_seq);
++			net_hdr_word(ptr++) = htonl(sp[this_sack].end_seq);
+ 		}
+ 
+ 		tp->rx_opt.dsack = 0;
+@@ -683,13 +689,14 @@ static void tcp_options_write(struct tcp
+ 
+ 		if (foc->exp) {
+ 			len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len;
+-			*ptr = htonl((TCPOPT_EXP << 24) | (len << 16) |
++			net_hdr_word(ptr) =
++				htonl((TCPOPT_EXP << 24) | (len << 16) |
+ 				     TCPOPT_FASTOPEN_MAGIC);
+ 			p += TCPOLEN_EXP_FASTOPEN_BASE;
+ 		} else {
+ 			len = TCPOLEN_FASTOPEN_BASE + foc->len;
+-			*p++ = TCPOPT_FASTOPEN;
+-			*p++ = len;
++			net_hdr_word(p++) = TCPOPT_FASTOPEN;
++			net_hdr_word(p++) = len;
+ 		}
+ 
+ 		memcpy(p, foc->val, foc->len);
+--- a/include/uapi/linux/igmp.h
++++ b/include/uapi/linux/igmp.h
+@@ -33,7 +33,7 @@ struct igmphdr {
+ 	__u8 code;		/* For newer IGMP */
+ 	__sum16 csum;
+ 	__be32 group;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /* V3 group record types [grec_type] */
+ #define IGMPV3_MODE_IS_INCLUDE		1
+@@ -49,7 +49,7 @@ struct igmpv3_grec {
+ 	__be16	grec_nsrcs;
+ 	__be32	grec_mca;
+ 	__be32	grec_src[];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct igmpv3_report {
+ 	__u8 type;
+@@ -58,7 +58,7 @@ struct igmpv3_report {
+ 	__be16 resv2;
+ 	__be16 ngrec;
+ 	struct igmpv3_grec grec[];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct igmpv3_query {
+ 	__u8 type;
+@@ -79,7 +79,7 @@ struct igmpv3_query {
+ 	__u8 qqic;
+ 	__be16 nsrcs;
+ 	__be32 srcs[];
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ #define IGMP_HOST_MEMBERSHIP_QUERY	0x11	/* From RFC1112 */
+ #define IGMP_HOST_MEMBERSHIP_REPORT	0x12	/* Ditto */
+--- a/net/core/flow_dissector.c
++++ b/net/core/flow_dissector.c
+@@ -131,7 +131,7 @@ __be32 __skb_flow_get_ports(const struct
+ 		ports = __skb_header_pointer(skb, thoff + poff,
+ 					     sizeof(_ports), data, hlen, &_ports);
+ 		if (ports)
+-			return *ports;
++			return (__be32)net_hdr_word(ports);
+ 	}
+ 
+ 	return 0;
+--- a/include/uapi/linux/icmpv6.h
++++ b/include/uapi/linux/icmpv6.h
+@@ -78,7 +78,7 @@ struct icmp6hdr {
+ #define icmp6_addrconf_other	icmp6_dataun.u_nd_ra.other
+ #define icmp6_rt_lifetime	icmp6_dataun.u_nd_ra.rt_lifetime
+ #define icmp6_router_pref	icmp6_dataun.u_nd_ra.router_pref
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ 
+ #define ICMPV6_ROUTER_PREF_LOW		0x3
+--- a/include/net/ndisc.h
++++ b/include/net/ndisc.h
+@@ -93,7 +93,7 @@ struct ra_msg {
+         struct icmp6hdr		icmph;
+ 	__be32			reachable_time;
+ 	__be32			retrans_timer;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ struct rd_msg {
+ 	struct icmp6hdr icmph;
+@@ -372,10 +372,10 @@ static inline u32 ndisc_hashfn(const voi
+ {
+ 	const u32 *p32 = pkey;
+ 
+-	return (((p32[0] ^ hash32_ptr(dev)) * hash_rnd[0]) +
+-		(p32[1] * hash_rnd[1]) +
+-		(p32[2] * hash_rnd[2]) +
+-		(p32[3] * hash_rnd[3]));
++	return (((net_hdr_word(&p32[0]) ^ hash32_ptr(dev)) * hash_rnd[0]) +
++		(net_hdr_word(&p32[1]) * hash_rnd[1]) +
++		(net_hdr_word(&p32[2]) * hash_rnd[2]) +
++		(net_hdr_word(&p32[3]) * hash_rnd[3]));
+ }
+ 
+ static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey)
+--- a/net/sched/cls_u32.c
++++ b/net/sched/cls_u32.c
+@@ -155,7 +155,7 @@ next_knode:
+ 			data = skb_header_pointer(skb, toff, 4, &hdata);
+ 			if (!data)
+ 				goto out;
+-			if ((*data ^ key->val) & key->mask) {
++			if ((net_hdr_word(data) ^ key->val) & key->mask) {
+ 				n = rcu_dereference_bh(n->next);
+ 				goto next_knode;
+ 			}
+@@ -206,8 +206,8 @@ check_terminal:
+ 						  &hdata);
+ 			if (!data)
+ 				goto out;
+-			sel = ht->divisor & u32_hash_fold(*data, &n->sel,
+-							  n->fshift);
++			sel = ht->divisor & u32_hash_fold(net_hdr_word(data),
++							  &n->sel, n->fshift);
+ 		}
+ 		if (!(n->sel.flags & (TC_U32_VAROFFSET | TC_U32_OFFSET | TC_U32_EAT)))
+ 			goto next_ht;
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -290,7 +290,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
+ 			continue;
+ 
+ 		iph2 = (struct ipv6hdr *)(p->data + off);
+-		first_word = *(__be32 *)iph ^ *(__be32 *)iph2;
++		first_word = net_hdr_word(iph) ^ net_hdr_word(iph2);
+ 
+ 		/* All fields must match except length and Traffic Class.
+ 		 * XXX skbs on the gro_list have all been parsed and pulled
+--- a/include/net/addrconf.h
++++ b/include/net/addrconf.h
+@@ -52,7 +52,7 @@ struct prefix_info {
+ 	__be32			reserved2;
+ 
+ 	struct in6_addr		prefix;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /* rfc4861 4.6.2: IPv6 PIO is 32 bytes in size */
+ static_assert(sizeof(struct prefix_info) == 32);
+--- a/include/net/inet_ecn.h
++++ b/include/net/inet_ecn.h
+@@ -138,9 +138,9 @@ static inline int IP6_ECN_set_ce(struct
+ 	if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph)))
+ 		return 0;
+ 
+-	from = *(__be32 *)iph;
++	from = net_hdr_word(iph);
+ 	to = from | htonl(INET_ECN_CE << 20);
+-	*(__be32 *)iph = to;
++	net_hdr_word(iph) = to;
+ 	if (skb->ip_summed == CHECKSUM_COMPLETE)
+ 		skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from),
+ 				     (__force __wsum)to);
+--- a/include/net/ipv6.h
++++ b/include/net/ipv6.h
+@@ -149,7 +149,7 @@ struct frag_hdr {
+ 	__u8	reserved;
+ 	__be16	frag_off;
+ 	__be32	identification;
+-};
++} __attribute__((packed, aligned(2)));
+ 
+ /*
+  * Jumbo payload option, as described in RFC 2675 2.
+@@ -615,8 +615,8 @@ static inline void __ipv6_addr_set_half(
+ 	}
+ #endif
+ #endif
+-	addr[0] = wh;
+-	addr[1] = wl;
++	net_hdr_word(&addr[0]) = wh;
++	net_hdr_word(&addr[1]) = wl;
+ }
+ 
+ static inline void ipv6_addr_set(struct in6_addr *addr,
+@@ -675,6 +675,8 @@ static inline bool ipv6_prefix_equal(con
+ 	const __be32 *a1 = addr1->s6_addr32;
+ 	const __be32 *a2 = addr2->s6_addr32;
+ 	unsigned int pdw, pbi;
++	/* Used for last <32-bit fraction of prefix */
++	u32 pbia1, pbia2;
+ 
+ 	/* check complete u32 in prefix */
+ 	pdw = prefixlen >> 5;
+@@ -683,7 +685,9 @@ static inline bool ipv6_prefix_equal(con
+ 
+ 	/* check incomplete u32 in prefix */
+ 	pbi = prefixlen & 0x1f;
+-	if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi))))
++	pbia1 = net_hdr_word(&a1[pdw]);
++	pbia2 = net_hdr_word(&a2[pdw]);
++	if (pbi && ((pbia1 ^ pbia2) & htonl((0xffffffff) << (32 - pbi))))
+ 		return false;
+ 
+ 	return true;
+@@ -805,13 +809,13 @@ static inline void ipv6_addr_set_v4mappe
+  */
+ static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen)
+ {
+-	const __be32 *a1 = token1, *a2 = token2;
++	const struct in6_addr *a1 = token1, *a2 = token2;
+ 	int i;
+ 
+ 	addrlen >>= 2;
+ 
+ 	for (i = 0; i < addrlen; i++) {
+-		__be32 xb = a1[i] ^ a2[i];
++		__be32 xb = a1->s6_addr32[i] ^ a2->s6_addr32[i];
+ 		if (xb)
+ 			return i * 32 + 31 - __fls(ntohl(xb));
+ 	}
+@@ -1005,17 +1009,18 @@ static inline u32 ip6_multipath_hash_fie
+ static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass,
+ 				__be32 flowlabel)
+ {
+-	*(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel;
++	net_hdr_word((__be32 *)hdr) =
++		htonl(0x60000000 | (tclass << 20)) | flowlabel;
+ }
+ 
+ static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr)
+ {
+-	return *(__be32 *)hdr & IPV6_FLOWINFO_MASK;
++	return net_hdr_word((__be32 *)hdr) & IPV6_FLOWINFO_MASK;
+ }
+ 
+ static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
+ {
+-	return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
++	return net_hdr_word((__be32 *)hdr) & IPV6_FLOWLABEL_MASK;
+ }
+ 
+ static inline u8 ip6_tclass(__be32 flowinfo)
+--- a/include/net/secure_seq.h
++++ b/include/net/secure_seq.h
+@@ -3,6 +3,7 @@
+ #define _NET_SECURE_SEQ
+ 
+ #include <linux/types.h>
++#include <linux/in6.h>
+ 
+ struct net;
+ 
+--- a/include/uapi/linux/in.h
++++ b/include/uapi/linux/in.h
+@@ -91,7 +91,7 @@ enum {
+ /* Internet address. */
+ struct in_addr {
+ 	__be32	s_addr;
+-};
++} __attribute__((packed, aligned(2)));
+ #endif
+ 
+ #define IP_TOS		1
+--- a/net/ipv6/ip6_fib.c
++++ b/net/ipv6/ip6_fib.c
+@@ -142,7 +142,7 @@ static __be32 addr_bit_set(const void *t
+ 	 * See include/asm-generic/bitops/le.h.
+ 	 */
+ 	return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) &
+-	       addr[fn_bit >> 5];
++	       net_hdr_word(&addr[fn_bit >> 5]);
+ }
+ 
+ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags, bool with_fib6_nh)
+--- a/net/netfilter/nf_conntrack_proto_tcp.c
++++ b/net/netfilter/nf_conntrack_proto_tcp.c
+@@ -406,7 +406,7 @@ static void tcp_sack(const struct sk_buf
+ 
+ 	/* Fast path for timestamp-only option */
+ 	if (length == TCPOLEN_TSTAMP_ALIGNED
+-	    && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24)
++	    && net_hdr_word(ptr) == htonl((TCPOPT_NOP << 24)
+ 				       | (TCPOPT_NOP << 16)
+ 				       | (TCPOPT_TIMESTAMP << 8)
+ 				       | TCPOLEN_TIMESTAMP))
+--- a/net/xfrm/xfrm_input.c
++++ b/net/xfrm/xfrm_input.c
+@@ -168,8 +168,8 @@ int xfrm_parse_spi(struct sk_buff *skb,
+ 	if (!pskb_may_pull(skb, hlen))
+ 		return -EINVAL;
+ 
+-	*spi = *(__be32 *)(skb_transport_header(skb) + offset);
+-	*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
++	*spi = net_hdr_word(skb_transport_header(skb) + offset);
++	*seq = net_hdr_word(skb_transport_header(skb) + offset_seq);
+ 	return 0;
+ }
+ EXPORT_SYMBOL(xfrm_parse_spi);
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -4183,14 +4183,16 @@ static bool tcp_parse_aligned_timestamp(
+ {
+ 	const __be32 *ptr = (const __be32 *)(th + 1);
+ 
+-	if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+-			  | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
++	if (net_hdr_word(ptr) ==
++	    htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
++		  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
+ 		tp->rx_opt.saw_tstamp = 1;
+ 		++ptr;
+-		tp->rx_opt.rcv_tsval = ntohl(*ptr);
++		tp->rx_opt.rcv_tsval = get_unaligned_be32(ptr);
+ 		++ptr;
+-		if (*ptr)
+-			tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset;
++		if (net_hdr_word(ptr))
++			tp->rx_opt.rcv_tsecr = get_unaligned_be32(ptr) -
++					       tp->tsoffset;
+ 		else
+ 			tp->rx_opt.rcv_tsecr = 0;
+ 		return true;
+--- a/include/uapi/linux/if_pppox.h
++++ b/include/uapi/linux/if_pppox.h
+@@ -51,6 +51,7 @@ struct pppoe_addr {
+  */
+ struct pptp_addr {
+ 	__u16		call_id;
++	__u16		pad;
+ 	struct in_addr	sin_addr;
+ };
+ 
+--- a/include/net/neighbour.h
++++ b/include/net/neighbour.h
+@@ -286,8 +286,10 @@ static inline bool neigh_key_eq128(const
+ 	const u32 *n32 = (const u32 *)n->primary_key;
+ 	const u32 *p32 = pkey;
+ 
+-	return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) |
+-		(n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0;
++	return ((n32[0] ^ net_hdr_word(&p32[0])) |
++		(n32[1] ^ net_hdr_word(&p32[1])) |
++		(n32[2] ^ net_hdr_word(&p32[2])) |
++		(n32[3] ^ net_hdr_word(&p32[3]))) == 0;
+ }
+ 
+ static inline struct neighbour *___neigh_lookup_noref(
+--- a/include/uapi/linux/netfilter_arp/arp_tables.h
++++ b/include/uapi/linux/netfilter_arp/arp_tables.h
+@@ -70,7 +70,7 @@ struct arpt_arp {
+ 	__u8 flags;
+ 	/* Inverse flags */
+ 	__u16 invflags;
+-};
++} __attribute__((aligned(4)));
+ 
+ /* Values for "flag" field in struct arpt_ip (general arp structure).
+  * No flags defined yet.
+--- a/net/core/utils.c
++++ b/net/core/utils.c
+@@ -460,8 +460,14 @@ void inet_proto_csum_replace16(__sum16 *
+ 			       bool pseudohdr)
+ {
+ 	__be32 diff[] = {
+-		~from[0], ~from[1], ~from[2], ~from[3],
+-		to[0], to[1], to[2], to[3],
++		~net_hdr_word(&from[0]),
++		~net_hdr_word(&from[1]),
++		~net_hdr_word(&from[2]),
++		~net_hdr_word(&from[3]),
++		net_hdr_word(&to[0]),
++		net_hdr_word(&to[1]),
++		net_hdr_word(&to[2]),
++		net_hdr_word(&to[3]),
+ 	};
+ 	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+ 		*sum = csum_fold(csum_partial(diff, sizeof(diff),
+--- a/include/linux/etherdevice.h
++++ b/include/linux/etherdevice.h
+@@ -555,7 +555,7 @@ static inline bool is_etherdev_addr(cons
+  * @b: Pointer to Ethernet header
+  *
+  * Compare two Ethernet headers, returns 0 if equal.
+- * This assumes that the network header (i.e., IP header) is 4-byte
++ * This assumes that the network header (i.e., IP header) is 2-byte
+  * aligned OR the platform can handle unaligned access.  This is the
+  * case for all packets coming into netif_receive_skb or similar
+  * entry points.
+@@ -578,11 +578,12 @@ static inline unsigned long compare_ethe
+ 	fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6);
+ 	return fold;
+ #else
+-	u32 *a32 = (u32 *)((u8 *)a + 2);
+-	u32 *b32 = (u32 *)((u8 *)b + 2);
++	const u16 *a16 = a;
++	const u16 *b16 = b;
+ 
+-	return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) |
+-	       (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]);
++	return (a16[0] ^ b16[0]) | (a16[1] ^ b16[1]) | (a16[2] ^ b16[2]) |
++	       (a16[3] ^ b16[3]) | (a16[4] ^ b16[4]) | (a16[5] ^ b16[5]) |
++	       (a16[6] ^ b16[6]);
+ #endif
+ }
+ 
+--- a/net/ipv4/tcp_offload.c
++++ b/net/ipv4/tcp_offload.c
+@@ -62,7 +62,7 @@ static struct sk_buff *__tcpv4_gso_segme
+ 	th2 = tcp_hdr(seg->next);
+ 	iph2 = ip_hdr(seg->next);
+ 
+-	if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
++	if (!(net_hdr_word(&th->source) ^ net_hdr_word(&th2->source)) &&
+ 	    iph->daddr == iph2->daddr && iph->saddr == iph2->saddr)
+ 		return segs;
+ 
+@@ -254,7 +254,7 @@ struct sk_buff *tcp_gro_lookup(struct li
+ 			continue;
+ 
+ 		th2 = tcp_hdr(p);
+-		if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
++		if (net_hdr_word(&th->source) ^ net_hdr_word(&th2->source)) {
+ 			NAPI_GRO_CB(p)->same_flow = 0;
+ 			continue;
+ 		}
+@@ -320,8 +320,8 @@ struct sk_buff *tcp_gro_receive(struct l
+ 		  ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH));
+ 	flush |= (__force int)(th->ack_seq ^ th2->ack_seq);
+ 	for (i = sizeof(*th); i < thlen; i += 4)
+-		flush |= *(u32 *)((u8 *)th + i) ^
+-			 *(u32 *)((u8 *)th2 + i);
++		flush |= net_hdr_word((u8 *)th + i) ^
++			 net_hdr_word((u8 *)th2 + i);
+ 
+ 	/* When we receive our second frame we can made a decision on if we
+ 	 * continue this flow as an atomic flow with a fixed ID or if we use
+--- a/net/ipv6/netfilter/ip6table_mangle.c
++++ b/net/ipv6/netfilter/ip6table_mangle.c
+@@ -44,7 +44,7 @@ ip6t_mangle_out(void *priv, struct sk_bu
+ 	hop_limit = ipv6_hdr(skb)->hop_limit;
+ 
+ 	/* flowlabel and prio (includes version, which shouldn't change either */
+-	flowlabel = *((u_int32_t *)ipv6_hdr(skb));
++	flowlabel = net_hdr_word(ipv6_hdr(skb));
+ 
+ 	ret = ip6t_do_table(priv, skb, state);
+ 
+@@ -53,7 +53,7 @@ ip6t_mangle_out(void *priv, struct sk_bu
+ 	     !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) ||
+ 	     skb->mark != mark ||
+ 	     ipv6_hdr(skb)->hop_limit != hop_limit ||
+-	     flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) {
++	     flowlabel != net_hdr_word(ipv6_hdr(skb)))) {
+ 		err = ip6_route_me_harder(state->net, state->sk, skb);
+ 		if (err < 0)
+ 			ret = NF_DROP_ERR(err);
diff --git a/target/linux/ath79/patches-6.1/910-mikrotik-rb4xx.patch b/target/linux/ath79/patches-6.1/910-mikrotik-rb4xx.patch
new file mode 100644
index 0000000000..536d7abf6b
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/910-mikrotik-rb4xx.patch
@@ -0,0 +1,121 @@
+From: Christopher Hill <ch6574 at gmail.com>
+Subject: [PATCH] ath79: add Mikrotik rb4xx series drivers
+
+This adds 3 Mikrotik rb4xx series drivers as follows:
+
+rb4xx-cpld: This is in the mfd subsystem, and is the parent CPLD device
+that interfaces between the SoC SPI bus and its two children below.
+rb4xx-gpio: This is the GPIO expander.
+rb4xx-nand: This is the NAND driver.
+
+The history of this code comes in three phases.
+
+1. The first is a May 2015 attempt to push the equivalient ar71xx rb4xx
+drivers upstream. See https://lore.kernel.org/patchwork/patch/940880/.
+
+Module-author: Gabor Juhos <juhosg at openwrt.org>
+Module-author: Imre Kaloz <kaloz at openwrt.org>
+Module-author: Bert Vermeulen <bert at biot.com>
+
+2. Next several ar71xx patches were applied bringing the code current.
+
+commit 7bbf4117c6fe4b764d9d7c62fb2bcf6dd93bff2c
+Submitted-by: Hauke Mehrtens <hauke at hauke-m.de>
+
+commit af79fdbe4af32a287798b579141204bda056b8aa
+commit 889272d92db689fd9c910243635e44c9d8323095
+commit e21cb649a235180563363b8af5ba8296b9ac0baa
+commit 7c09fa4a7492ca436f2c94bd9a465b7c5bbeed6f
+Submitted-by: Felix Fietkau <nbd at nbd.name>
+
+3. Finally a heavy refactor to split the driver into the three new
+subsystems, and updated to work with the device tree configuration, plus
+updates and review feedback incorporated
+
+Reviewed-by: Thibaut VARÈNE <hacks at slashdirt.org>
+Submitted-by: Christopher Hill <ch6574 at gmail.com>
+---
+ drivers/mfd/Kconfig                           | 8 ++++++++
+ drivers/mfd/Makefile                          | 1 +
+ drivers/gpio/Kconfig                          | 6 ++++++
+ drivers/gpio/Makefile                         | 1 +
+ drivers/mtd/nand/raw/Kconfig                  | 7 +++++++
+ drivers/mtd/nand/raw/Makefile                 | 1 +
+ 6 files changed, 24 insertions(+)
+
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -2209,6 +2209,14 @@ config RAVE_SP_CORE
+ 	  Select this to get support for the Supervisory Processor
+ 	  device found on several devices in RAVE line of hardware.
+ 
++config MFD_RB4XX_CPLD
++	tristate "CPLD driver for Mikrotik RB4xx series boards"
++	select MFD_CORE
++	depends on ATH79 || COMPILE_TEST
++	help
++	  Enables support for the CPLD chip (NAND & GPIO) on Mikrotik
++	  Routerboard RB4xx series.
++
+ config SGI_MFD_IOC3
+ 	bool "SGI IOC3 core driver"
+ 	depends on PCI && MIPS && 64BIT
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -269,6 +269,7 @@ obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-
+ obj-$(CONFIG_MFD_ACER_A500_EC)	+= acer-ec-a500.o
+ obj-$(CONFIG_MFD_QCOM_PM8008)	+= qcom-pm8008.o
+ 
++obj-$(CONFIG_MFD_RB4XX_CPLD)	+= rb4xx-cpld.o
+ obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
+ obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)	+= simple-mfd-i2c.o
+ obj-$(CONFIG_MFD_INTEL_M10_BMC)   += intel-m10-bmc.o
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -1594,6 +1594,12 @@ config GPIO_SODAVILLE
+ 	help
+ 	  Say Y here to support Intel Sodaville GPIO.
+ 
++config GPIO_RB4XX
++	tristate "GPIO expander for Mikrotik RB4xx series boards"
++	depends on MFD_RB4XX_CPLD
++	help
++	  GPIO driver for Mikrotik Routerboard RB4xx series.
++
+ endmenu
+ 
+ menu "SPI GPIO expanders"
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -123,6 +123,7 @@ obj-$(CONFIG_GPIO_PL061)		+= gpio-pl061.
+ obj-$(CONFIG_GPIO_PMIC_EIC_SPRD)	+= gpio-pmic-eic-sprd.o
+ obj-$(CONFIG_GPIO_PXA)			+= gpio-pxa.o
+ obj-$(CONFIG_GPIO_RASPBERRYPI_EXP)	+= gpio-raspberrypi-exp.o
++obj-$(CONFIG_GPIO_RB4XX)		+= gpio-rb4xx.o
+ obj-$(CONFIG_GPIO_RC5T583)		+= gpio-rc5t583.o
+ obj-$(CONFIG_GPIO_RCAR)			+= gpio-rcar.o
+ obj-$(CONFIG_GPIO_RDA)			+= gpio-rda.o
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -565,4 +565,11 @@ config MTD_NAND_AR934X
+ 	  Enables support for NAND controller on Qualcomm Atheros SoCs.
+ 	  This controller is found on AR934x and QCA955x SoCs.
+ 
++config MTD_NAND_RB4XX
++	tristate "Support for NAND driver for Mikrotik RB4xx series boards"
++	depends on MFD_RB4XX_CPLD
++	help
++	  Enables support for the NAND flash chip on Mikrotik Routerboard
++	  RB4xx series.
++
+ endif # MTD_RAW_NAND
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -60,6 +60,7 @@ obj-$(CONFIG_MTD_NAND_ROCKCHIP)		+= rock
+ obj-$(CONFIG_MTD_NAND_PL35X)		+= pl35x-nand-controller.o
+ obj-$(CONFIG_MTD_NAND_RENESAS)		+= renesas-nand-controller.o
+ obj-$(CONFIG_MTD_NAND_AR934X)		+= ar934x_nand.o
++obj-$(CONFIG_MTD_NAND_RB4XX)		+= nand_rb4xx.o
+ 
+ nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+ nand-objs += nand_onfi.o
diff --git a/target/linux/ath79/patches-6.1/911-mikrotik-rb91x.patch b/target/linux/ath79/patches-6.1/911-mikrotik-rb91x.patch
new file mode 100644
index 0000000000..677428fa65
--- /dev/null
+++ b/target/linux/ath79/patches-6.1/911-mikrotik-rb91x.patch
@@ -0,0 +1,96 @@
+From: Denis Kalashnikov <denis281089 at gmail.com>
+Subject: [PATCH] ath79: add support for reset key on MikroTik RB912UAG-2HPnD
+
+On MikroTik RB91x board series a reset key shares SoC gpio
+line #15 with NAND ALE and NAND IO7. So we need a custom
+gpio driver to manage this non-trivial connection schema.
+Also rb91x-nand needs to have an ability to disable a polling
+of the key while it works with NAND.
+
+While we've been integrating rb91x-key into a firmware, we've
+figured out that:
+* In the gpio-latch driver we need to add a "cansleep" suffix to
+several gpiolib calls,
+* When gpio-latch and rb91x-nand fail to get a gpio and an error
+is -EPROBE_DEFER, they shouldn't report about this, since this
+actually is not an error and occurs when the gpio-latch probe
+function is called before the rb91x-key probe.
+We fix these related things here too.
+
+Submitted-by: Denis Kalashnikov <denis281089 at gmail.com>
+Reviewed-by: Sergey Ryazanov <ryazanov.s.a at gmail.com>
+Tested-by: Koen Vandeputte <koen.vandeputte at ncentric.com>
+---
+ drivers/gpio/Kconfig                          | 11 +++++++++++
+ drivers/gpio/Makefile                         |  2 ++
+ drivers/mtd/nand/raw/Kconfig                  |  6 ++++++
+ drivers/mtd/nand/raw/Makefile                 |  1 +
+ 7 files changed, 20 insertions(+)
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -368,6 +368,12 @@ config GPIO_IXP4XX
+ 
+ 	  If unsure, say N.
+ 
++config GPIO_LATCH_MIKROTIK
++	tristate "MikroTik RouterBOARD GPIO latch support"
++	depends on ATH79
++	help
++	  GPIO driver for latch on some MikroTik RouterBOARDs.
++
+ config GPIO_LOGICVC
+ 	tristate "Xylon LogiCVC GPIO support"
+ 	depends on MFD_SYSCON && OF
+@@ -544,6 +550,10 @@ config GPIO_ROCKCHIP
+ 	help
+ 	  Say yes here to support GPIO on Rockchip SoCs.
+ 
++config GPIO_RB91X_KEY
++	tristate "MikroTik RB91x board series reset key support"
++	depends on ATH79
++
+ config GPIO_SAMA5D2_PIOBU
+ 	tristate "SAMA5D2 PIOBU GPIO support"
+ 	depends on MFD_SYSCON
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -76,6 +76,7 @@ obj-$(CONFIG_GPIO_IT87)			+= gpio-it87.o
+ obj-$(CONFIG_GPIO_IXP4XX)		+= gpio-ixp4xx.o
+ obj-$(CONFIG_GPIO_JANZ_TTL)		+= gpio-janz-ttl.o
+ obj-$(CONFIG_GPIO_KEMPLD)		+= gpio-kempld.o
++obj-$(CONFIG_GPIO_LATCH_MIKROTIK)	+= gpio-latch-mikrotik.o
+ obj-$(CONFIG_GPIO_LOGICVC)		+= gpio-logicvc.o
+ obj-$(CONFIG_GPIO_LOONGSON1)		+= gpio-loongson1.o
+ obj-$(CONFIG_GPIO_LOONGSON)		+= gpio-loongson.o
+@@ -124,6 +125,7 @@ obj-$(CONFIG_GPIO_PMIC_EIC_SPRD)	+= gpio
+ obj-$(CONFIG_GPIO_PXA)			+= gpio-pxa.o
+ obj-$(CONFIG_GPIO_RASPBERRYPI_EXP)	+= gpio-raspberrypi-exp.o
+ obj-$(CONFIG_GPIO_RB4XX)		+= gpio-rb4xx.o
++obj-$(CONFIG_GPIO_RB91X_KEY)		+= gpio-rb91x-key.o
+ obj-$(CONFIG_GPIO_RC5T583)		+= gpio-rc5t583.o
+ obj-$(CONFIG_GPIO_RCAR)			+= gpio-rcar.o
+ obj-$(CONFIG_GPIO_RDA)			+= gpio-rda.o
+--- a/drivers/mtd/nand/raw/Kconfig
++++ b/drivers/mtd/nand/raw/Kconfig
+@@ -572,4 +572,10 @@ config MTD_NAND_RB4XX
+ 	  Enables support for the NAND flash chip on Mikrotik Routerboard
+ 	  RB4xx series.
+ 
++config MTD_NAND_RB91X
++	tristate "MikroTik RB91x NAND driver support"
++	depends on ATH79 && MTD_RAW_NAND
++	help
++	  Enables support for the NAND flash chip on MikroTik RB91x series.
++
+ endif # MTD_RAW_NAND
+--- a/drivers/mtd/nand/raw/Makefile
++++ b/drivers/mtd/nand/raw/Makefile
+@@ -61,6 +61,7 @@ obj-$(CONFIG_MTD_NAND_PL35X)		+= pl35x-n
+ obj-$(CONFIG_MTD_NAND_RENESAS)		+= renesas-nand-controller.o
+ obj-$(CONFIG_MTD_NAND_AR934X)		+= ar934x_nand.o
+ obj-$(CONFIG_MTD_NAND_RB4XX)		+= nand_rb4xx.o
++obj-$(CONFIG_MTD_NAND_RB91X)		+= rb91x_nand.o
+ 
+ nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
+ nand-objs += nand_onfi.o




More information about the lede-commits mailing list