From: Ahmed Naseef Date: Mon, 29 Dec 2025 09:12:20 +0000 (+0400) Subject: econet: add EN7528 subtarget support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fab098cb6121647ca9cc6e501d56ebe8a9ea550b;p=thirdparty%2Fopenwrt.git 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 Link: https://github.com/openwrt/openwrt/pull/21326 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/econet/Makefile b/target/linux/econet/Makefile index 28b8ab33adb..f3e8af3945c 100644 --- a/target/linux/econet/Makefile +++ b/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 diff --git a/target/linux/econet/dts/en7528.dtsi b/target/linux/econet/dts/en7528.dtsi new file mode 100644 index 00000000000..78eab98ed81 --- /dev/null +++ b/target/linux/econet/dts/en7528.dtsi @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +#include + +/ { + 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 = , + , + , + ; + + 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 = ; + + clock-frequency = <7372800>; + }; +}; diff --git a/target/linux/econet/dts/en7528_generic.dts b/target/linux/econet/dts/en7528_generic.dts new file mode 100644 index 00000000000..2a3835eb2b1 --- /dev/null +++ b/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>; + }; + }; +}; diff --git a/target/linux/econet/en751221/config-6.12 b/target/linux/econet/en751221/config-6.12 index b8a52c0f9d9..e9137a0e9fc 100644 --- a/target/linux/econet/en751221/config-6.12 +++ b/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 diff --git a/target/linux/econet/en751221/target.mk b/target/linux/econet/en751221/target.mk index e54fb3e6f62..823ffde7cf9 100644 --- a/target/linux/econet/en751221/target.mk +++ b/target/linux/econet/en751221/target.mk @@ -1,3 +1,4 @@ +ARCH:=mips BOARDNAME:=en751221 CPU_TYPE:=24kc KERNELNAME:=vmlinuz.bin diff --git a/target/linux/econet/en7528/config-6.12 b/target/linux/econet/en7528/config-6.12 new file mode 100644 index 00000000000..c956eb06494 --- /dev/null +++ b/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 diff --git a/target/linux/econet/en7528/profiles/00-default.mk b/target/linux/econet/en7528/profiles/00-default.mk new file mode 100644 index 00000000000..83888590616 --- /dev/null +++ b/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)) diff --git a/target/linux/econet/en7528/target.mk b/target/linux/econet/en7528/target.mk new file mode 100644 index 00000000000..1f174f70ed8 --- /dev/null +++ b/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 diff --git a/target/linux/econet/image/en7528.mk b/target/linux/econet/image/en7528.mk new file mode 100644 index 00000000000..1bd8cb58d87 --- /dev/null +++ b/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 diff --git a/target/linux/econet/patches-6.12/100-econet-add-en7528-soc.patch b/target/linux/econet/patches-6.12/100-econet-add-en7528-soc.patch new file mode 100644 index 00000000000..f11c6d329dc --- /dev/null +++ b/target/linux/econet/patches-6.12/100-econet-add-en7528-soc.patch @@ -0,0 +1,119 @@ +From: Ahmed Naseef +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 +--- 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 + #include + #include ++#include + + #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 + diff --git a/target/linux/econet/patches-6.12/101-econet-timer-add-en7528-support.patch b/target/linux/econet/patches-6.12/101-econet-timer-add-en7528-support.patch new file mode 100644 index 00000000000..3d864145914 --- /dev/null +++ b/target/linux/econet/patches-6.12/101-econet-timer-add-en7528-support.patch @@ -0,0 +1,264 @@ +From: Ahmed Naseef +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 +--- 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 ++ * Copyright (C) 2025 by Ahmed Naseef + */ + + #include + #include + #include ++#include + #include + #include + #include +@@ -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); diff --git a/target/linux/econet/patches-6.12/303-spi-airoha-snfi-enable-for-econet.patch b/target/linux/econet/patches-6.12/303-spi-airoha-snfi-enable-for-econet.patch new file mode 100644 index 00000000000..8556633d01c --- /dev/null +++ b/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 +--- 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 diff --git a/target/linux/econet/patches-6.12/310-usb-enable-econet-usb.patch b/target/linux/econet/patches-6.12/310-usb-enable-econet-usb.patch index 15deffaa0cb..39ed0c43f54 100644 --- a/target/linux/econet/patches-6.12/310-usb-enable-econet-usb.patch +++ b/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 diff --git a/target/linux/econet/patches-6.12/886-uart-add-en7523-support.patch b/target/linux/econet/patches-6.12/886-uart-add-en7523-support.patch new file mode 100644 index 00000000000..cad2a715d95 --- /dev/null +++ b/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 ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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); diff --git a/target/linux/econet/patches-6.12/887-uart-airoha-add-econet-support.patch b/target/linux/econet/patches-6.12/887-uart-airoha-add-econet-support.patch new file mode 100644 index 00000000000..b25d02e9690 --- /dev/null +++ b/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 +--- 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.