Просмотр исходного кода

econet: add EN7528 subtarget support

The EN7528 is a little endian dual-core MIPS 1004Kc SoC used in xPON
devices. Unlike the big endian EN751221, EN7528 uses the MIPS GIC
interrupt controller for SMP.

This adds minimal boot support for EN7528:
- New en7528 subtarget with mipsel architecture
- Kernel patches for EN7528 SoC with GIC support
- Timer driver extended to support GIC shared interrupts per CPU
- SPI driver fix for EN7528 chip select handling
- Generic device tree for initial bring-up

Signed-off-by: Ahmed Naseef <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/21326
Signed-off-by: Hauke Mehrtens <[email protected]>
Ahmed Naseef 1 месяц назад
Родитель
Сommit
fab098cb61

+ 1 - 2
target/linux/econet/Makefile

@@ -4,11 +4,10 @@
 
 include $(TOPDIR)/rules.mk
 
-ARCH:=mips
 BOARD:=econet
 BOARDNAME:=EcoNet EN75xx MIPS
 FEATURES:=dt source-only squashfs nand usb
-SUBTARGETS:=en751221
+SUBTARGETS:=en751221 en7528
 
 KERNEL_PATCHVER:=6.12
 

+ 103 - 0
target/linux/econet/dts/en7528.dtsi

@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+
+/ {
+	compatible = "econet,en7528";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	hpt_clock: clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <200000000>;  /* 200 MHz */
+	};
+
+	spi_clock: spi-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;  /* 40 MHz */
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips1004Kc";
+			reg = <0>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "mips,mips1004Kc";
+			reg = <1>;
+		};
+	};
+
+	cpuintc: interrupt-controller {
+		compatible = "mti,cpu-interrupt-controller";
+		interrupt-controller;
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+	};
+
+	gic: interrupt-controller@1f8c0000 {
+		compatible = "mti,gic";
+		reg = <0x1f8c0000 0x20000>;
+
+		interrupt-controller;
+		#interrupt-cells = <3>;
+
+		interrupt-parent = <&cpuintc>;
+		interrupts = <2>;
+	};
+
+	timer_hpt: timer@1fbf0400 {
+		compatible = "econet,en7528-timer";
+		reg = <0x1fbf0400 0x14>,
+		      <0x1fbe0000 0x14>;
+
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SHARED 30 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SHARED 29 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SHARED 37 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SHARED 36 IRQ_TYPE_LEVEL_HIGH>;
+
+		clocks = <&hpt_clock>;
+	};
+
+	spi_ctrl: spi@1fa10000 {
+		compatible = "airoha,en7581-snand";
+		reg = <0x1fa10000 0x140>,
+		      <0x1fa11000 0x160>;
+
+		clocks = <&spi_clock>;
+		clock-names = "spi";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		nand: nand@0 {
+			compatible = "spi-nand";
+			reg = <0>;
+			spi-max-frequency = <40000000>;
+			spi-tx-bus-width = <1>;
+			spi-rx-bus-width = <2>;
+		};
+	};
+
+	uart: serial@1fbf0000 {
+		compatible = "airoha,en7523-uart";
+		reg = <0x1fbf0000 0x30>;
+		reg-io-width = <4>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>;
+
+		clock-frequency = <7372800>;
+	};
+};

+ 57 - 0
target/linux/econet/dts/en7528_generic.dts

@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+#include "en7528.dtsi"
+
+/ {
+	model = "Generic EN7528";
+	compatible = "econet,en7528-generic", "econet,en7528";
+
+	memory@0 {
+		// We hope at least 64MB will be available on every device
+		device_type = "memory";
+		reg = <0x00000000 0x4000000>;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+		linux,usable-memory-range = <0x00020000 0x3fe0000>;
+	};
+
+	aliases {
+		serial0 = &uart;
+	};
+};
+
+&nand {
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@1 {
+			// We don't know how big the flash is
+			// Put 1GB and let it truncate
+			label = "all_flash";
+			reg = <0x0 0x40000000>;
+			read-only;
+		};
+
+		partition@2 {
+			// We don't know how big the bootloader
+			// is, but when we're doing testing, lets
+			// make sure nobody touches anything below 4MB
+			label = "bootloader";
+			reg = <0x0 0x00400000>;
+			read-only;
+		};
+
+		partition@3 {
+			label = "rest_of_flash";
+			reg = <0x00400000 0x40000000>;
+		};
+	};
+};

+ 3 - 0
target/linux/econet/en751221/config-6.12

@@ -147,6 +147,7 @@ CONFIG_RESET_CONTROLLER=y
 CONFIG_RFS_ACCEL=y
 CONFIG_RPS=y
 CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y
+# CONFIG_SERIAL_8250_AIROHA is not set
 CONFIG_SERIAL_MCTRL_GPIO=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SGL_ALLOC=y
@@ -154,8 +155,10 @@ CONFIG_SMP=y
 CONFIG_SMP_UP=y
 CONFIG_SOCK_RX_QUEUE_MAPPING=y
 CONFIG_SOC_ECONET_EN751221=y
+# CONFIG_SOC_ECONET_EN7528 is not set
 CONFIG_SPI=y
 CONFIG_SPI_AIROHA_EN7523=y
+# CONFIG_SPI_AIROHA_SNFI is not set
 CONFIG_SPI_MASTER=y
 CONFIG_SPI_MEM=y
 CONFIG_SYSCTL_EXCEPTION_TRACE=y

+ 1 - 0
target/linux/econet/en751221/target.mk

@@ -1,3 +1,4 @@
+ARCH:=mips
 BOARDNAME:=en751221
 CPU_TYPE:=24kc
 KERNELNAME:=vmlinuz.bin

+ 216 - 0
target/linux/econet/en7528/config-6.12

@@ -0,0 +1,216 @@
+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_BOARD_SCACHE=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+# CONFIG_COMMON_CLK_EN7523 is not set
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=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_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_MIPSR2_IRQ_EI=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_MITIGATIONS=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LIB_GF128MUL=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_UTILS=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_ZBOOT=y
+CONFIG_DMA_NEED_SYNC=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTB_ECONET_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EARLY_PRINTK_8250=y
+CONFIG_ECONET=y
+CONFIG_ECONET_EN751221_TIMER=y
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_FS_IOMAP=y
+CONFIG_FUNCTION_ALIGNMENT=0
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=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_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIO_CDEV=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+# CONFIG_JFFS2_FS is not set
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MIGRATION=y
+CONFIG_MIPS=y
+CONFIG_MIPS_ASID_BITS=8
+CONFIG_MIPS_ASID_SHIFT=0
+CONFIG_MIPS_CM=y
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+CONFIG_MIPS_CPC=y
+CONFIG_MIPS_CPS=y
+# CONFIG_MIPS_CPS_NS16550_BOOL is not set
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_MIPS_GIC=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_MIPS_MT=y
+CONFIG_MIPS_MT_FPAFF=y
+CONFIG_MIPS_MT_SMP=y
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_NR_CPU_NR_MAP=4
+CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MIPS_SPRAM=y
+CONFIG_MMU_LAZY_TLB_REFCOUNT=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_MTK_BMT=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=13
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_SRCU_NMI_SAFE=y
+CONFIG_NET_EGRESS=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_XGRESS=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
+CONFIG_NVMEM_LAYOUTS=y
+CONFIG_NVMEM_SYSFS=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_PADATA=y
+CONFIG_PAGE_POOL=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PCI_DRIVERS_LEGACY=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_QUEUED_SPINLOCKS=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+# CONFIG_SCHED_CORE is not set
+CONFIG_SCHED_SMT=y
+CONFIG_SERIAL_8250_AIROHA=y
+CONFIG_SERIAL_MCTRL_GPIO=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SMP=y
+CONFIG_SMP_UP=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+# CONFIG_SOC_ECONET_EN751221 is not set
+CONFIG_SOC_ECONET_EN7528=y
+CONFIG_SPI=y
+# CONFIG_SPI_AIROHA_EN7523 is not set
+CONFIG_SPI_AIROHA_SNFI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPLIT_PTE_PTLOCKS=y
+CONFIG_SYNC_R4K=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=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_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_MIPS_CPS=y
+CONFIG_SYS_SUPPORTS_MULTITHREADING=y
+CONFIG_SYS_SUPPORTS_SCHED_SMT=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_SYS_SUPPORTS_ZBOOT=y
+CONFIG_SYS_SUPPORTS_ZBOOT_UART16550=y
+CONFIG_TARGET_ISA_REV=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
+CONFIG_USE_OF=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_XPS=y
+CONFIG_XXHASH=y
+CONFIG_ZBOOT_LOAD_ADDRESS=0x80020000
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZSTD_COMMON=y
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y

+ 12 - 0
target/linux/econet/en7528/profiles/00-default.mk

@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2025 OpenWrt.org
+
+define Profile/Default
+	NAME:=Default Profile
+endef
+
+define Profile/Default/Description
+	Default package set compatible with most EN7528 boards.
+endef
+$(eval $(call Profile,Default))

+ 11 - 0
target/linux/econet/en7528/target.mk

@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ARCH:=mipsel
+SUBTARGET:=en7528
+BOARDNAME:=EN7528 based boards
+CPU_TYPE:=24kc
+KERNELNAME:=vmlinuz.bin
+
+define Target/Description
+	Build firmware images for EcoNet EN7528 based boards.
+endef

+ 6 - 0
target/linux/econet/image/en7528.mk

@@ -0,0 +1,6 @@
+define Device/en7528_generic
+  DEVICE_VENDOR := EN7528
+  DEVICE_MODEL := Generic
+  DEVICE_DTS := en7528_generic
+endef
+TARGET_DEVICES += en7528_generic

+ 119 - 0
target/linux/econet/patches-6.12/100-econet-add-en7528-soc.patch

@@ -0,0 +1,119 @@
+From: Ahmed Naseef <[email protected]>
+Subject: mips: econet: add EN7528 SoC support
+
+The EN7528 is a little endian dual-core MIPS 1004Kc SoC used in xPON
+devices. Unlike the big endian EN751221, EN7528 uses the MIPS GIC
+interrupt controller for SMP.
+
+This adds boot support for the EN7528 SoC family:
+- New SOC_ECONET_EN7528 Kconfig option
+- Little endian support for ECONET platform
+- UART base address adjustment for endianness
+- CPS SMP ops registration for multi-core support
+
+Signed-off-by: Ahmed Naseef <[email protected]>
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -391,13 +391,13 @@ config MACH_DECSTATION
+ config ECONET
+ 	bool "EcoNet MIPS family"
+ 	select BOOT_RAW
+-	select CPU_BIG_ENDIAN
+ 	select DEBUG_ZBOOT if DEBUG_KERNEL
+ 	select EARLY_PRINTK_8250
+ 	select ECONET_EN751221_TIMER
+ 	select SERIAL_8250
+ 	select SERIAL_OF_PLATFORM
+ 	select SYS_SUPPORTS_BIG_ENDIAN
++	select SYS_SUPPORTS_LITTLE_ENDIAN
+ 	select SYS_HAS_CPU_MIPS32_R1
+ 	select SYS_HAS_CPU_MIPS32_R2
+ 	select SYS_HAS_EARLY_PRINTK
+--- a/arch/mips/econet/Kconfig
++++ b/arch/mips/econet/Kconfig
+@@ -12,6 +12,7 @@ choice
+ 	config SOC_ECONET_EN751221
+ 		bool "EN751221 family"
+ 		select COMMON_CLK
++		select CPU_BIG_ENDIAN
+ 		select ECONET_EN751221_INTC
+ 		select IRQ_MIPS_CPU
+ 		select SMP
+@@ -22,6 +23,23 @@ choice
+ 		  They are based on single core MIPS 34Kc processors. To boot
+ 		  this kernel, you will need a device tree such as
+ 		  MIPS_RAW_APPENDED_DTB=y, and a root filesystem.
++
++	config SOC_ECONET_EN7528
++		bool "EN7528 family"
++		select COMMON_CLK
++		select CPU_LITTLE_ENDIAN
++		select IRQ_MIPS_CPU
++		select MIPS_CPU_SCACHE
++		select MIPS_GIC
++		select SMP
++		select SMP_UP
++		select SYS_SUPPORTS_HIGHMEM
++		select SYS_SUPPORTS_MIPS_CPS
++		select SYS_SUPPORTS_MULTITHREADING
++		select SYS_SUPPORTS_SMP
++		help
++		  The EN7528 family with dual-core MIPS 1004Kc.
++		  Requires MIPS_RAW_APPENDED_DTB=y for boot.
+ endchoice
+ 
+ choice
+--- a/arch/mips/econet/init.c
++++ b/arch/mips/econet/init.c
+@@ -16,11 +16,16 @@
+ #include <asm/prom.h>
+ #include <asm/smp-ops.h>
+ #include <asm/reboot.h>
++#include <asm/mips-cps.h>
+ 
+ #define CR_AHB_RSTCR		((void __iomem *)CKSEG1ADDR(0x1fb00040))
+ #define RESET			BIT(31)
+ 
+-#define UART_BASE		CKSEG1ADDR(0x1fbf0003)
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++#define UART_BASE		CKSEG1ADDR(0x1fbf0000)	/* LE: byte at offset 0 */
++#else
++#define UART_BASE		CKSEG1ADDR(0x1fbf0003)	/* BE: byte at offset 3 */
++#endif
+ #define UART_REG_SHIFT		2
+ 
+ static void hw_reset(char *command)
+@@ -51,11 +56,18 @@ void __init plat_mem_setup(void)
+ 	early_init_dt_scan_memory();
+ }
+ 
+-/* 3. Overload __weak device_tree_init(), add SMP_UP ops */
++/* 3. Overload __weak device_tree_init(), register SMP ops */
+ void __init device_tree_init(void)
+ {
+ 	unflatten_and_copy_device_tree();
+ 
++	/* EN7528 dual-core: probe CM/CPC and register CPS SMP ops */
++	mips_cm_probe();
++	mips_cpc_probe();
++
++	if (!register_cps_smp_ops())
++		return;
++
+ 	register_up_smp_ops();
+ }
+ 
+--- a/arch/mips/boot/compressed/uart-16550.c
++++ b/arch/mips/boot/compressed/uart-16550.c
+@@ -21,7 +21,11 @@
+ #endif
+ 
+ #ifdef CONFIG_ECONET
++#ifdef CONFIG_CPU_LITTLE_ENDIAN
++#define EN75_UART_BASE	0x1fbf0000
++#else
+ #define EN75_UART_BASE	0x1fbf0003
++#endif
+ #define PORT(offset)	(CKSEG1ADDR(EN75_UART_BASE) + (4 * (offset)))
+ #endif
+ 

+ 264 - 0
target/linux/econet/patches-6.12/101-econet-timer-add-en7528-support.patch

@@ -0,0 +1,264 @@
+From: Ahmed Naseef <[email protected]>
+Subject: mips: econet: timer: add EN7528 support to EN751221 timer driver
+
+Extend the existing EN751221 timer driver to support EN7528/EN751627 SoCs.
+The driver now auto-detects the IRQ mode based on device tree:
+- EN751221: Single percpu IRQ (legacy interrupt controller)
+- EN7528/EN751627: Separate IRQ per CPU (GIC shared interrupts)
+
+Signed-off-by: Ahmed Naseef <[email protected]>
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -79,7 +79,10 @@ config ECONET_EN751221_TIMER
+ 	select CLKSRC_MMIO
+ 	select TIMER_OF
+ 	help
+-	  Support for CPU timer found on EcoNet MIPS based SoCs.
++	  Support for CPU timer found on EcoNet EN75xx MIPS based SoCs
++	  (EN751221, EN751627, EN7528). The driver supports both GIC-based
++	  (separate IRQ per CPU) and legacy interrupt controller (percpu IRQ)
++	  modes.
+ 
+ config FTTMR010_TIMER
+ 	bool "Faraday Technology timer driver" if COMPILE_TEST
+--- a/drivers/clocksource/timer-econet-en751221.c
++++ b/drivers/clocksource/timer-econet-en751221.c
+@@ -2,12 +2,20 @@
+ /*
+  * Timer present on EcoNet EN75xx MIPS based SoCs.
+  *
++ * This driver supports both:
++ * - EN751221: Single percpu IRQ mode (legacy interrupt controller)
++ * - EN7528/EN751627: Separate IRQ per CPU mode (GIC shared interrupts)
++ *
++ * The mode is auto-detected based on IRQ count in device tree.
++ *
+  * Copyright (C) 2025 by Caleb James DeLisle <[email protected]>
++ * Copyright (C) 2025 by Ahmed Naseef <[email protected]>
+  */
+ 
+ #include <linux/io.h>
+ #include <linux/cpumask.h>
+ #include <linux/interrupt.h>
++#include <linux/irq.h>
+ #include <linux/clockchips.h>
+ #include <linux/sched_clock.h>
+ #include <linux/of.h>
+@@ -21,10 +29,14 @@
+ #define ECONET_MAX_DELTA		GENMASK(ECONET_BITS - 2, 0)
+ /* 34Kc hardware has 1 block and 1004Kc has 2. */
+ #define ECONET_NUM_BLOCKS		DIV_ROUND_UP(NR_CPUS, 2)
++#define ECONET_MAX_IRQS			4
+ 
+ static struct {
+ 	void __iomem	*membase[ECONET_NUM_BLOCKS];
+ 	u32		freq_hz;
++	int		irqs[ECONET_MAX_IRQS];
++	int		num_irqs;
++	bool		use_percpu_irq;
+ } econet_timer __ro_after_init;
+ 
+ static DEFINE_PER_CPU(struct clock_event_device, econet_timer_pcpu);
+@@ -98,12 +110,21 @@ static int cevt_init_cpu(uint cpu)
+ 	struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, cpu);
+ 	u32 reg;
+ 
++	if (!econet_timer.use_percpu_irq && cpu >= econet_timer.num_irqs)
++		return -EINVAL;
++
+ 	pr_debug("%s: Setting up clockevent for CPU %d\n", cd->name, cpu);
+ 
+ 	reg = ioread32(reg_ctl(cpu)) | ctl_bit_enabled(cpu);
+ 	iowrite32(reg, reg_ctl(cpu));
+ 
+-	enable_percpu_irq(cd->irq, IRQ_TYPE_NONE);
++	if (econet_timer.use_percpu_irq) {
++		enable_percpu_irq(cd->irq, IRQ_TYPE_NONE);
++	} else {
++		if (irq_force_affinity(econet_timer.irqs[cpu], cpumask_of(cpu)))
++			pr_warn("%s: failed to set IRQ %d affinity to CPU %d\n",
++				cd->name, econet_timer.irqs[cpu], cpu);
++	}
+ 
+ 	/* Do this last because it synchronously configures the timer */
+ 	clockevents_config_and_register(cd, econet_timer.freq_hz,
+@@ -126,7 +147,21 @@ static void __init cevt_dev_init(uint cp
+ 	iowrite32(U32_MAX, reg_compare(cpu));
+ }
+ 
+-static int __init cevt_init(struct device_node *np)
++static void __init cevt_setup_clockevent(struct clock_event_device *cd,
++					 struct device_node *np,
++					 int irq, int cpu)
++{
++	cd->rating		= 310;
++	cd->features		= CLOCK_EVT_FEAT_ONESHOT |
++				  CLOCK_EVT_FEAT_C3STOP |
++				  CLOCK_EVT_FEAT_PERCPU;
++	cd->set_next_event	= cevt_set_next_event;
++	cd->irq			= irq;
++	cd->cpumask		= cpumask_of(cpu);
++	cd->name		= np->name;
++}
++
++static int __init cevt_init_percpu(struct device_node *np)
+ {
+ 	int i, irq, ret;
+ 
+@@ -137,42 +172,85 @@ static int __init cevt_init(struct devic
+ 	}
+ 
+ 	ret = request_percpu_irq(irq, cevt_interrupt, np->name, &econet_timer_pcpu);
+-
+ 	if (ret < 0) {
+ 		pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, irq, ret);
+-		goto err_unmap_irq;
++		irq_dispose_mapping(irq);
++		return ret;
+ 	}
+ 
+ 	for_each_possible_cpu(i) {
+ 		struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, i);
+ 
+-		cd->rating		= 310,
+-		cd->features		= CLOCK_EVT_FEAT_ONESHOT |
+-					  CLOCK_EVT_FEAT_C3STOP |
+-					  CLOCK_EVT_FEAT_PERCPU;
+-		cd->set_next_event	= cevt_set_next_event;
+-		cd->irq			= irq;
+-		cd->cpumask		= cpumask_of(i);
+-		cd->name		= np->name;
++		cevt_setup_clockevent(cd, np, irq, i);
++		cevt_dev_init(i);
++	}
++
++	return 0;
++}
++
++static int __init cevt_init_separate(struct device_node *np)
++{
++	int i, ret;
++
++	for (i = 0; i < econet_timer.num_irqs; i++) {
++		struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, i);
++
++		econet_timer.irqs[i] = irq_of_parse_and_map(np, i);
++		if (econet_timer.irqs[i] <= 0) {
++			pr_err("%pOFn: irq_of_parse_and_map failed", np);
++			ret = -EINVAL;
++			goto err_free_irqs;
++		}
++
++		ret = request_irq(econet_timer.irqs[i], cevt_interrupt,
++				  IRQF_TIMER | IRQF_NOBALANCING,
++				  np->name, NULL);
++		if (ret < 0) {
++			pr_err("%pOFn: IRQ %d setup failed (%d)\n", np,
++			       econet_timer.irqs[i], ret);
++			irq_dispose_mapping(econet_timer.irqs[i]);
++			goto err_free_irqs;
++		}
+ 
++		cevt_setup_clockevent(cd, np, econet_timer.irqs[i], i);
+ 		cevt_dev_init(i);
+ 	}
+ 
+-	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+-			  "clockevents/econet/timer:starting",
+-			  cevt_init_cpu, NULL);
+ 	return 0;
+ 
+-err_unmap_irq:
+-	irq_dispose_mapping(irq);
++err_free_irqs:
++	while (--i >= 0) {
++		free_irq(econet_timer.irqs[i], NULL);
++		irq_dispose_mapping(econet_timer.irqs[i]);
++	}
+ 	return ret;
+ }
+ 
++static int __init cevt_init(struct device_node *np)
++{
++	econet_timer.num_irqs = of_irq_count(np);
++	if (econet_timer.num_irqs <= 0 || econet_timer.num_irqs > ECONET_MAX_IRQS) {
++		pr_err("%pOFn: invalid IRQ count %d\n", np, econet_timer.num_irqs);
++		return -EINVAL;
++	}
++
++	/* Auto-detect mode based on IRQ count:
++	 * 1 IRQ = percpu mode (EN751221)
++	 * N IRQs = separate IRQ per CPU (EN7528/EN751627)
++	 */
++	econet_timer.use_percpu_irq = (econet_timer.num_irqs == 1);
++
++	if (econet_timer.use_percpu_irq)
++		return cevt_init_percpu(np);
++	else
++		return cevt_init_separate(np);
++}
++
+ static int __init timer_init(struct device_node *np)
+ {
+ 	int num_blocks = DIV_ROUND_UP(num_possible_cpus(), 2);
+ 	struct clk *clk;
+-	int ret;
++	int ret, i;
+ 
+ 	clk = of_clk_get(np, 0);
+ 	if (IS_ERR(clk)) {
+@@ -182,11 +260,12 @@ static int __init timer_init(struct devi
+ 
+ 	econet_timer.freq_hz = clk_get_rate(clk);
+ 
+-	for (int i = 0; i < num_blocks; i++) {
++	for (i = 0; i < num_blocks; i++) {
+ 		econet_timer.membase[i] = of_iomap(np, i);
+ 		if (!econet_timer.membase[i]) {
+ 			pr_err("%pOFn: failed to map register [%d]\n", np, i);
+-			return -ENXIO;
++			ret = -ENXIO;
++			goto err_unmap;
+ 		}
+ 	}
+ 
+@@ -196,21 +275,34 @@ static int __init timer_init(struct devi
+ 				    clocksource_mmio_readl_up);
+ 	if (ret) {
+ 		pr_err("%pOFn: clocksource_mmio_init failed: %d", np, ret);
+-		return ret;
++		goto err_unmap;
+ 	}
+ 
+ 	ret = cevt_init(np);
+ 	if (ret < 0)
+-		return ret;
++		goto err_unmap;
++
++	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
++			  "clockevents/econet/timer:starting",
++			  cevt_init_cpu, NULL);
+ 
+ 	sched_clock_register(sched_clock_read, ECONET_BITS,
+ 			     econet_timer.freq_hz);
+ 
+-	pr_info("%pOFn: using %u.%03u MHz high precision timer\n", np,
++	pr_info("%pOFn: using %u.%03u MHz high precision timer (%s mode)\n", np,
+ 		econet_timer.freq_hz / 1000000,
+-		(econet_timer.freq_hz / 1000) % 1000);
++		(econet_timer.freq_hz / 1000) % 1000,
++		econet_timer.use_percpu_irq ? "percpu" : "separate IRQ");
+ 
+ 	return 0;
++
++err_unmap:
++	for (i = 0; i < num_blocks; i++) {
++		if (econet_timer.membase[i])
++			iounmap(econet_timer.membase[i]);
++	}
++	return ret;
+ }
+ 
+-TIMER_OF_DECLARE(econet_timer_hpt, "econet,en751221-timer", timer_init);
++TIMER_OF_DECLARE(econet_en751221_timer, "econet,en751221-timer", timer_init);
++TIMER_OF_DECLARE(econet_en7528_timer, "econet,en7528-timer", timer_init);

+ 21 - 0
target/linux/econet/patches-6.12/303-spi-airoha-snfi-enable-for-econet.patch

@@ -0,0 +1,21 @@
+spi: airoha-snfi: enable for EcoNet EN7528
+
+Enable the Airoha SNFI (SPI NAND Flash Interface) driver for EcoNet
+EN7528 SoC. The EN7528 shares the same SPI controller and NFI DMA
+engine as the Airoha EN7523/EN7581, with identical register layouts.
+
+Using the DMA-capable SNFI driver provides significantly better
+performance compared to the manual mode spi-en7523 driver.
+
+Signed-off-by: Ahmed Naseef <[email protected]>
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -59,7 +59,7 @@ comment "SPI Master Controller Drivers"
+ 
+ config SPI_AIROHA_SNFI
+ 	tristate "Airoha SPI NAND Flash Interface"
+-	depends on ARCH_AIROHA || COMPILE_TEST
++	depends on ARCH_AIROHA || ECONET || COMPILE_TEST
+ 	depends on SPI_MASTER
+ 	select REGMAP_MMIO
+ 	help

+ 3 - 3
target/linux/econet/patches-6.12/310-usb-enable-econet-usb.patch

@@ -1,13 +1,13 @@
 --- a/arch/mips/Kconfig
 +++ b/arch/mips/Kconfig
-@@ -392,6 +392,7 @@ config ECONET
+@@ -391,6 +391,7 @@ config MACH_DECSTATION
+ config ECONET
  	bool "EcoNet MIPS family"
  	select BOOT_RAW
- 	select CPU_BIG_ENDIAN
 +	select DMA_NONCOHERENT
  	select DEBUG_ZBOOT if DEBUG_KERNEL
  	select EARLY_PRINTK_8250
- 	select ECONET_EN751221_TIMER
+ 	select SERIAL_8250
 --- a/drivers/usb/host/Kconfig
 +++ b/drivers/usb/host/Kconfig
 @@ -71,7 +71,7 @@ config USB_XHCI_HISTB

+ 206 - 0
target/linux/econet/patches-6.12/886-uart-add-en7523-support.patch

@@ -0,0 +1,206 @@
+--- /dev/null
++++ b/drivers/tty/serial/8250/8250_en7523.c
+@@ -0,0 +1,94 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Airoha EN7523 driver.
++ *
++ * Copyright (c) 2022 Genexis Sweden AB
++ * Author: Benjamin Larsson <[email protected]>
++ */
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/serial_8250.h>
++#include <linux/serial_reg.h>
++#include <linux/console.h>
++#include <linux/dma-mapping.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++
++#include "8250.h"
++
++
++/* The Airoha UART is 16550-compatible except for the baud rate calculation.
++ *
++ * crystal_clock = 20 MHz
++ * xindiv_clock = crystal_clock / clock_div
++ * (x/y) = XYD, 32 bit register with 16 bits of x and and then 16 bits of y
++ * clock_div = XINCLK_DIVCNT (default set to 10 (0x4)),
++ *           - 3 bit register [ 1, 2, 4, 8, 10, 12, 16, 20 ]
++ *
++ * baud_rate = ((xindiv_clock) * (x/y)) / ([BRDH,BRDL] * 16)
++ *
++ * XYD_y seems to need to be larger then XYD_x for things to work.
++ * Setting [BRDH,BRDL] to [0,1] and XYD_y to 65000 give even values
++ * for usual baud rates.
++ *
++ * Selecting divider needs to fulfill
++ * 1.8432 MHz <= xindiv_clk <= APB clock / 2
++ * The clocks are unknown but a divider of value 1 did not work.
++ *
++ * Optimally the XYD, BRD and XINCLK_DIVCNT registers could be searched to
++ * find values that gives the least error for every baud rate. But searching
++ * the space takes time and in practise only a few rates are of interest.
++ * With some value combinations not working a tested subset is used giving
++ * a usable range from 110 to 460800 baud.
++ */
++
++#define CLOCK_DIV_TAB_ELEMS 3
++#define XYD_Y 65000
++#define XINDIV_CLOCK 20000000
++#define UART_BRDL_20M 0x01
++#define UART_BRDH_20M 0x00
++
++static int clock_div_tab[] = { 10, 4, 2};
++static int clock_div_reg[] = {  4, 2, 1};
++
++
++int en7523_set_uart_baud_rate (struct uart_port *port, unsigned int baud)
++{
++	struct uart_8250_port *up = up_to_u8250p(port);
++	unsigned int xyd_x, nom, denom;
++	int i;
++
++	/* set DLAB to access the baud rate divider registers (BRDH, BRDL) */
++	serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
++
++	/* set baud rate calculation defaults */
++
++	/* set BRDIV ([BRDH,BRDL]) to 1 */
++	serial_port_out(port, UART_BRDL, UART_BRDL_20M);
++	serial_port_out(port, UART_BRDH, UART_BRDH_20M);
++
++	/* calculate XYD_x and XINCLKDR register */
++
++	for (i = 0 ; i < CLOCK_DIV_TAB_ELEMS ; i++) {
++		denom = (XINDIV_CLOCK/40) / clock_div_tab[i];
++		nom = (baud * (XYD_Y/40));
++		xyd_x = ((nom/denom) << 4);
++		if (xyd_x < XYD_Y) break;
++	}
++
++	serial_port_out(port, UART_XINCLKDR, clock_div_reg[i]);
++	serial_port_out(port, UART_XYD, (xyd_x<<16) | XYD_Y);
++
++	/* unset DLAB */
++	serial_port_out(port, UART_LCR, up->lcr);
++
++	return 0;
++}
++
++EXPORT_SYMBOL_GPL(en7523_set_uart_baud_rate);
+--- a/drivers/tty/serial/8250/8250_of.c
++++ b/drivers/tty/serial/8250/8250_of.c
+@@ -341,6 +341,7 @@ static const struct of_device_id of_plat
+ 	{ .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, },
+ 	{ .compatible = "nuvoton,wpcm450-uart", .data = (void *)PORT_NPCM, },
+ 	{ .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, },
++	{ .compatible = "airoha,en7523-uart", .data = (void *)PORT_AIROHA, },
+ 	{ /* end of list */ },
+ };
+ MODULE_DEVICE_TABLE(of, of_platform_serial_table);
+--- a/drivers/tty/serial/8250/8250_port.c
++++ b/drivers/tty/serial/8250/8250_port.c
+@@ -319,6 +319,14 @@ static const struct serial8250_config ua
+ 		.rxtrig_bytes	= {1, 8, 16, 30},
+ 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
+ 	},
++	[PORT_AIROHA] = {
++		.name		= "Airoha 16550",
++		.fifo_size	= 8,
++		.tx_loadsz	= 1,
++		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
++		.rxtrig_bytes	= {1, 4},
++		.flags		= UART_CAP_FIFO,
++	},
+ };
+ 
+ /* Uart divisor latch read */
+@@ -2835,6 +2843,12 @@ serial8250_do_set_termios(struct uart_po
+ 
+ 	serial8250_set_divisor(port, baud, quot, frac);
+ 
++#ifdef CONFIG_SERIAL_8250_AIROHA
++	/* Airoha SoCs have custom registers for baud rate settings */
++	if (port->type == PORT_AIROHA)
++		en7523_set_uart_baud_rate(port, baud);
++#endif
++
+ 	/*
+ 	 * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
+ 	 * is written without DLAB set, this mode will be disabled.
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -355,6 +355,16 @@ config SERIAL_8250_ACORN
+ 	  system, say Y to this option.  The driver can handle 1, 2, or 3 port
+ 	  cards.  If unsure, say N.
+ 
++config SERIAL_8250_AIROHA
++	tristate "Airoha UART support"
++	depends on (ARCH_AIROHA || COMPILE_TEST) && OF && SERIAL_8250
++	help
++	  Selecting this option enables an Airoha SoC specific baud rate
++	  calculation routine on an otherwise 16550 compatible UART hardware.
++
++	  If you have an Airoha based board and want to use the serial port,
++	  say Y to this option. If unsure, say N.
++
+ config SERIAL_8250_BCM2835AUX
+ 	tristate "BCM2835 auxiliar mini UART support"
+ 	depends on ARCH_BCM2835 || COMPILE_TEST
+--- a/drivers/tty/serial/8250/Makefile
++++ b/drivers/tty/serial/8250/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_8250_CONSOLE)	+= 825
+ 
+ obj-$(CONFIG_SERIAL_8250_ACCENT)	+= 8250_accent.o
+ obj-$(CONFIG_SERIAL_8250_ACORN)		+= 8250_acorn.o
++obj-$(CONFIG_SERIAL_8250_AIROHA) 	+= 8250_en7523.o
+ obj-$(CONFIG_SERIAL_8250_ASPEED_VUART)	+= 8250_aspeed_vuart.o
+ obj-$(CONFIG_SERIAL_8250_BCM2835AUX)	+= 8250_bcm2835aux.o
+ obj-$(CONFIG_SERIAL_8250_BCM7271)	+= 8250_bcm7271.o
+--- a/include/uapi/linux/serial_reg.h
++++ b/include/uapi/linux/serial_reg.h
+@@ -383,5 +383,17 @@
+ #define UART_ALTR_EN_TXFIFO_LW	0x01	/* Enable the TX FIFO Low Watermark */
+ #define UART_ALTR_TX_LOW	0x41	/* Tx FIFO Low Watermark */
+ 
++/*
++ * These are definitions for the Airoha EN75XX uart registers
++ * Normalized because of 32 bits registers.
++ */
++#define UART_BRDL		0
++#define UART_BRDH		1
++#define UART_XINCLKDR		10
++#define UART_XYD		11
++#define UART_TXLVLCNT		12
++#define UART_RXLVLCNT		13
++#define UART_FINTLVL		14
++
+ #endif /* _LINUX_SERIAL_REG_H */
+ 
+--- a/include/uapi/linux/serial_core.h
++++ b/include/uapi/linux/serial_core.h
+@@ -31,6 +31,7 @@
+ #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
+ #define PORT_RT2880	29	/* Ralink RT2880 internal UART */
+ #define PORT_16550A_FSL64 30	/* Freescale 16550 UART with 64 FIFOs */
++#define PORT_AIROHA    31	/* Airoha 16550 UART */
+ 
+ /*
+  * ARM specific type numbers.  These are not currently guaranteed
+--- a/include/linux/serial_8250.h
++++ b/include/linux/serial_8250.h
+@@ -195,6 +195,7 @@ void serial8250_do_set_mctrl(struct uart
+ void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
+ 			       unsigned int quot);
+ int fsl8250_handle_irq(struct uart_port *port);
++int en7523_set_uart_baud_rate(struct uart_port *port, unsigned int baud);
+ int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
+ u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr);
+ void serial8250_read_char(struct uart_8250_port *up, u16 lsr);

+ 18 - 0
target/linux/econet/patches-6.12/887-uart-airoha-add-econet-support.patch

@@ -0,0 +1,18 @@
+serial: 8250: airoha: add EcoNet platform support
+
+The EcoNet EN75xx SoCs use the same UART IP core as the Airoha
+AN7523 SoCs. Add ECONET to the Kconfig dependency to enable
+the Airoha UART driver for EcoNet platforms.
+
+Signed-off-by: Ahmed Naseef <[email protected]>
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -357,7 +357,7 @@ config SERIAL_8250_ACORN
+ 
+ config SERIAL_8250_AIROHA
+ 	tristate "Airoha UART support"
+-	depends on (ARCH_AIROHA || COMPILE_TEST) && OF && SERIAL_8250
++	depends on (ARCH_AIROHA || ECONET || COMPILE_TEST) && OF && SERIAL_8250
+ 	help
+ 	  Selecting this option enables an Airoha SoC specific baud rate
+ 	  calculation routine on an otherwise 16550 compatible UART hardware.