From: Ahmed Naseef Date: Thu, 11 Jun 2026 13:05:21 +0000 (+0400) Subject: kernel/econet: restore files for v6.12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0619a10834bb73956f1a2bf8bc296a8efd43a1db;p=thirdparty%2Fopenwrt.git kernel/econet: restore files for v6.12 This is an automatically generated commit which aids following Kernel patch history, as git will see the move and copy as a rename thus defeating the purpose. For the original discussion see: https://lists.openwrt.org/pipermail/openwrt-devel/2023-October/041673.html Signed-off-by: Ahmed Naseef Link: https://github.com/openwrt/openwrt/pull/23755 Signed-off-by: Jonas Jelonek --- diff --git a/target/linux/econet/en751221/config-6.12 b/target/linux/econet/en751221/config-6.12 new file mode 100644 index 00000000000..fe69f10c74b --- /dev/null +++ b/target/linux/econet/en751221/config-6.12 @@ -0,0 +1,209 @@ +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_KEEP_MEMBLOCK=y +CONFIG_ARCH_MMAP_RND_BITS_MAX=15 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15 +CONFIG_BLK_MQ_PCI=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_EN7523=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=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_R1 is not set +CONFIG_CPU_MIPS32_R2=y +CONFIG_CPU_MIPSR2=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_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_DTB_ECONET_SMARTFIBER_XP8421_B is not set +CONFIG_DTC=y +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_8250=y +CONFIG_ECONET=y +CONFIG_ECONET_EN751221_INTC=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_MSI_IRQ=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIO_CDEV=y +# CONFIG_GPIO_EN7523 is not set +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=y +CONFIG_JFFS2_ZLIB=y +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_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_MIPS_CMDLINE_FROM_DTB=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 +# CONFIG_MIPS_NO_APPENDED_DTB is not set +CONFIG_MIPS_NR_CPU_NR_MAP=2 +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_NR_CPUS=2 +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=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_DRIVERS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHY_EN7528_PCIE=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_RANDSTRUCT_NONE=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +# CONFIG_SERIAL_8250_AIROHA is not set +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=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 +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_LITTLE_ENDIAN=y +CONFIG_SYS_SUPPORTS_MIPS16=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_USB_SUPPORT=y +CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y +CONFIG_USE_OF=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/en751627/config-6.12 b/target/linux/econet/en751627/config-6.12 new file mode 100644 index 00000000000..5e7b280d720 --- /dev/null +++ b/target/linux/econet/en751627/config-6.12 @@ -0,0 +1,239 @@ +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_BLK_MQ_PCI=y +CONFIG_BOARD_SCACHE=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_EN7523=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=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_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_ALLOCATOR=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_MSI_IRQ=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_EN7523=y +CONFIG_GPIO_GENERIC=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_LEDS_GPIO=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MFD_SYSCON=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_NLS=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=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_DRIVERS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHY_EN7528_PCIE=y +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_RESET_CONTROLLER=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_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +# CONFIG_USB_XHCI_PLATFORM is not set +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/config-6.12 b/target/linux/econet/en7528/config-6.12 new file mode 100644 index 00000000000..f5778340282 --- /dev/null +++ b/target/linux/econet/en7528/config-6.12 @@ -0,0 +1,241 @@ +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_BLK_MQ_PCI=y +CONFIG_BOARD_SCACHE=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_EN7523=y +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_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_ALLOCATOR=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_MSI_IRQ=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_EN7523=y +CONFIG_GPIO_GENERIC=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_LEDS_GPIO=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MFD_SYSCON=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_NLS=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=y +CONFIG_PCIE_MEDIATEK=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_DRIVERS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_ARCH_FALLBACKS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHY_EN7528_PCIE=y +CONFIG_PHY_EN7528_USB=y +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_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_RESET_CONTROLLER=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_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +# CONFIG_USB_XHCI_PLATFORM is not set +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/patches-6.12/001-v6.16-dt-bindings-interrupt-controller-Add-EcoNet-EN751221.patch b/target/linux/econet/patches-6.12/001-v6.16-dt-bindings-interrupt-controller-Add-EcoNet-EN751221.patch new file mode 100644 index 00000000000..c146af679ac --- /dev/null +++ b/target/linux/econet/patches-6.12/001-v6.16-dt-bindings-interrupt-controller-Add-EcoNet-EN751221.patch @@ -0,0 +1,98 @@ +From 9773c540441c6ae15aefb49e67142e94369dbbc0 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Sun, 30 Mar 2025 17:02:58 +0000 +Subject: [PATCH] dt-bindings: interrupt-controller: Add EcoNet EN751221 INTC + +Document the device tree binding for the interrupt controller in the +EcoNet EN751221 MIPS SoC. + +Signed-off-by: Caleb James DeLisle +Signed-off-by: Thomas Gleixner +Reviewed-by: Rob Herring (Arm) +Link: https://lore.kernel.org/all/20250330170306.2584136-3-cjd@cjdns.fr +--- + .../econet,en751221-intc.yaml | 78 +++++++++++++++++++ + 1 file changed, 78 insertions(+) + create mode 100644 Documentation/devicetree/bindings/interrupt-controller/econet,en751221-intc.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/interrupt-controller/econet,en751221-intc.yaml +@@ -0,0 +1,78 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/interrupt-controller/econet,en751221-intc.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: EcoNet EN751221 Interrupt Controller ++ ++maintainers: ++ - Caleb James DeLisle ++ ++description: ++ The EcoNet EN751221 Interrupt Controller is a simple interrupt controller ++ designed for the MIPS 34Kc MT SMP processor with 2 VPEs. Each interrupt can ++ be routed to either VPE but not both, so to support per-CPU interrupts, a ++ secondary IRQ number is allocated to control masking/unmasking on VPE#1. For ++ lack of a better term we call these "shadow interrupts". The assignment of ++ shadow interrupts is defined by the SoC integrator when wiring the interrupt ++ lines, so they are configurable in the device tree. ++ ++allOf: ++ - $ref: /schemas/interrupt-controller.yaml# ++ ++properties: ++ compatible: ++ const: econet,en751221-intc ++ ++ reg: ++ maxItems: 1 ++ ++ "#interrupt-cells": ++ const: 1 ++ ++ interrupt-controller: true ++ ++ interrupts: ++ maxItems: 1 ++ description: Interrupt line connecting this controller to its parent. ++ ++ econet,shadow-interrupts: ++ $ref: /schemas/types.yaml#/definitions/uint32-matrix ++ description: ++ An array of interrupt number pairs where each pair represents a shadow ++ interrupt relationship. The first number in each pair is the primary IRQ, ++ and the second is its shadow IRQ used for VPE#1 control. For example, ++ <8 3> means IRQ 8 is shadowed by IRQ 3, so IRQ 3 cannot be mapped, but ++ when VPE#1 requests IRQ 8, it will manipulate the IRQ 3 mask bit. ++ minItems: 1 ++ maxItems: 20 ++ items: ++ items: ++ - description: primary per-CPU IRQ ++ - description: shadow IRQ number ++ ++required: ++ - compatible ++ - reg ++ - interrupt-controller ++ - "#interrupt-cells" ++ - interrupts ++ ++additionalProperties: false ++ ++examples: ++ - | ++ interrupt-controller@1fb40000 { ++ compatible = "econet,en751221-intc"; ++ reg = <0x1fb40000 0x100>; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ ++ interrupt-parent = <&cpuintc>; ++ interrupts = <2>; ++ ++ econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>; ++ }; ++... diff --git a/target/linux/econet/patches-6.12/002-v6.16-irqchip-Add-EcoNet-EN751221-INTC.patch b/target/linux/econet/patches-6.12/002-v6.16-irqchip-Add-EcoNet-EN751221-INTC.patch new file mode 100644 index 00000000000..d3f57f4e7fb --- /dev/null +++ b/target/linux/econet/patches-6.12/002-v6.16-irqchip-Add-EcoNet-EN751221-INTC.patch @@ -0,0 +1,353 @@ +From 1902a59cf5f9d8b99ecf0cb8f122cb00ef7a3f13 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Sun, 30 Mar 2025 17:02:59 +0000 +Subject: [PATCH] irqchip: Add EcoNet EN751221 INTC + +Add a driver for the interrupt controller in the EcoNet EN751221 MIPS SoC. + +Signed-off-by: Caleb James DeLisle +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/20250330170306.2584136-4-cjd@cjdns.fr +--- + drivers/irqchip/Kconfig | 5 + + drivers/irqchip/Makefile | 1 + + drivers/irqchip/irq-econet-en751221.c | 309 ++++++++++++++++++++++++++ + 3 files changed, 315 insertions(+) + create mode 100644 drivers/irqchip/irq-econet-en751221.c + +--- a/drivers/irqchip/Kconfig ++++ b/drivers/irqchip/Kconfig +@@ -148,6 +148,11 @@ config DW_APB_ICTL + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN_HIERARCHY + ++config ECONET_EN751221_INTC ++ bool ++ select GENERIC_IRQ_CHIP ++ select IRQ_DOMAIN ++ + config FARADAY_FTINTC010 + bool + select IRQ_DOMAIN +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_ARCH_BCM2835) += irq-bcm28 + obj-$(CONFIG_ARCH_ACTIONS) += irq-owl-sirq.o + obj-$(CONFIG_DAVINCI_CP_INTC) += irq-davinci-cp-intc.o + obj-$(CONFIG_EXYNOS_IRQ_COMBINER) += exynos-combiner.o ++obj-$(CONFIG_ECONET_EN751221_INTC) += irq-econet-en751221.o + obj-$(CONFIG_FARADAY_FTINTC010) += irq-ftintc010.o + obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o + obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o +--- /dev/null ++++ b/drivers/irqchip/irq-econet-en751221.c +@@ -0,0 +1,309 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * EN751221 Interrupt Controller Driver. ++ * ++ * The EcoNet EN751221 Interrupt Controller is a simple interrupt controller ++ * designed for the MIPS 34Kc MT SMP processor with 2 VPEs. Each interrupt can ++ * be routed to either VPE but not both, so to support per-CPU interrupts, a ++ * secondary IRQ number is allocated to control masking/unmasking on VPE#1. In ++ * this driver, these are called "shadow interrupts". The assignment of shadow ++ * interrupts is defined by the SoC integrator when wiring the interrupt lines, ++ * so they are configurable in the device tree. ++ * ++ * If an interrupt (say 30) needs per-CPU capability, the SoC integrator ++ * allocates another IRQ number (say 29) to be its shadow. The device tree ++ * reflects this by adding the pair <30 29> to the "econet,shadow-interrupts" ++ * property. ++ * ++ * When VPE#1 requests IRQ 30, the driver manipulates the mask bit for IRQ 29, ++ * telling the hardware to mask VPE#1's view of IRQ 30. ++ * ++ * Copyright (C) 2025 Caleb James DeLisle ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IRQ_COUNT 40 ++ ++#define NOT_PERCPU 0xff ++#define IS_SHADOW 0xfe ++ ++#define REG_MASK0 0x04 ++#define REG_MASK1 0x50 ++#define REG_PENDING0 0x08 ++#define REG_PENDING1 0x54 ++ ++/** ++ * @membase: Base address of the interrupt controller registers ++ * @interrupt_shadows: Array of all interrupts, for each value, ++ * - NOT_PERCPU: This interrupt is not per-cpu, so it has no shadow ++ * - IS_SHADOW: This interrupt is a shadow of another per-cpu interrupt ++ * - else: This is a per-cpu interrupt whose shadow is the value ++ */ ++static struct { ++ void __iomem *membase; ++ u8 interrupt_shadows[IRQ_COUNT]; ++} econet_intc __ro_after_init; ++ ++static DEFINE_RAW_SPINLOCK(irq_lock); ++ ++/* IRQs must be disabled */ ++static void econet_wreg(u32 reg, u32 val, u32 mask) ++{ ++ u32 v; ++ ++ guard(raw_spinlock)(&irq_lock); ++ ++ v = ioread32(econet_intc.membase + reg); ++ v &= ~mask; ++ v |= val & mask; ++ iowrite32(v, econet_intc.membase + reg); ++} ++ ++/* IRQs must be disabled */ ++static void econet_chmask(u32 hwirq, bool unmask) ++{ ++ u32 reg, mask; ++ u8 shadow; ++ ++ /* ++ * If the IRQ is a shadow, it should never be manipulated directly. ++ * It should only be masked/unmasked as a result of the "real" per-cpu ++ * irq being manipulated by a thread running on VPE#1. ++ * If it is per-cpu (has a shadow), and we're on VPE#1, the shadow is what we mask. ++ * This is single processor only, so smp_processor_id() never exceeds 1. ++ */ ++ shadow = econet_intc.interrupt_shadows[hwirq]; ++ if (WARN_ON_ONCE(shadow == IS_SHADOW)) ++ return; ++ else if (shadow != NOT_PERCPU && smp_processor_id() == 1) ++ hwirq = shadow; ++ ++ if (hwirq >= 32) { ++ reg = REG_MASK1; ++ mask = BIT(hwirq - 32); ++ } else { ++ reg = REG_MASK0; ++ mask = BIT(hwirq); ++ } ++ ++ econet_wreg(reg, unmask ? mask : 0, mask); ++} ++ ++/* IRQs must be disabled */ ++static void econet_intc_mask(struct irq_data *d) ++{ ++ econet_chmask(d->hwirq, false); ++} ++ ++/* IRQs must be disabled */ ++static void econet_intc_unmask(struct irq_data *d) ++{ ++ econet_chmask(d->hwirq, true); ++} ++ ++static void econet_mask_all(void) ++{ ++ /* IRQs are generally disabled during init, but guarding here makes it non-obligatory. */ ++ guard(irqsave)(); ++ econet_wreg(REG_MASK0, 0, ~0); ++ econet_wreg(REG_MASK1, 0, ~0); ++} ++ ++static void econet_intc_handle_pending(struct irq_domain *d, u32 pending, u32 offset) ++{ ++ int hwirq; ++ ++ while (pending) { ++ hwirq = fls(pending) - 1; ++ generic_handle_domain_irq(d, hwirq + offset); ++ pending &= ~BIT(hwirq); ++ } ++} ++ ++static void econet_intc_from_parent(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ struct irq_domain *domain; ++ u32 pending0, pending1; ++ ++ chained_irq_enter(chip, desc); ++ ++ pending0 = ioread32(econet_intc.membase + REG_PENDING0); ++ pending1 = ioread32(econet_intc.membase + REG_PENDING1); ++ ++ if (unlikely(!(pending0 | pending1))) { ++ spurious_interrupt(); ++ } else { ++ domain = irq_desc_get_handler_data(desc); ++ econet_intc_handle_pending(domain, pending0, 0); ++ econet_intc_handle_pending(domain, pending1, 32); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static const struct irq_chip econet_irq_chip; ++ ++static int econet_intc_map(struct irq_domain *d, u32 irq, irq_hw_number_t hwirq) ++{ ++ int ret; ++ ++ if (hwirq >= IRQ_COUNT) { ++ pr_err("%s: hwirq %lu out of range\n", __func__, hwirq); ++ return -EINVAL; ++ } else if (econet_intc.interrupt_shadows[hwirq] == IS_SHADOW) { ++ pr_err("%s: can't map hwirq %lu, it is a shadow interrupt\n", __func__, hwirq); ++ return -EINVAL; ++ } ++ ++ if (econet_intc.interrupt_shadows[hwirq] == NOT_PERCPU) { ++ irq_set_chip_and_handler(irq, &econet_irq_chip, handle_level_irq); ++ } else { ++ irq_set_chip_and_handler(irq, &econet_irq_chip, handle_percpu_devid_irq); ++ ret = irq_set_percpu_devid(irq); ++ if (ret) ++ pr_warn("%s: Failed irq_set_percpu_devid for %u: %d\n", d->name, irq, ret); ++ } ++ ++ irq_set_chip_data(irq, NULL); ++ return 0; ++} ++ ++static const struct irq_chip econet_irq_chip = { ++ .name = "en751221-intc", ++ .irq_unmask = econet_intc_unmask, ++ .irq_mask = econet_intc_mask, ++ .irq_mask_ack = econet_intc_mask, ++}; ++ ++static const struct irq_domain_ops econet_domain_ops = { ++ .xlate = irq_domain_xlate_onecell, ++ .map = econet_intc_map ++}; ++ ++static int __init get_shadow_interrupts(struct device_node *node) ++{ ++ const char *field = "econet,shadow-interrupts"; ++ int num_shadows; ++ ++ num_shadows = of_property_count_u32_elems(node, field); ++ ++ memset(econet_intc.interrupt_shadows, NOT_PERCPU, ++ sizeof(econet_intc.interrupt_shadows)); ++ ++ if (num_shadows <= 0) { ++ return 0; ++ } else if (num_shadows % 2) { ++ pr_err("%pOF: %s count is odd, ignoring\n", node, field); ++ return 0; ++ } ++ ++ u32 *shadows __free(kfree) = kmalloc_array(num_shadows, sizeof(u32), GFP_KERNEL); ++ if (!shadows) ++ return -ENOMEM; ++ ++ if (of_property_read_u32_array(node, field, shadows, num_shadows)) { ++ pr_err("%pOF: Failed to read %s\n", node, field); ++ return -EINVAL; ++ } ++ ++ for (int i = 0; i < num_shadows; i += 2) { ++ u32 shadow = shadows[i + 1]; ++ u32 target = shadows[i]; ++ ++ if (shadow > IRQ_COUNT) { ++ pr_err("%pOF: %s[%d] shadow(%d) out of range\n", ++ node, field, i + 1, shadow); ++ continue; ++ } ++ ++ if (target >= IRQ_COUNT) { ++ pr_err("%pOF: %s[%d] target(%d) out of range\n", node, field, i, target); ++ continue; ++ } ++ ++ if (econet_intc.interrupt_shadows[target] != NOT_PERCPU) { ++ pr_err("%pOF: %s[%d] target(%d) already has a shadow\n", ++ node, field, i, target); ++ continue; ++ } ++ ++ if (econet_intc.interrupt_shadows[shadow] != NOT_PERCPU) { ++ pr_err("%pOF: %s[%d] shadow(%d) already has a target\n", ++ node, field, i + 1, shadow); ++ continue; ++ } ++ ++ econet_intc.interrupt_shadows[target] = shadow; ++ econet_intc.interrupt_shadows[shadow] = IS_SHADOW; ++ } ++ ++ return 0; ++} ++ ++static int __init econet_intc_of_init(struct device_node *node, struct device_node *parent) ++{ ++ struct irq_domain *domain; ++ struct resource res; ++ int ret, irq; ++ ++ ret = get_shadow_interrupts(node); ++ if (ret) ++ return ret; ++ ++ irq = irq_of_parse_and_map(node, 0); ++ if (!irq) { ++ pr_err("%pOF: DT: Failed to get IRQ from 'interrupts'\n", node); ++ return -EINVAL; ++ } ++ ++ if (of_address_to_resource(node, 0, &res)) { ++ pr_err("%pOF: DT: Failed to get 'reg'\n", node); ++ ret = -EINVAL; ++ goto err_dispose_mapping; ++ } ++ ++ if (!request_mem_region(res.start, resource_size(&res), res.name)) { ++ pr_err("%pOF: Failed to request memory\n", node); ++ ret = -EBUSY; ++ goto err_dispose_mapping; ++ } ++ ++ econet_intc.membase = ioremap(res.start, resource_size(&res)); ++ if (!econet_intc.membase) { ++ pr_err("%pOF: Failed to remap membase\n", node); ++ ret = -ENOMEM; ++ goto err_release; ++ } ++ ++ econet_mask_all(); ++ ++ domain = irq_domain_add_linear(node, IRQ_COUNT, &econet_domain_ops, NULL); ++ if (!domain) { ++ pr_err("%pOF: Failed to add irqdomain\n", node); ++ ret = -ENOMEM; ++ goto err_unmap; ++ } ++ ++ irq_set_chained_handler_and_data(irq, econet_intc_from_parent, domain); ++ ++ return 0; ++ ++err_unmap: ++ iounmap(econet_intc.membase); ++err_release: ++ release_mem_region(res.start, resource_size(&res)); ++err_dispose_mapping: ++ irq_dispose_mapping(irq); ++ return ret; ++} ++ ++IRQCHIP_DECLARE(econet_en751221_intc, "econet,en751221-intc", econet_intc_of_init); diff --git a/target/linux/econet/patches-6.12/003-v6.16-dt-bindings-vendor-prefixes-Add-EcoNet.patch b/target/linux/econet/patches-6.12/003-v6.16-dt-bindings-vendor-prefixes-Add-EcoNet.patch new file mode 100644 index 00000000000..e2466782d14 --- /dev/null +++ b/target/linux/econet/patches-6.12/003-v6.16-dt-bindings-vendor-prefixes-Add-EcoNet.patch @@ -0,0 +1,26 @@ +From 9e0dd98654a528735d2b363d0dc73f7904108652 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Sun, 30 Mar 2025 17:02:57 +0000 +Subject: [PATCH] dt-bindings: vendor-prefixes: Add EcoNet + +Add the "econet" vendor prefix for SoC maker + +Signed-off-by: Caleb James DeLisle +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20250330170306.2584136-2-cjd@cjdns.fr +Signed-off-by: Rob Herring (Arm) +--- + Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -420,6 +420,8 @@ patternProperties: + description: EBV Elektronik + "^eckelmann,.*": + description: Eckelmann AG ++ "^econet,.*": ++ description: EcoNet (HK) Limited + "^edgeble,.*": + description: Edgeble AI Technologies Pvt. Ltd. + "^edimax,.*": diff --git a/target/linux/econet/patches-6.12/004-v6.16-dt-bindings-timer-Add-EcoNet-EN751221-HPT-CPU-Timer.patch b/target/linux/econet/patches-6.12/004-v6.16-dt-bindings-timer-Add-EcoNet-EN751221-HPT-CPU-Timer.patch new file mode 100644 index 00000000000..92f8604ea2c --- /dev/null +++ b/target/linux/econet/patches-6.12/004-v6.16-dt-bindings-timer-Add-EcoNet-EN751221-HPT-CPU-Timer.patch @@ -0,0 +1,100 @@ +From 30fddbd5325459102e448c9a26a1bc15ef563381 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:54 +0000 +Subject: [PATCH] dt-bindings: timer: Add EcoNet EN751221 "HPT" CPU Timer + +Add device tree bindings for the so-called high-precision timer (HPT) +in the EcoNet EN751221 SoC. + +Signed-off-by: Caleb James DeLisle +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20250507134500.390547-2-cjd@cjdns.fr +Signed-off-by: Daniel Lezcano +--- + .../bindings/timer/econet,en751221-timer.yaml | 80 +++++++++++++++++++ + 1 file changed, 80 insertions(+) + create mode 100644 Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml +@@ -0,0 +1,80 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/timer/econet,en751221-timer.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: EcoNet EN751221 High Precision Timer (HPT) ++ ++maintainers: ++ - Caleb James DeLisle ++ ++description: ++ The EcoNet High Precision Timer (HPT) is a timer peripheral found in various ++ EcoNet SoCs, including the EN751221 and EN751627 families. It provides per-VPE ++ count/compare registers and a per-CPU control register, with a single interrupt ++ line using a percpu-devid interrupt mechanism. ++ ++properties: ++ compatible: ++ oneOf: ++ - const: econet,en751221-timer ++ - items: ++ - const: econet,en751627-timer ++ - const: econet,en751221-timer ++ ++ reg: ++ minItems: 1 ++ maxItems: 2 ++ ++ interrupts: ++ maxItems: 1 ++ description: A percpu-devid timer interrupt shared across CPUs. ++ ++ clocks: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ ++allOf: ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: econet,en751627-timer ++ then: ++ properties: ++ reg: ++ items: ++ - description: VPE timers 0 and 1 ++ - description: VPE timers 2 and 3 ++ else: ++ properties: ++ reg: ++ items: ++ - description: VPE timers 0 and 1 ++ ++additionalProperties: false ++ ++examples: ++ - | ++ timer@1fbf0400 { ++ compatible = "econet,en751627-timer", "econet,en751221-timer"; ++ reg = <0x1fbf0400 0x100>, <0x1fbe0000 0x100>; ++ interrupt-parent = <&intc>; ++ interrupts = <30>; ++ clocks = <&hpt_clock>; ++ }; ++ - | ++ timer@1fbf0400 { ++ compatible = "econet,en751221-timer"; ++ reg = <0x1fbe0400 0x100>; ++ interrupt-parent = <&intc>; ++ interrupts = <30>; ++ clocks = <&hpt_clock>; ++ }; ++... diff --git a/target/linux/econet/patches-6.12/005-v6.16-clocksource-drivers-Add-EcoNet-Timer-HPT-driver.patch b/target/linux/econet/patches-6.12/005-v6.16-clocksource-drivers-Add-EcoNet-Timer-HPT-driver.patch new file mode 100644 index 00000000000..dcd4bb15e33 --- /dev/null +++ b/target/linux/econet/patches-6.12/005-v6.16-clocksource-drivers-Add-EcoNet-Timer-HPT-driver.patch @@ -0,0 +1,276 @@ +From 3b4c33ac87d0d11308f4445ecec2a124e2e77724 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:55 +0000 +Subject: [PATCH] clocksource/drivers: Add EcoNet Timer HPT driver + +Introduce a clocksource driver for the so-called high-precision timer (HPT) +in the EcoNet EN751221 and EN751627 MIPS SoCs. + +It's a 32 bit upward-counting one-shot timer which relies on the crystal so it +is unaffected by CPU power mode. On MIPS 34K devices (single core) there is +one timer, and on 1004K devices (dual core) there are two. + +Each timer has two sets of count/compare registers so that there is one for +each of the VPEs on the core. Because each core has 2 VPEs, register selection +takes the CPU number / 2 for the timer corrisponding to the core, then CPU +number % 2 for the register corrisponding to the VPE. + +These timers use a percpu-devid IRQ to route interrupts to the VPE which set +the event. + +Signed-off-by: Caleb James DeLisle +Link: https://lore.kernel.org/r/20250507134500.390547-3-cjd@cjdns.fr +Signed-off-by: Daniel Lezcano +--- + drivers/clocksource/Kconfig | 8 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-econet-en751221.c | 216 ++++++++++++++++++++ + 3 files changed, 225 insertions(+) + create mode 100644 drivers/clocksource/timer-econet-en751221.c + +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -73,6 +73,14 @@ config DW_APB_TIMER_OF + select DW_APB_TIMER + select TIMER_OF + ++config ECONET_EN751221_TIMER ++ bool "EcoNet EN751221 High Precision Timer" if COMPILE_TEST ++ depends on HAS_IOMEM ++ select CLKSRC_MMIO ++ select TIMER_OF ++ help ++ Support for CPU timer found on EcoNet MIPS based SoCs. ++ + config FTTMR010_TIMER + bool "Faraday Technology timer driver" if COMPILE_TEST + depends on HAS_IOMEM +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_CLKBLD_I8253) += i8253.o + obj-$(CONFIG_CLKSRC_MMIO) += mmio.o + obj-$(CONFIG_DAVINCI_TIMER) += timer-davinci.o + obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o ++obj-$(CONFIG_ECONET_EN751221_TIMER) += timer-econet-en751221.o + obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o + obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o + obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o +--- /dev/null ++++ b/drivers/clocksource/timer-econet-en751221.c +@@ -0,0 +1,216 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Timer present on EcoNet EN75xx MIPS based SoCs. ++ * ++ * Copyright (C) 2025 by Caleb James DeLisle ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ECONET_BITS 32 ++#define ECONET_MIN_DELTA 0x00001000 ++#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) ++ ++static struct { ++ void __iomem *membase[ECONET_NUM_BLOCKS]; ++ u32 freq_hz; ++} econet_timer __ro_after_init; ++ ++static DEFINE_PER_CPU(struct clock_event_device, econet_timer_pcpu); ++ ++/* Each memory block has 2 timers, the order of registers is: ++ * CTL, CMR0, CNT0, CMR1, CNT1 ++ */ ++static inline void __iomem *reg_ctl(u32 timer_n) ++{ ++ return econet_timer.membase[timer_n >> 1]; ++} ++ ++static inline void __iomem *reg_compare(u32 timer_n) ++{ ++ return econet_timer.membase[timer_n >> 1] + (timer_n & 1) * 0x08 + 0x04; ++} ++ ++static inline void __iomem *reg_count(u32 timer_n) ++{ ++ return econet_timer.membase[timer_n >> 1] + (timer_n & 1) * 0x08 + 0x08; ++} ++ ++static inline u32 ctl_bit_enabled(u32 timer_n) ++{ ++ return 1U << (timer_n & 1); ++} ++ ++static inline u32 ctl_bit_pending(u32 timer_n) ++{ ++ return 1U << ((timer_n & 1) + 16); ++} ++ ++static bool cevt_is_pending(int cpu_id) ++{ ++ return ioread32(reg_ctl(cpu_id)) & ctl_bit_pending(cpu_id); ++} ++ ++static irqreturn_t cevt_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *dev = this_cpu_ptr(&econet_timer_pcpu); ++ int cpu = cpumask_first(dev->cpumask); ++ ++ /* Each VPE has its own events, ++ * so this will only happen on spurious interrupt. ++ */ ++ if (!cevt_is_pending(cpu)) ++ return IRQ_NONE; ++ ++ iowrite32(ioread32(reg_count(cpu)), reg_compare(cpu)); ++ dev->event_handler(dev); ++ return IRQ_HANDLED; ++} ++ ++static int cevt_set_next_event(ulong delta, struct clock_event_device *dev) ++{ ++ u32 next; ++ int cpu; ++ ++ cpu = cpumask_first(dev->cpumask); ++ next = ioread32(reg_count(cpu)) + delta; ++ iowrite32(next, reg_compare(cpu)); ++ ++ if ((s32)(next - ioread32(reg_count(cpu))) < ECONET_MIN_DELTA / 2) ++ return -ETIME; ++ ++ return 0; ++} ++ ++static int cevt_init_cpu(uint cpu) ++{ ++ struct clock_event_device *cd = &per_cpu(econet_timer_pcpu, cpu); ++ u32 reg; ++ ++ 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); ++ ++ /* Do this last because it synchronously configures the timer */ ++ clockevents_config_and_register(cd, econet_timer.freq_hz, ++ ECONET_MIN_DELTA, ECONET_MAX_DELTA); ++ ++ return 0; ++} ++ ++static u64 notrace sched_clock_read(void) ++{ ++ /* Always read from clock zero no matter the CPU */ ++ return (u64)ioread32(reg_count(0)); ++} ++ ++/* Init */ ++ ++static void __init cevt_dev_init(uint cpu) ++{ ++ iowrite32(0, reg_count(cpu)); ++ iowrite32(U32_MAX, reg_compare(cpu)); ++} ++ ++static int __init cevt_init(struct device_node *np) ++{ ++ int i, irq, ret; ++ ++ irq = irq_of_parse_and_map(np, 0); ++ if (irq <= 0) { ++ pr_err("%pOFn: irq_of_parse_and_map failed", np); ++ return -EINVAL; ++ } ++ ++ 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; ++ } ++ ++ 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_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); ++ return ret; ++} ++ ++static int __init timer_init(struct device_node *np) ++{ ++ int num_blocks = DIV_ROUND_UP(num_possible_cpus(), 2); ++ struct clk *clk; ++ int ret; ++ ++ clk = of_clk_get(np, 0); ++ if (IS_ERR(clk)) { ++ pr_err("%pOFn: Failed to get CPU clock from DT %ld\n", np, PTR_ERR(clk)); ++ return PTR_ERR(clk); ++ } ++ ++ econet_timer.freq_hz = clk_get_rate(clk); ++ ++ for (int 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; ++ } ++ } ++ ++ /* For clocksource purposes always read clock zero, whatever the CPU */ ++ ret = clocksource_mmio_init(reg_count(0), np->name, ++ econet_timer.freq_hz, 301, ECONET_BITS, ++ clocksource_mmio_readl_up); ++ if (ret) { ++ pr_err("%pOFn: clocksource_mmio_init failed: %d", np, ret); ++ return ret; ++ } ++ ++ ret = cevt_init(np); ++ if (ret < 0) ++ return ret; ++ ++ sched_clock_register(sched_clock_read, ECONET_BITS, ++ econet_timer.freq_hz); ++ ++ pr_info("%pOFn: using %u.%03u MHz high precision timer\n", np, ++ econet_timer.freq_hz / 1000000, ++ (econet_timer.freq_hz / 1000) % 1000); ++ ++ return 0; ++} ++ ++TIMER_OF_DECLARE(econet_timer_hpt, "econet,en751221-timer", timer_init); diff --git a/target/linux/econet/patches-6.12/006-v6.16-dt-bindings-mips-Add-EcoNet-platform-binding.patch b/target/linux/econet/patches-6.12/006-v6.16-dt-bindings-mips-Add-EcoNet-platform-binding.patch new file mode 100644 index 00000000000..64714dc8a2e --- /dev/null +++ b/target/linux/econet/patches-6.12/006-v6.16-dt-bindings-mips-Add-EcoNet-platform-binding.patch @@ -0,0 +1,44 @@ +From be8b4173719a61fdd8379e86895d855775cf5f91 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:56 +0000 +Subject: [PATCH] dt-bindings: mips: Add EcoNet platform binding + +Document the top-level device tree binding for EcoNet MIPS-based SoCs. + +Signed-off-by: Caleb James DeLisle +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Thomas Bogendoerfer +--- + .../devicetree/bindings/mips/econet.yaml | 26 +++++++++++++++++++ + 1 file changed, 26 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mips/econet.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mips/econet.yaml +@@ -0,0 +1,26 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mips/econet.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: EcoNet MIPS SoCs ++ ++maintainers: ++ - Caleb James DeLisle ++ ++properties: ++ $nodename: ++ const: '/' ++ ++ compatible: ++ oneOf: ++ - description: Boards with EcoNet EN751221 family SoC ++ items: ++ - enum: ++ - smartfiber,xp8421-b ++ - const: econet,en751221 ++ ++additionalProperties: true ++ ++... diff --git a/target/linux/econet/patches-6.12/007-v6.16-mips-Add-EcoNet-MIPS-platform-support.patch b/target/linux/econet/patches-6.12/007-v6.16-mips-Add-EcoNet-MIPS-platform-support.patch new file mode 100644 index 00000000000..86b05b07a1c --- /dev/null +++ b/target/linux/econet/patches-6.12/007-v6.16-mips-Add-EcoNet-MIPS-platform-support.patch @@ -0,0 +1,222 @@ +From 35fb26f94dfa1b291086b84b2421f957214824d1 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:57 +0000 +Subject: [PATCH] mips: Add EcoNet MIPS platform support + +Add platform support for EcoNet MIPS SoCs. + +Signed-off-by: Caleb James DeLisle +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/Kbuild.platforms | 1 + + arch/mips/Kconfig | 25 +++++++++ + arch/mips/boot/compressed/uart-16550.c | 5 ++ + arch/mips/econet/Kconfig | 37 ++++++++++++ + arch/mips/econet/Makefile | 2 + + arch/mips/econet/Platform | 5 ++ + arch/mips/econet/init.c | 78 ++++++++++++++++++++++++++ + 7 files changed, 153 insertions(+) + create mode 100644 arch/mips/econet/Kconfig + create mode 100644 arch/mips/econet/Makefile + create mode 100644 arch/mips/econet/Platform + create mode 100644 arch/mips/econet/init.c + +--- a/arch/mips/Kbuild.platforms ++++ b/arch/mips/Kbuild.platforms +@@ -11,6 +11,7 @@ platform-$(CONFIG_CAVIUM_OCTEON_SOC) += + platform-$(CONFIG_EYEQ) += mobileye/ + platform-$(CONFIG_MIPS_COBALT) += cobalt/ + platform-$(CONFIG_MACH_DECSTATION) += dec/ ++platform-$(CONFIG_ECONET) += econet/ + platform-$(CONFIG_MIPS_GENERIC) += generic/ + platform-$(CONFIG_MACH_JAZZ) += jazz/ + platform-$(CONFIG_LANTIQ) += lantiq/ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -388,6 +388,30 @@ config MACH_DECSTATION + + otherwise choose R3000. + ++config ECONET ++ bool "EcoNet MIPS family" ++ select BOOT_RAW ++ select CPU_BIG_ENDIAN ++ select DEBUG_ZBOOT ++ select EARLY_PRINTK_8250 ++ select ECONET_EN751221_TIMER ++ select SERIAL_OF_PLATFORM ++ select SYS_SUPPORTS_BIG_ENDIAN ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_HAS_EARLY_PRINTK ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_MIPS16 ++ select SYS_SUPPORTS_ZBOOT_UART16550 ++ select USE_GENERIC_EARLY_PRINTK_8250 ++ select USE_OF ++ help ++ EcoNet EN75xx MIPS devices are big endian MIPS machines used ++ in XPON (fiber) and DSL applications. They have SPI, PCI, USB, ++ GPIO, and Ethernet, with optional XPON, DSL, and VoIP DSP cores. ++ Don't confuse these with the Airoha ARM devices sometimes referred ++ to as "EcoNet", this family is for MIPS based devices only. ++ + config MACH_JAZZ + bool "Jazz family of machines" + select ARC_MEMORY +@@ -1017,6 +1041,7 @@ source "arch/mips/ath79/Kconfig" + source "arch/mips/bcm47xx/Kconfig" + source "arch/mips/bcm63xx/Kconfig" + source "arch/mips/bmips/Kconfig" ++source "arch/mips/econet/Kconfig" + source "arch/mips/generic/Kconfig" + source "arch/mips/ingenic/Kconfig" + source "arch/mips/jazz/Kconfig" +--- a/arch/mips/boot/compressed/uart-16550.c ++++ b/arch/mips/boot/compressed/uart-16550.c +@@ -20,6 +20,11 @@ + #define PORT(offset) (CKSEG1ADDR(INGENIC_UART_BASE_ADDR) + (4 * offset)) + #endif + ++#ifdef CONFIG_ECONET ++#define EN75_UART_BASE 0x1fbf0003 ++#define PORT(offset) (CKSEG1ADDR(EN75_UART_BASE) + (4 * (offset))) ++#endif ++ + #ifndef IOTYPE + #define IOTYPE char + #endif +--- /dev/null ++++ b/arch/mips/econet/Kconfig +@@ -0,0 +1,37 @@ ++# SPDX-License-Identifier: GPL-2.0 ++if ECONET ++ ++choice ++ prompt "EcoNet SoC selection" ++ default SOC_ECONET_EN751221 ++ help ++ Select EcoNet MIPS SoC type. Individual SoCs within a family are ++ very similar, so is it enough to select the right family, and ++ then customize to the specific SoC using the device tree only. ++ ++ config SOC_ECONET_EN751221 ++ bool "EN751221 family" ++ select COMMON_CLK ++ select ECONET_EN751221_INTC ++ select IRQ_MIPS_CPU ++ select SMP ++ select SMP_UP ++ select SYS_SUPPORTS_SMP ++ help ++ The EN751221 family includes EN7512, RN7513, EN7521, EN7526. ++ 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. ++endchoice ++ ++choice ++ prompt "Devicetree selection" ++ default DTB_ECONET_NONE ++ help ++ Select the devicetree. ++ ++ config DTB_ECONET_NONE ++ bool "None" ++endchoice ++ ++endif +--- /dev/null ++++ b/arch/mips/econet/Makefile +@@ -0,0 +1,2 @@ ++ ++obj-y := init.o +--- /dev/null ++++ b/arch/mips/econet/Platform +@@ -0,0 +1,5 @@ ++# To address a 7.2MB kernel size limit in the EcoNet SDK bootloader, ++# we put the load address well above where the bootloader loads and then use ++# zboot. So please set CONFIG_ZBOOT_LOAD_ADDRESS to the address where your ++# bootloader actually places the kernel. ++load-$(CONFIG_ECONET) += 0xffffffff81000000 +--- /dev/null ++++ b/arch/mips/econet/init.c +@@ -0,0 +1,78 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * EcoNet setup code ++ * ++ * Copyright (C) 2025 Caleb James DeLisle ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CR_AHB_RSTCR ((void __iomem *)CKSEG1ADDR(0x1fb00040)) ++#define RESET BIT(31) ++ ++#define UART_BASE CKSEG1ADDR(0x1fbf0003) ++#define UART_REG_SHIFT 2 ++ ++static void hw_reset(char *command) ++{ ++ iowrite32(RESET, CR_AHB_RSTCR); ++} ++ ++/* 1. Bring up early printk. */ ++void __init prom_init(void) ++{ ++ setup_8250_early_printk_port(UART_BASE, UART_REG_SHIFT, 0); ++ _machine_restart = hw_reset; ++} ++ ++/* 2. Parse the DT and find memory */ ++void __init plat_mem_setup(void) ++{ ++ void *dtb; ++ ++ set_io_port_base(KSEG1); ++ ++ dtb = get_fdt(); ++ if (!dtb) ++ panic("no dtb found"); ++ ++ __dt_setup_arch(dtb); ++ ++ early_init_dt_scan_memory(); ++} ++ ++/* 3. Overload __weak device_tree_init(), add SMP_UP ops */ ++void __init device_tree_init(void) ++{ ++ unflatten_and_copy_device_tree(); ++ ++ register_up_smp_ops(); ++} ++ ++const char *get_system_type(void) ++{ ++ return "EcoNet-EN75xx"; ++} ++ ++/* 4. Initialize the IRQ subsystem */ ++void __init arch_init_irq(void) ++{ ++ irqchip_init(); ++} ++ ++/* 5. Timers */ ++void __init plat_time_init(void) ++{ ++ of_clk_init(NULL); ++ timer_probe(); ++} diff --git a/target/linux/econet/patches-6.12/008-v6.16-dt-bindings-vendor-prefixes-Add-SmartFiber.patch b/target/linux/econet/patches-6.12/008-v6.16-dt-bindings-vendor-prefixes-Add-SmartFiber.patch new file mode 100644 index 00000000000..6d51af02310 --- /dev/null +++ b/target/linux/econet/patches-6.12/008-v6.16-dt-bindings-vendor-prefixes-Add-SmartFiber.patch @@ -0,0 +1,29 @@ +From abc2d0bc2cb7c1412b8b254c0446f94b3e203c7c Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:58 +0000 +Subject: [PATCH] dt-bindings: vendor-prefixes: Add SmartFiber +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add "smartfiber" vendor prefix for manufactorer of EcoNet based boards. + +Signed-off-by: Caleb James DeLisle +Acked-by: Krzysztof Kozlowski +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Bogendoerfer +--- + Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml ++++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml +@@ -1370,6 +1370,8 @@ patternProperties: + description: SKOV A/S + "^skyworks,.*": + description: Skyworks Solutions, Inc. ++ "^smartfiber,.*": ++ description: ShenZhen Smartfiber Technology Co, Ltd. + "^smartlabs,.*": + description: SmartLabs LLC + "^smartrg,.*": diff --git a/target/linux/econet/patches-6.12/009-v6.16-mips-dts-Add-EcoNet-DTS-with-EN751221-and-SmartFiber.patch b/target/linux/econet/patches-6.12/009-v6.16-mips-dts-Add-EcoNet-DTS-with-EN751221-and-SmartFiber.patch new file mode 100644 index 00000000000..cb5b4571372 --- /dev/null +++ b/target/linux/econet/patches-6.12/009-v6.16-mips-dts-Add-EcoNet-DTS-with-EN751221-and-SmartFiber.patch @@ -0,0 +1,149 @@ +From 0ec4887009729297f7c10368084e41a8a9fbbd0e Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:44:59 +0000 +Subject: [PATCH] mips: dts: Add EcoNet DTS with EN751221 and SmartFiber + XP8421-B board + +Add DTS files in support of EcoNet platform, including SmartFiber XP8421-B, +a low cost commercially available board based on EN751221. + +Signed-off-by: Caleb James DeLisle +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/boot/dts/Makefile | 1 + + arch/mips/boot/dts/econet/Makefile | 2 + + arch/mips/boot/dts/econet/en751221.dtsi | 67 +++++++++++++++++++ + .../econet/en751221_smartfiber_xp8421-b.dts | 19 ++++++ + arch/mips/econet/Kconfig | 11 +++ + 5 files changed, 100 insertions(+) + create mode 100644 arch/mips/boot/dts/econet/Makefile + create mode 100644 arch/mips/boot/dts/econet/en751221.dtsi + create mode 100644 arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts + +--- a/arch/mips/boot/dts/Makefile ++++ b/arch/mips/boot/dts/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + subdir-$(CONFIG_BMIPS_GENERIC) += brcm + subdir-$(CONFIG_CAVIUM_OCTEON_SOC) += cavium-octeon ++subdir-$(CONFIG_ECONET) += econet + subdir-$(CONFIG_EYEQ) += mobileye + subdir-$(CONFIG_FIT_IMAGE_FDT_MARDUK) += img + subdir-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += img +--- /dev/null ++++ b/arch/mips/boot/dts/econet/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_DTB_ECONET_SMARTFIBER_XP8421_B) += en751221_smartfiber_xp8421-b.dtb +--- /dev/null ++++ b/arch/mips/boot/dts/econet/en751221.dtsi +@@ -0,0 +1,67 @@ ++// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++/dts-v1/; ++ ++/ { ++ compatible = "econet,en751221"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ hpt_clock: clock { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <200000000>; /* 200 MHz */ ++ }; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "mips,mips24KEc"; ++ reg = <0>; ++ }; ++ }; ++ ++ cpuintc: interrupt-controller { ++ compatible = "mti,cpu-interrupt-controller"; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ ++ intc: interrupt-controller@1fb40000 { ++ compatible = "econet,en751221-intc"; ++ reg = <0x1fb40000 0x100>; ++ interrupt-parent = <&cpuintc>; ++ interrupts = <2>; ++ ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ econet,shadow-interrupts = <7 2>, <8 3>, <13 12>, <30 29>; ++ }; ++ ++ uart: serial@1fbf0000 { ++ compatible = "ns16550"; ++ reg = <0x1fbf0000 0x30>; ++ reg-io-width = <4>; ++ reg-shift = <2>; ++ interrupt-parent = <&intc>; ++ interrupts = <0>; ++ /* ++ * Conversion of baud rate to clock frequency requires a ++ * computation that is not in the ns16550 driver, so this ++ * uart is fixed at 115200 baud. ++ */ ++ clock-frequency = <1843200>; ++ }; ++ ++ timer_hpt: timer@1fbf0400 { ++ compatible = "econet,en751221-timer"; ++ reg = <0x1fbf0400 0x100>; ++ ++ interrupt-parent = <&intc>; ++ interrupts = <30>; ++ clocks = <&hpt_clock>; ++ }; ++}; +--- /dev/null ++++ b/arch/mips/boot/dts/econet/en751221_smartfiber_xp8421-b.dts +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++/dts-v1/; ++ ++#include "en751221.dtsi" ++ ++/ { ++ model = "SmartFiber XP8421-B"; ++ compatible = "smartfiber,xp8421-b", "econet,en751221"; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x00000000 0x1c000000>; ++ }; ++ ++ chosen { ++ stdout-path = "/serial@1fbf0000:115200"; ++ linux,usable-memory-range = <0x00020000 0x1bfe0000>; ++ }; ++}; +--- a/arch/mips/econet/Kconfig ++++ b/arch/mips/econet/Kconfig +@@ -32,6 +32,17 @@ choice + + config DTB_ECONET_NONE + bool "None" ++ ++ config DTB_ECONET_SMARTFIBER_XP8421_B ++ bool "EN751221 SmartFiber XP8421-B" ++ depends on SOC_ECONET_EN751221 ++ select BUILTIN_DTB ++ help ++ The SmartFiber XP8421-B is a device based on the EN751221 SoC. ++ It has 512MB of memory and 256MB of NAND flash. This kernel ++ needs only an appended initramfs to boot. It can be loaded ++ through XMODEM and booted from memory in the bootloader, or ++ it can be packed in tclinux.trx format and written to flash. + endchoice + + endif diff --git a/target/linux/econet/patches-6.12/010-v6.16-MAINTAINERS-Add-entry-for-newly-added-EcoNet-platfor.patch b/target/linux/econet/patches-6.12/010-v6.16-MAINTAINERS-Add-entry-for-newly-added-EcoNet-platfor.patch new file mode 100644 index 00000000000..e4230573c29 --- /dev/null +++ b/target/linux/econet/patches-6.12/010-v6.16-MAINTAINERS-Add-entry-for-newly-added-EcoNet-platfor.patch @@ -0,0 +1,38 @@ +From faefb0a59c5914b7b8f737e2ec5c82822e5bc4c7 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 7 May 2025 13:45:00 +0000 +Subject: [PATCH] MAINTAINERS: Add entry for newly added EcoNet platform. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a MAINTAINERS entry as part of integration of the EcoNet MIPS platform. + +Signed-off-by: Caleb James DeLisle +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Thomas Bogendoerfer +--- + MAINTAINERS | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -8025,6 +8025,18 @@ W: https://linuxtv.org + Q: http://patchwork.linuxtv.org/project/linux-media/list/ + F: drivers/media/dvb-frontends/ec100* + ++ECONET MIPS PLATFORM ++M: Caleb James DeLisle ++L: linux-mips@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/interrupt-controller/econet,en751221-intc.yaml ++F: Documentation/devicetree/bindings/mips/econet.yaml ++F: Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml ++F: arch/mips/boot/dts/econet/ ++F: arch/mips/econet/ ++F: drivers/clocksource/timer-econet-en751221.c ++F: drivers/irqchip/irq-econet-en751221.c ++ + ECRYPT FILE SYSTEM + M: Tyler Hicks + L: ecryptfs@vger.kernel.org diff --git a/target/linux/econet/patches-6.12/011-v6.16-mips-econet-Fix-incorrect-Kconfig-dependencies.patch b/target/linux/econet/patches-6.12/011-v6.16-mips-econet-Fix-incorrect-Kconfig-dependencies.patch new file mode 100644 index 00000000000..fe9e6792eb7 --- /dev/null +++ b/target/linux/econet/patches-6.12/011-v6.16-mips-econet-Fix-incorrect-Kconfig-dependencies.patch @@ -0,0 +1,32 @@ +From 79ee1d20e37cd553cc961962fca8107e69a0c293 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 21 May 2025 21:33:33 +0000 +Subject: [PATCH] mips: econet: Fix incorrect Kconfig dependencies + +config ECONET selects SERIAL_OF_PLATFORM and that depends on SERIAL_8250 +so we need to select SERIAL_8250 directly. +Also do not enable DEBUG_ZBOOT unless DEBUG_KERNEL is set. + +Signed-off-by: Caleb James DeLisle +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202505211654.CBdIsoTq-lkp@intel.com/ +Closes: https://lore.kernel.org/oe-kbuild-all/202505211451.WRjyf3a9-lkp@intel.com/ +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -392,9 +392,10 @@ config ECONET + bool "EcoNet MIPS family" + select BOOT_RAW + select CPU_BIG_ENDIAN +- select DEBUG_ZBOOT ++ 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_HAS_CPU_MIPS32_R1 diff --git a/target/linux/econet/patches-6.12/012-v6.13-clk-en7523-move-en7581_reset_register-in-en7581_clk_.patch b/target/linux/econet/patches-6.12/012-v6.13-clk-en7523-move-en7581_reset_register-in-en7581_clk_.patch new file mode 100644 index 00000000000..26b3da9c4d9 --- /dev/null +++ b/target/linux/econet/patches-6.12/012-v6.13-clk-en7523-move-en7581_reset_register-in-en7581_clk_.patch @@ -0,0 +1,174 @@ +From 82e6bf912d5846646892becea659b39d178d79e3 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 12 Nov 2024 01:08:53 +0100 +Subject: [PATCH 5/8] clk: en7523: move en7581_reset_register() in + en7581_clk_hw_init() + +Move en7581_reset_register routine in en7581_clk_hw_init() since reset +feature is supported just by EN7581 SoC. +Get rid of reset struct in en_clk_soc_data data struct. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/20241112-clk-en7581-syscon-v2-6-8ada5e394ae4@kernel.org +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 93 ++++++++++++++-------------------------- + 1 file changed, 33 insertions(+), 60 deletions(-) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -76,11 +76,6 @@ struct en_rst_data { + + struct en_clk_soc_data { + const struct clk_ops pcie_ops; +- struct { +- const u16 *bank_ofs; +- const u16 *idx_map; +- u16 idx_map_nr; +- } reset; + int (*hw_init)(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data); + }; +@@ -596,32 +591,6 @@ static void en7581_register_clocks(struc + clk_data->num = EN7523_NUM_CLOCKS; + } + +-static int en7581_clk_hw_init(struct platform_device *pdev, +- struct clk_hw_onecell_data *clk_data) +-{ +- void __iomem *np_base; +- struct regmap *map; +- u32 val; +- +- map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); +- if (IS_ERR(map)) +- return PTR_ERR(map); +- +- np_base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(np_base)) +- return PTR_ERR(np_base); +- +- en7581_register_clocks(&pdev->dev, clk_data, map, np_base); +- +- val = readl(np_base + REG_NP_SCU_SSTR); +- val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK); +- writel(val, np_base + REG_NP_SCU_SSTR); +- val = readl(np_base + REG_NP_SCU_PCIC); +- writel(val | 3, np_base + REG_NP_SCU_PCIC); +- +- return 0; +-} +- + static int en7523_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) + { +@@ -671,23 +640,18 @@ static int en7523_reset_xlate(struct res + return rst_data->idx_map[reset_spec->args[0]]; + } + +-static const struct reset_control_ops en7523_reset_ops = { ++static const struct reset_control_ops en7581_reset_ops = { + .assert = en7523_reset_assert, + .deassert = en7523_reset_deassert, + .status = en7523_reset_status, + }; + +-static int en7523_reset_register(struct platform_device *pdev, +- const struct en_clk_soc_data *soc_data) ++static int en7581_reset_register(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct en_rst_data *rst_data; + void __iomem *base; + +- /* no reset lines available */ +- if (!soc_data->reset.idx_map_nr) +- return 0; +- + base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(base)) + return PTR_ERR(base); +@@ -696,13 +660,13 @@ static int en7523_reset_register(struct + if (!rst_data) + return -ENOMEM; + +- rst_data->bank_ofs = soc_data->reset.bank_ofs; +- rst_data->idx_map = soc_data->reset.idx_map; ++ rst_data->bank_ofs = en7581_rst_ofs; ++ rst_data->idx_map = en7581_rst_map; + rst_data->base = base; + +- rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr; ++ rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map); + rst_data->rcdev.of_xlate = en7523_reset_xlate; +- rst_data->rcdev.ops = &en7523_reset_ops; ++ rst_data->rcdev.ops = &en7581_reset_ops; + rst_data->rcdev.of_node = dev->of_node; + rst_data->rcdev.of_reset_n_cells = 1; + rst_data->rcdev.owner = THIS_MODULE; +@@ -711,6 +675,32 @@ static int en7523_reset_register(struct + return devm_reset_controller_register(dev, &rst_data->rcdev); + } + ++static int en7581_clk_hw_init(struct platform_device *pdev, ++ struct clk_hw_onecell_data *clk_data) ++{ ++ void __iomem *np_base; ++ struct regmap *map; ++ u32 val; ++ ++ map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); ++ ++ np_base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(np_base)) ++ return PTR_ERR(np_base); ++ ++ en7581_register_clocks(&pdev->dev, clk_data, map, np_base); ++ ++ val = readl(np_base + REG_NP_SCU_SSTR); ++ val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK); ++ writel(val, np_base + REG_NP_SCU_SSTR); ++ val = readl(np_base + REG_NP_SCU_PCIC); ++ writel(val | 3, np_base + REG_NP_SCU_PCIC); ++ ++ return en7581_reset_register(pdev); ++} ++ + static int en7523_clk_probe(struct platform_device *pdev) + { + struct device_node *node = pdev->dev.of_node; +@@ -729,19 +719,7 @@ static int en7523_clk_probe(struct platf + if (r) + return r; + +- r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); +- if (r) +- return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n", +- pdev->name); +- +- r = en7523_reset_register(pdev, soc_data); +- if (r) { +- of_clk_del_provider(node); +- return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n", +- pdev->name); +- } +- +- return 0; ++ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + } + + static const struct en_clk_soc_data en7523_data = { +@@ -759,11 +737,6 @@ static const struct en_clk_soc_data en75 + .enable = en7581_pci_enable, + .disable = en7581_pci_disable, + }, +- .reset = { +- .bank_ofs = en7581_rst_ofs, +- .idx_map = en7581_rst_map, +- .idx_map_nr = ARRAY_SIZE(en7581_rst_map), +- }, + .hw_init = en7581_clk_hw_init, + }; + diff --git a/target/linux/econet/patches-6.12/013-v6.13-clk-en7523-map-io-region-in-a-single-block.patch b/target/linux/econet/patches-6.12/013-v6.13-clk-en7523-map-io-region-in-a-single-block.patch new file mode 100644 index 00000000000..4e4952d8a6d --- /dev/null +++ b/target/linux/econet/patches-6.12/013-v6.13-clk-en7523-map-io-region-in-a-single-block.patch @@ -0,0 +1,84 @@ +From a9eaf305017a5ebe73ab34e85bd5414055a88f29 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 12 Nov 2024 01:08:54 +0100 +Subject: [PATCH 6/8] clk: en7523: map io region in a single block + +Map all clock-controller memory region in a single block. +This patch does not introduce any backward incompatibility since the dts +for EN7581 SoC is not upstream yet. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/20241112-clk-en7581-syscon-v2-7-8ada5e394ae4@kernel.org +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 32 +++++++++++++------------------- + 1 file changed, 13 insertions(+), 19 deletions(-) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -39,8 +39,8 @@ + #define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11) + #define REG_CRYPTO_CLKSRC2 0x20c + +-#define REG_RST_CTRL2 0x00 +-#define REG_RST_CTRL1 0x04 ++#define REG_RST_CTRL2 0x830 ++#define REG_RST_CTRL1 0x834 + + struct en_clk_desc { + int id; +@@ -646,15 +646,9 @@ static const struct reset_control_ops en + .status = en7523_reset_status, + }; + +-static int en7581_reset_register(struct platform_device *pdev) ++static int en7581_reset_register(struct device *dev, void __iomem *base) + { +- struct device *dev = &pdev->dev; + struct en_rst_data *rst_data; +- void __iomem *base; +- +- base = devm_platform_ioremap_resource(pdev, 1); +- if (IS_ERR(base)) +- return PTR_ERR(base); + + rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL); + if (!rst_data) +@@ -678,27 +672,27 @@ static int en7581_reset_register(struct + static int en7581_clk_hw_init(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data) + { +- void __iomem *np_base; + struct regmap *map; ++ void __iomem *base; + u32 val; + + map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); + if (IS_ERR(map)) + return PTR_ERR(map); + +- np_base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(np_base)) +- return PTR_ERR(np_base); ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); + +- en7581_register_clocks(&pdev->dev, clk_data, map, np_base); ++ en7581_register_clocks(&pdev->dev, clk_data, map, base); + +- val = readl(np_base + REG_NP_SCU_SSTR); ++ val = readl(base + REG_NP_SCU_SSTR); + val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK); +- writel(val, np_base + REG_NP_SCU_SSTR); +- val = readl(np_base + REG_NP_SCU_PCIC); +- writel(val | 3, np_base + REG_NP_SCU_PCIC); ++ writel(val, base + REG_NP_SCU_SSTR); ++ val = readl(base + REG_NP_SCU_PCIC); ++ writel(val | 3, base + REG_NP_SCU_PCIC); + +- return en7581_reset_register(pdev); ++ return en7581_reset_register(&pdev->dev, base); + } + + static int en7523_clk_probe(struct platform_device *pdev) diff --git a/target/linux/econet/patches-6.12/014-v6.14-PCI-mediatek-gen3-Move-reset-delay-in-mtk_pcie_en758.patch b/target/linux/econet/patches-6.12/014-v6.14-PCI-mediatek-gen3-Move-reset-delay-in-mtk_pcie_en758.patch new file mode 100644 index 00000000000..44664202a83 --- /dev/null +++ b/target/linux/econet/patches-6.12/014-v6.14-PCI-mediatek-gen3-Move-reset-delay-in-mtk_pcie_en758.patch @@ -0,0 +1,42 @@ +From 90d4e466c9ea2010f33880a36317a8486ccbe082 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 8 Jan 2025 10:50:43 +0100 +Subject: [PATCH 1/3] PCI: mediatek-gen3: Move reset delay in + mtk_pcie_en7581_power_up() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Airoha EN7581 has a hw bug asserting/releasing PCIE_PE_RSTB signal +causing occasional PCIe link down issues. In order to overcome the +problem, PCIe block is reset using REG_PCI_CONTROL (0x88) and +REG_RESET_CONTROL (0x834) registers available in the clock module +running clk_bulk_prepare_enable() in mtk_pcie_en7581_power_up(). + +In order to make the code more readable, move the wait for the time +needed to complete the PCIe reset from en7581_pci_enable() to +mtk_pcie_en7581_power_up(). + +Reduce reset timeout from 250ms to the standard PCIE_T_PVPERL_MS value +(100ms) since it has no impact on the driver behavior. + +Link: https://lore.kernel.org/r/20250108-pcie-en7581-fixes-v6-4-21ac939a3b9b@kernel.org +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Krzysztof Wilczyński +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Manivannan Sadhasivam +Acked-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -478,7 +478,6 @@ static int en7581_pci_enable(struct clk_ + REG_PCI_CONTROL_PERSTOUT; + val = readl(np_base + REG_PCI_CONTROL); + writel(val | mask, np_base + REG_PCI_CONTROL); +- msleep(250); + + return 0; + } diff --git a/target/linux/econet/patches-6.12/015-v6.14-clk-en7523-Rework-clock-handling-for-different-clock.patch b/target/linux/econet/patches-6.12/015-v6.14-clk-en7523-Rework-clock-handling-for-different-clock.patch new file mode 100644 index 00000000000..a33e842b9eb --- /dev/null +++ b/target/linux/econet/patches-6.12/015-v6.14-clk-en7523-Rework-clock-handling-for-different-clock.patch @@ -0,0 +1,83 @@ +From e4a9748e7103c47e575459db2b6a77d14f34da2b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 14 Jan 2025 00:10:02 +0100 +Subject: [PATCH 2/3] clk: en7523: Rework clock handling for different clock + numbers + +Airoha EN7581 SoC have additional clock compared to EN7523 but current +driver permits to only support up to EN7523 clock numbers. + +To handle this, rework the clock handling and permit to declare the +clocks number in match_data and alloca clk_data based on the compatible +match_data. + +Signed-off-by: Christian Marangi +Link: https://lore.kernel.org/r/20250113231030.6735-2-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -75,6 +75,7 @@ struct en_rst_data { + }; + + struct en_clk_soc_data { ++ u32 num_clocks; + const struct clk_ops pcie_ops; + int (*hw_init)(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data); +@@ -503,8 +504,6 @@ static void en7523_register_clocks(struc + u32 rate; + int i; + +- clk_data->num = EN7523_NUM_CLOCKS; +- + for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) { + const struct en_clk_desc *desc = &en7523_base_clks[i]; + u32 reg = desc->div_reg ? desc->div_reg : desc->base_reg; +@@ -586,8 +585,6 @@ static void en7581_register_clocks(struc + + hw = en7523_register_pcie_clk(dev, base); + clk_data->hws[EN7523_CLK_PCIE] = hw; +- +- clk_data->num = EN7523_NUM_CLOCKS; + } + + static int en7523_reset_update(struct reset_controller_dev *rcdev, +@@ -701,13 +698,15 @@ static int en7523_clk_probe(struct platf + struct clk_hw_onecell_data *clk_data; + int r; + ++ soc_data = device_get_match_data(&pdev->dev); ++ + clk_data = devm_kzalloc(&pdev->dev, +- struct_size(clk_data, hws, EN7523_NUM_CLOCKS), ++ struct_size(clk_data, hws, soc_data->num_clocks), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + +- soc_data = device_get_match_data(&pdev->dev); ++ clk_data->num = soc_data->num_clocks; + r = soc_data->hw_init(pdev, clk_data); + if (r) + return r; +@@ -716,6 +715,7 @@ static int en7523_clk_probe(struct platf + } + + static const struct en_clk_soc_data en7523_data = { ++ .num_clocks = ARRAY_SIZE(en7523_base_clks) + 1, + .pcie_ops = { + .is_enabled = en7523_pci_is_enabled, + .prepare = en7523_pci_prepare, +@@ -725,6 +725,8 @@ static const struct en_clk_soc_data en75 + }; + + static const struct en_clk_soc_data en7581_data = { ++ /* We increment num_clocks by 1 to account for additional PCIe clock */ ++ .num_clocks = ARRAY_SIZE(en7581_base_clks) + 1, + .pcie_ops = { + .is_enabled = en7581_pci_is_enabled, + .enable = en7581_pci_enable, diff --git a/target/linux/econet/patches-6.12/016-v6.14-clk-en7523-Add-clock-for-eMMC-for-EN7581.patch b/target/linux/econet/patches-6.12/016-v6.14-clk-en7523-Add-clock-for-eMMC-for-EN7581.patch new file mode 100644 index 00000000000..35d34a5ccfe --- /dev/null +++ b/target/linux/econet/patches-6.12/016-v6.14-clk-en7523-Add-clock-for-eMMC-for-EN7581.patch @@ -0,0 +1,41 @@ +From bfe257f9780d8f77045a7da6ec959ee0659d2f98 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 14 Jan 2025 00:10:05 +0100 +Subject: [PATCH 3/3] clk: en7523: Add clock for eMMC for EN7581 + +Add clock for eMMC for EN7581. This is used to give info of the current +eMMC source clock and to switch it from 200MHz or 150MHz. + +Signed-off-by: Christian Marangi +Link: https://lore.kernel.org/r/20250113231030.6735-5-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -91,6 +91,7 @@ static const u32 emi7581_base[] = { 5400 + static const u32 bus7581_base[] = { 600000000, 540000000 }; + static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 }; + static const u32 crypto_base[] = { 540000000, 480000000 }; ++static const u32 emmc7581_base[] = { 200000000, 150000000 }; + + static const struct en_clk_desc en7523_base_clks[] = { + { +@@ -281,6 +282,15 @@ static const struct en_clk_desc en7581_b + .base_shift = 0, + .base_values = crypto_base, + .n_base_values = ARRAY_SIZE(crypto_base), ++ }, { ++ .id = EN7581_CLK_EMMC, ++ .name = "emmc", ++ ++ .base_reg = REG_CRYPTO_CLKSRC2, ++ .base_bits = 1, ++ .base_shift = 12, ++ .base_values = emmc7581_base, ++ .n_base_values = ARRAY_SIZE(emmc7581_base), + } + }; + diff --git a/target/linux/econet/patches-6.12/017-v6.19rc1-clk-en7523-Add-reset-controller-support-for-EN7523-S.patch b/target/linux/econet/patches-6.12/017-v6.19rc1-clk-en7523-Add-reset-controller-support-for-EN7523-S.patch new file mode 100644 index 00000000000..c332cef387a --- /dev/null +++ b/target/linux/econet/patches-6.12/017-v6.19rc1-clk-en7523-Add-reset-controller-support-for-EN7523-S.patch @@ -0,0 +1,133 @@ +From 1c0608d860db973ad09b5a9ccb19b76ae07622a3 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Nov 2025 06:56:44 +0300 +Subject: [PATCH] clk: en7523: Add reset-controller support for EN7523 SoC + +Introduce reset API support to EN7523 clock driver. EN7523 uses the +same reset logic as EN7581, so just reuse existing code. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Philipp Zabel +Signed-off-by: Stephen Boyd +--- + drivers/clk/clk-en7523.c | 64 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 59 insertions(+), 5 deletions(-) + +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #define RST_NR_PER_BANK 32 +@@ -299,6 +300,53 @@ static const u16 en7581_rst_ofs[] = { + REG_RST_CTRL1, + }; + ++static const u16 en7523_rst_map[] = { ++ /* RST_CTRL2 */ ++ [EN7523_XPON_PHY_RST] = 0, ++ [EN7523_XSI_MAC_RST] = 7, ++ [EN7523_XSI_PHY_RST] = 8, ++ [EN7523_NPU_RST] = 9, ++ [EN7523_I2S_RST] = 10, ++ [EN7523_TRNG_RST] = 11, ++ [EN7523_TRNG_MSTART_RST] = 12, ++ [EN7523_DUAL_HSI0_RST] = 13, ++ [EN7523_DUAL_HSI1_RST] = 14, ++ [EN7523_HSI_RST] = 15, ++ [EN7523_DUAL_HSI0_MAC_RST] = 16, ++ [EN7523_DUAL_HSI1_MAC_RST] = 17, ++ [EN7523_HSI_MAC_RST] = 18, ++ [EN7523_WDMA_RST] = 19, ++ [EN7523_WOE0_RST] = 20, ++ [EN7523_WOE1_RST] = 21, ++ [EN7523_HSDMA_RST] = 22, ++ [EN7523_I2C2RBUS_RST] = 23, ++ [EN7523_TDMA_RST] = 24, ++ /* RST_CTRL1 */ ++ [EN7523_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0, ++ [EN7523_FE_PDMA_RST] = RST_NR_PER_BANK + 1, ++ [EN7523_FE_QDMA_RST] = RST_NR_PER_BANK + 2, ++ [EN7523_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4, ++ [EN7523_CRYPTO_RST] = RST_NR_PER_BANK + 6, ++ [EN7523_TIMER_RST] = RST_NR_PER_BANK + 8, ++ [EN7523_PCM1_RST] = RST_NR_PER_BANK + 11, ++ [EN7523_UART_RST] = RST_NR_PER_BANK + 12, ++ [EN7523_GPIO_RST] = RST_NR_PER_BANK + 13, ++ [EN7523_GDMA_RST] = RST_NR_PER_BANK + 14, ++ [EN7523_I2C_MASTER_RST] = RST_NR_PER_BANK + 16, ++ [EN7523_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17, ++ [EN7523_SFC_RST] = RST_NR_PER_BANK + 18, ++ [EN7523_UART2_RST] = RST_NR_PER_BANK + 19, ++ [EN7523_GDMP_RST] = RST_NR_PER_BANK + 20, ++ [EN7523_FE_RST] = RST_NR_PER_BANK + 21, ++ [EN7523_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22, ++ [EN7523_GSW_RST] = RST_NR_PER_BANK + 23, ++ [EN7523_SFC2_PCM_RST] = RST_NR_PER_BANK + 25, ++ [EN7523_PCIE0_RST] = RST_NR_PER_BANK + 26, ++ [EN7523_PCIE1_RST] = RST_NR_PER_BANK + 27, ++ [EN7523_PCIE_HB_RST] = RST_NR_PER_BANK + 29, ++ [EN7523_XPON_MAC_RST] = RST_NR_PER_BANK + 31, ++}; ++ + static const u16 en7581_rst_map[] = { + /* RST_CTRL2 */ + [EN7581_XPON_PHY_RST] = 0, +@@ -357,6 +405,9 @@ static const u16 en7581_rst_map[] = { + [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31, + }; + ++static int en7581_reset_register(struct device *dev, void __iomem *base, ++ const u16 *rst_map, int nr_resets); ++ + static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val) + { + if (!desc->base_bits) +@@ -552,7 +603,8 @@ static int en7523_clk_hw_init(struct pla + + en7523_register_clocks(&pdev->dev, clk_data, base, np_base); + +- return 0; ++ return en7581_reset_register(&pdev->dev, np_base, en7523_rst_map, ++ ARRAY_SIZE(en7523_rst_map)); + } + + static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data, +@@ -652,7 +704,8 @@ static const struct reset_control_ops en + .status = en7523_reset_status, + }; + +-static int en7581_reset_register(struct device *dev, void __iomem *base) ++static int en7581_reset_register(struct device *dev, void __iomem *base, ++ const u16 *rst_map, int nr_resets) + { + struct en_rst_data *rst_data; + +@@ -661,10 +714,10 @@ static int en7581_reset_register(struct + return -ENOMEM; + + rst_data->bank_ofs = en7581_rst_ofs; +- rst_data->idx_map = en7581_rst_map; ++ rst_data->idx_map = rst_map; + rst_data->base = base; + +- rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map); ++ rst_data->rcdev.nr_resets = nr_resets; + rst_data->rcdev.of_xlate = en7523_reset_xlate; + rst_data->rcdev.ops = &en7581_reset_ops; + rst_data->rcdev.of_node = dev->of_node; +@@ -698,7 +751,8 @@ static int en7581_clk_hw_init(struct pla + val = readl(base + REG_NP_SCU_PCIC); + writel(val | 3, base + REG_NP_SCU_PCIC); + +- return en7581_reset_register(&pdev->dev, base); ++ return en7581_reset_register(&pdev->dev, base, en7581_rst_map, ++ ARRAY_SIZE(en7581_rst_map)); + } + + static int en7523_clk_probe(struct platform_device *pdev) diff --git a/target/linux/econet/patches-6.12/018-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch b/target/linux/econet/patches-6.12/018-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch new file mode 100644 index 00000000000..ef56753c9bd --- /dev/null +++ b/target/linux/econet/patches-6.12/018-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch @@ -0,0 +1,35 @@ +From 947643509279a605a09959a06d332bf027e8be57 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Nov 2025 06:56:43 +0300 +Subject: [PATCH] dt-bindings: clock: airoha: Add reset support to EN7523 clock + binding + +Introduce reset capability to EN7523 device-tree clock binding +documentation. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Rob Herring (Arm) +Signed-off-by: Stephen Boyd +--- + Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml ++++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +@@ -64,8 +64,6 @@ allOf: + - description: scu base address + - description: misc scu base address + +- '#reset-cells': false +- + - if: + properties: + compatible: +@@ -89,6 +87,7 @@ examples: + reg = <0x1fa20000 0x400>, + <0x1fb00000 0x1000>; + #clock-cells = <1>; ++ #reset-cells = <1>; + }; + + - | diff --git a/target/linux/econet/patches-6.12/019-v6.13-dt-bindings-clock-airoha-Update-reg-mapping-for-EN75.patch b/target/linux/econet/patches-6.12/019-v6.13-dt-bindings-clock-airoha-Update-reg-mapping-for-EN75.patch new file mode 100644 index 00000000000..a4af01dd205 --- /dev/null +++ b/target/linux/econet/patches-6.12/019-v6.13-dt-bindings-clock-airoha-Update-reg-mapping-for-EN75.patch @@ -0,0 +1,74 @@ +From 0f7c637d1103d79829dec198e5f1b678c1feb5f2 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 12 Nov 2024 01:08:48 +0100 +Subject: [PATCH] dt-bindings: clock: airoha: Update reg mapping for EN7581 + SoC. + +clk-en7523 driver for EN7581 SoC is mapping all the scu memory region +while it is configuring the chip-scu one via a syscon. Update the reg +mapping definition for this device. This patch does not introduce any +backward incompatibility since the dts for EN7581 SoC is not upstream +yet. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/20241112-clk-en7581-syscon-v2-1-8ada5e394ae4@kernel.org +Reviewed-by: Rob Herring (Arm) +Signed-off-by: Stephen Boyd +--- + .../bindings/clock/airoha,en7523-scu.yaml | 23 +++++++------------ + 1 file changed, 8 insertions(+), 15 deletions(-) + +--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml ++++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +@@ -34,8 +34,10 @@ properties: + - airoha,en7581-scu + + reg: +- minItems: 2 +- maxItems: 4 ++ items: ++ - description: scu base address ++ - description: misc scu base address ++ minItems: 1 + + "#clock-cells": + description: +@@ -60,9 +62,7 @@ allOf: + then: + properties: + reg: +- items: +- - description: scu base address +- - description: misc scu base address ++ minItems: 2 + + - if: + properties: +@@ -71,11 +71,7 @@ allOf: + then: + properties: + reg: +- items: +- - description: scu base address +- - description: misc scu base address +- - description: reset base address +- - description: pb scu base address ++ maxItems: 1 + + additionalProperties: false + +@@ -95,12 +91,9 @@ examples: + #address-cells = <2>; + #size-cells = <2>; + +- scuclk: clock-controller@1fa20000 { ++ scuclk: clock-controller@1fb00000 { + compatible = "airoha,en7581-scu"; +- reg = <0x0 0x1fa20000 0x0 0x400>, +- <0x0 0x1fb00000 0x0 0x90>, +- <0x0 0x1fb00830 0x0 0x8>, +- <0x0 0x1fbe3400 0x0 0xfc>; ++ reg = <0x0 0x1fb00000 0x0 0x970>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/target/linux/econet/patches-6.12/020-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch b/target/linux/econet/patches-6.12/020-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch new file mode 100644 index 00000000000..135fcced637 --- /dev/null +++ b/target/linux/econet/patches-6.12/020-v6.19rc1-dt-bindings-clock-airoha-Add-reset-support-to-EN7523.patch @@ -0,0 +1,81 @@ +From 947643509279a605a09959a06d332bf027e8be57 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Nov 2025 06:56:43 +0300 +Subject: [PATCH] dt-bindings: clock: airoha: Add reset support to EN7523 clock + binding + +Introduce reset capability to EN7523 device-tree clock binding +documentation. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Rob Herring (Arm) +Signed-off-by: Stephen Boyd +--- + .../dt-bindings/reset/airoha,en7523-reset.h | 61 +++++++++++++++++++ + 1 file changed, 61 insertions(+) + create mode 100644 include/dt-bindings/reset/airoha,en7523-reset.h + +--- /dev/null ++++ b/include/dt-bindings/reset/airoha,en7523-reset.h +@@ -0,0 +1,61 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2024 iopsys Software Solutions AB. ++ * Copyright (C) 2025 Genexis AB. ++ * ++ * Author: Mikhail Kshevetskiy ++ * ++ * based on ++ * include/dt-bindings/reset/airoha,en7581-reset.h ++ * by Lorenzo Bianconi ++ */ ++ ++#ifndef __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7523_H_ ++#define __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7523_H_ ++ ++/* RST_CTRL2 */ ++#define EN7523_XPON_PHY_RST 0 ++#define EN7523_XSI_MAC_RST 1 ++#define EN7523_XSI_PHY_RST 2 ++#define EN7523_NPU_RST 3 ++#define EN7523_I2S_RST 4 ++#define EN7523_TRNG_RST 5 ++#define EN7523_TRNG_MSTART_RST 6 ++#define EN7523_DUAL_HSI0_RST 7 ++#define EN7523_DUAL_HSI1_RST 8 ++#define EN7523_HSI_RST 9 ++#define EN7523_DUAL_HSI0_MAC_RST 10 ++#define EN7523_DUAL_HSI1_MAC_RST 11 ++#define EN7523_HSI_MAC_RST 12 ++#define EN7523_WDMA_RST 13 ++#define EN7523_WOE0_RST 14 ++#define EN7523_WOE1_RST 15 ++#define EN7523_HSDMA_RST 16 ++#define EN7523_I2C2RBUS_RST 17 ++#define EN7523_TDMA_RST 18 ++/* RST_CTRL1 */ ++#define EN7523_PCM1_ZSI_ISI_RST 19 ++#define EN7523_FE_PDMA_RST 20 ++#define EN7523_FE_QDMA_RST 21 ++#define EN7523_PCM_SPIWP_RST 22 ++#define EN7523_CRYPTO_RST 23 ++#define EN7523_TIMER_RST 24 ++#define EN7523_PCM1_RST 25 ++#define EN7523_UART_RST 26 ++#define EN7523_GPIO_RST 27 ++#define EN7523_GDMA_RST 28 ++#define EN7523_I2C_MASTER_RST 29 ++#define EN7523_PCM2_ZSI_ISI_RST 30 ++#define EN7523_SFC_RST 31 ++#define EN7523_UART2_RST 32 ++#define EN7523_GDMP_RST 33 ++#define EN7523_FE_RST 34 ++#define EN7523_USB_HOST_P0_RST 35 ++#define EN7523_GSW_RST 36 ++#define EN7523_SFC2_PCM_RST 37 ++#define EN7523_PCIE0_RST 38 ++#define EN7523_PCIE1_RST 39 ++#define EN7523_PCIE_HB_RST 40 ++#define EN7523_XPON_MAC_RST 41 ++ ++#endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_EN7523_H_ */ diff --git a/target/linux/econet/patches-6.12/021-v6.14-dt-bindings-clock-drop-NUM_CLOCKS-define-for-EN7581.patch b/target/linux/econet/patches-6.12/021-v6.14-dt-bindings-clock-drop-NUM_CLOCKS-define-for-EN7581.patch new file mode 100644 index 00000000000..a6594ebac80 --- /dev/null +++ b/target/linux/econet/patches-6.12/021-v6.14-dt-bindings-clock-drop-NUM_CLOCKS-define-for-EN7581.patch @@ -0,0 +1,26 @@ +From 02d3b7557ce28c373ea1e925ae16ab5988284313 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 14 Jan 2025 00:10:03 +0100 +Subject: [PATCH 1/2] dt-bindings: clock: drop NUM_CLOCKS define for EN7581 + +Drop NUM_CLOCKS define for EN7581 include. This is not a binding and +should not be placed here. Value is derived internally in the user +driver. + +Signed-off-by: Christian Marangi +Acked-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20250113231030.6735-3-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + include/dt-bindings/clock/en7523-clk.h | 2 -- + 1 file changed, 2 deletions(-) + +--- a/include/dt-bindings/clock/en7523-clk.h ++++ b/include/dt-bindings/clock/en7523-clk.h +@@ -12,6 +12,4 @@ + #define EN7523_CLK_CRYPTO 6 + #define EN7523_CLK_PCIE 7 + +-#define EN7523_NUM_CLOCKS 8 +- + #endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */ diff --git a/target/linux/econet/patches-6.12/022-v6.14-dt-bindings-clock-add-ID-for-eMMC-for-EN7581.patch b/target/linux/econet/patches-6.12/022-v6.14-dt-bindings-clock-add-ID-for-eMMC-for-EN7581.patch new file mode 100644 index 00000000000..f500a798084 --- /dev/null +++ b/target/linux/econet/patches-6.12/022-v6.14-dt-bindings-clock-add-ID-for-eMMC-for-EN7581.patch @@ -0,0 +1,25 @@ +From 82108ad3285f58f314ad41398f44017c7dbe44de Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 14 Jan 2025 00:10:04 +0100 +Subject: [PATCH 2/2] dt-bindings: clock: add ID for eMMC for EN7581 + +Add ID for eMMC for EN7581. This is to control clock selection of eMMC +between 200MHz and 150MHz. + +Signed-off-by: Christian Marangi +Acked-by: Conor Dooley +Link: https://lore.kernel.org/r/20250113231030.6735-4-ansuelsmth@gmail.com +Signed-off-by: Stephen Boyd +--- + include/dt-bindings/clock/en7523-clk.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/dt-bindings/clock/en7523-clk.h ++++ b/include/dt-bindings/clock/en7523-clk.h +@@ -12,4 +12,6 @@ + #define EN7523_CLK_CRYPTO 6 + #define EN7523_CLK_PCIE 7 + ++#define EN7581_CLK_EMMC 8 ++ + #endif /* _DT_BINDINGS_CLOCK_AIROHA_EN7523_H_ */ diff --git a/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch b/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch new file mode 100644 index 00000000000..c99c25921c7 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-05-v6.19-spi-airoha-remove-unnecessary-restriction-length.patch @@ -0,0 +1,33 @@ +From 661856ca131c8bf6724905966e02149805660abe Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:53 +0300 +Subject: [PATCH 05/14] spi: airoha: remove unnecessary restriction length + +The "length < 160" restriction is not needed because airoha_snand_write_data() +and airoha_snand_read_data() will properly handle data transfers above +SPI_MAX_TRANSFER_SIZE. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-3-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 7 ------- + 1 file changed, 7 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -619,13 +619,6 @@ static int airoha_snand_adjust_op_size(s + + if (op->data.nbytes > max_len) + op->data.nbytes = max_len; +- } else { +- max_len = 1 + op->addr.nbytes + op->dummy.nbytes; +- if (max_len >= 160) +- return -EOPNOTSUPP; +- +- if (op->data.nbytes > 160 - max_len) +- op->data.nbytes = 160 - max_len; + } + + return 0; diff --git a/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch b/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch new file mode 100644 index 00000000000..afe496c968f --- /dev/null +++ b/target/linux/econet/patches-6.12/029-06-v6.19-spi-airoha-remove-unnecessary-switch-to-non-dma-mode.patch @@ -0,0 +1,30 @@ +From 7350f8dc15bfbb7abf1ce4babea6fcace1c574c5 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:55 +0300 +Subject: [PATCH 06/14] spi: airoha: remove unnecessary switch to non-dma mode + +The code switches to dma at the start of dirmap operation and returns +to non-dma at the end of dirmap operation, so an additional switch to +non-dma at the start of dirmap write is not required. + +Signed-off-by: Mikhail Kshevetskiy +Acked-by: Lorenzo Bianconi +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-5-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -815,9 +815,6 @@ static ssize_t airoha_snand_dirmap_write + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); +- err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); +- if (err < 0) +- return err; + + memcpy(txrx_buf + offs, buf, len); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, diff --git a/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch b/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch new file mode 100644 index 00000000000..c85c6861fc2 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-07-v6.19-spi-airoha-unify-dirmap-read-write-code.patch @@ -0,0 +1,137 @@ +From 233a22687411ea053a4b169c07324ee6aa33bf38 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:58 +0300 +Subject: [PATCH 07/14] spi: airoha: unify dirmap read/write code + +Makes dirmap writing looks similar to dirmap reading. Just a minor +refactoring, no behavior change is expected. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-8-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 50 ++++++++++++++++++++++------------- + 1 file changed, 32 insertions(+), 18 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -672,6 +672,8 @@ static ssize_t airoha_snand_dirmap_read( + u32 val, rd_mode; + int err; + ++ as_ctrl = spi_controller_get_devdata(spi->controller); ++ + switch (op->cmd.opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + rd_mode = 1; +@@ -684,7 +686,6 @@ static ssize_t airoha_snand_dirmap_read( + break; + } + +- as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + return err; +@@ -748,7 +749,7 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* trigger dma start read */ ++ /* trigger dma reading */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) +@@ -806,37 +807,47 @@ error_dma_mode_off: + static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) + { +- struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + u8 *txrx_buf = spi_get_ctldata(spi); + struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; +- u32 wr_mode, val; ++ u32 wr_mode, val, opcode; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ opcode = desc->info.op_tmpl.cmd.opcode; ++ switch (opcode) { ++ case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: ++ case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: ++ wr_mode = 0; ++ break; ++ case SPI_NAND_OP_PROGRAM_LOAD_QUAD: ++ case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD: ++ wr_mode = 2; ++ break; ++ default: ++ /* unknown opcode */ ++ return -EOPNOTSUPP; ++ } ++ + memcpy(txrx_buf + offs, buf, len); +- dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, +- DMA_TO_DEVICE); +- err = dma_mapping_error(as_ctrl->dev, dma_addr); +- if (err) +- return err; + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) +- goto error_dma_unmap; ++ return err; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) +- goto error_dma_unmap; ++ goto error_dma_mode_off; + +- if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || +- op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) +- wr_mode = BIT(1); +- else +- wr_mode = 0; ++ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, ++ DMA_TO_DEVICE); ++ err = dma_mapping_error(as_ctrl->dev, dma_addr); ++ if (err) ++ goto error_dma_mode_off; + ++ /* set dma addr */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) +@@ -850,12 +861,13 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + ++ /* set write command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, +- FIELD_PREP(SPI_NFI_PG_LOAD_CMD, +- op->cmd.opcode)); ++ FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode)); + if (err) + goto error_dma_unmap; + ++ /* set write mode */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); + if (err) +@@ -887,6 +899,7 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + ++ /* trigger dma writing */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) +@@ -931,6 +944,7 @@ static ssize_t airoha_snand_dirmap_write + error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); ++error_dma_mode_off: + airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + return err; + } diff --git a/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch b/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch new file mode 100644 index 00000000000..7e3fcb47647 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-08-v6.19-spi-airoha-support-of-dualio-quadio-flash-reading-co.patch @@ -0,0 +1,94 @@ +From 80b09137aeab27e59004383058f8cc696a9ee048 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:16:59 +0300 +Subject: [PATCH 08/14] spi: airoha: support of dualio/quadio flash reading + commands + +Airoha snfi spi controller supports acceleration of DUAL/QUAD +operations, but does not supports DUAL_IO/QUAD_IO operations. +Luckily DUAL/QUAD operations do the same as DUAL_IO/QUAD_IO ones, +so we can issue corresponding DUAL/QUAD operation instead of +DUAL_IO/QUAD_IO one. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-9-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -147,6 +147,8 @@ + #define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) + + #define REG_SPI_NFI_RD_CTL2 0x0510 ++#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0) ++ + #define REG_SPI_NFI_RD_CTL3 0x0514 + + #define REG_SPI_NFI_PG_CTL1 0x0524 +@@ -179,7 +181,9 @@ + #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 + #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b + #define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b ++#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb + #define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b ++#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb + #define SPI_NAND_OP_WRITE_ENABLE 0x06 + #define SPI_NAND_OP_WRITE_DISABLE 0x04 + #define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 +@@ -664,26 +668,38 @@ static int airoha_snand_dirmap_create(st + static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) + { +- struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + struct airoha_snand_ctrl *as_ctrl; + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; +- u32 val, rd_mode; ++ u32 val, rd_mode, opcode; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- switch (op->cmd.opcode) { ++ /* ++ * DUALIO and QUADIO opcodes are not supported by the spi controller, ++ * replace them with supported opcodes. ++ */ ++ opcode = desc->info.op_tmpl.cmd.opcode; ++ switch (opcode) { ++ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: ++ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: ++ rd_mode = 0; ++ break; + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: ++ case SPI_NAND_OP_READ_FROM_CACHE_DUALIO: ++ opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL; + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: ++ case SPI_NAND_OP_READ_FROM_CACHE_QUADIO: ++ opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD; + rd_mode = 2; + break; + default: +- rd_mode = 0; +- break; ++ /* unknown opcode */ ++ return -EOPNOTSUPP; + } + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); +@@ -717,7 +733,7 @@ static ssize_t airoha_snand_dirmap_read( + + /* set read command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, +- op->cmd.opcode); ++ FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode)); + if (err) + goto error_dma_unmap; + diff --git a/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch b/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch new file mode 100644 index 00000000000..f8902f7e575 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-09-v6.19-spi-airoha-avoid-setting-of-page-oob-sizes-in-REG_SP.patch @@ -0,0 +1,64 @@ +From 70eec454f2d6cdfab547c262781acd38328e11a1 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:00 +0300 +Subject: [PATCH 09/14] spi: airoha: avoid setting of page/oob sizes in + REG_SPI_NFI_PAGEFMT + +spi-airoha-snfi uses custom sector size in REG_SPI_NFI_SECCUS_SIZE +register, so setting of page/oob sizes in REG_SPI_NFI_PAGEFMT is not +required. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-10-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 38 ----------------------------------- + 1 file changed, 38 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -518,44 +518,6 @@ static int airoha_snand_nfi_config(struc + if (err) + return err; + +- /* page format */ +- switch (as_ctrl->nfi_cfg.spare_size) { +- case 26: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); +- break; +- case 27: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); +- break; +- case 28: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); +- break; +- default: +- val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); +- break; +- } +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, +- SPI_NFI_SPARE_SIZE, val); +- if (err) +- return err; +- +- switch (as_ctrl->nfi_cfg.page_size) { +- case 2048: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); +- break; +- case 4096: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); +- break; +- default: +- val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); +- break; +- } +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, +- SPI_NFI_PAGE_SIZE, val); +- if (err) +- return err; +- + /* sec num */ + val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, diff --git a/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch b/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch new file mode 100644 index 00000000000..40e2f6ea218 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-10-v6.19-spi-airoha-reduce-the-number-of-modification-of-REG_.patch @@ -0,0 +1,199 @@ +From d1ff30df1d9a4eb4c067795abb5e2a66910fd108 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:01 +0300 +Subject: [PATCH 10/14] spi: airoha: reduce the number of modification of + REG_SPI_NFI_CNFG and REG_SPI_NFI_SECCUS_SIZE registers + +This just reduce the number of modification of REG_SPI_NFI_CNFG and +REG_SPI_NFI_SECCUS_SIZE registers during dirmap operation. + +This patch is a necessary step to avoid reading flash page settings +from SNFI registers during driver startup. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-11-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 135 +++++++++++++++++++++++++--------- + 1 file changed, 102 insertions(+), 33 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -668,7 +668,48 @@ static ssize_t airoha_snand_dirmap_read( + if (err < 0) + return err; + +- err = airoha_snand_nfi_config(as_ctrl); ++ /* NFI reset */ ++ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* NFI configure: ++ * - No AutoFDM (custom sector size (SECCUS) register will be used) ++ * - No SoC's hardware ECC (flash internal ECC will be used) ++ * - Use burst mode (faster, but requires 16 byte alignment for addresses) ++ * - Setup for reading (SPI_NFI_READ_MODE) ++ * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6) ++ * - Use DMA instead of PIO for data reading ++ */ ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ SPI_NFI_HW_ECC_EN | ++ SPI_NFI_AUTO_FDM_EN | ++ SPI_NFI_OPMODE, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ FIELD_PREP(SPI_NFI_OPMODE, 6)); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set number of sector will be read */ ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_SEC_NUM, val); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set custom sector size */ ++ val = as_ctrl->nfi_cfg.sec_size; ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, ++ SPI_NFI_CUS_SEC_SIZE | ++ SPI_NFI_CUS_SEC_SIZE_EN, ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + +@@ -684,7 +725,14 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* set cust sec size */ ++ /* ++ * Setup transfer length ++ * --------------------- ++ * The following rule MUST be met: ++ * transfer_length = ++ * = NFI_SNF_MISC_CTL2.read_data_byte_number = ++ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size ++ */ + val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; + val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, +@@ -711,18 +759,6 @@ static ssize_t airoha_snand_dirmap_read( + if (err) + goto error_dma_unmap; + +- /* set nfi read */ +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_OPMODE, +- FIELD_PREP(SPI_NFI_OPMODE, 6)); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); +- if (err) +- goto error_dma_unmap; +- + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0); + if (err) + goto error_dma_unmap; +@@ -815,7 +851,48 @@ static ssize_t airoha_snand_dirmap_write + if (err < 0) + return err; + +- err = airoha_snand_nfi_config(as_ctrl); ++ /* NFI reset */ ++ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* ++ * NFI configure: ++ * - No AutoFDM (custom sector size (SECCUS) register will be used) ++ * - No SoC's hardware ECC (flash internal ECC will be used) ++ * - Use burst mode (faster, but requires 16 byte alignment for addresses) ++ * - Setup for writing (SPI_NFI_READ_MODE bit is cleared) ++ * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3) ++ * - Use DMA instead of PIO for data writing ++ */ ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_READ_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ SPI_NFI_HW_ECC_EN | ++ SPI_NFI_AUTO_FDM_EN | ++ SPI_NFI_OPMODE, ++ SPI_NFI_DMA_MODE | ++ SPI_NFI_DMA_BURST_EN | ++ FIELD_PREP(SPI_NFI_OPMODE, 3)); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set number of sector will be written */ ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, ++ SPI_NFI_SEC_NUM, val); ++ if (err) ++ goto error_dma_mode_off; ++ ++ /* Set custom sector size */ ++ val = as_ctrl->nfi_cfg.sec_size; ++ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, ++ SPI_NFI_CUS_SEC_SIZE | ++ SPI_NFI_CUS_SEC_SIZE_EN, ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + +@@ -831,8 +908,16 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + +- val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, +- as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); ++ /* ++ * Setup transfer length ++ * --------------------- ++ * The following rule MUST be met: ++ * transfer_length = ++ * = NFI_SNF_MISC_CTL2.write_data_byte_number = ++ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size ++ */ ++ val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; ++ val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, val); +@@ -857,22 +942,6 @@ static ssize_t airoha_snand_dirmap_write + if (err) + goto error_dma_unmap; + +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_READ_MODE); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_OPMODE, +- FIELD_PREP(SPI_NFI_OPMODE, 3)); +- if (err) +- goto error_dma_unmap; +- +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_DMA_MODE); +- if (err) +- goto error_dma_unmap; +- + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + goto error_dma_unmap; diff --git a/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch b/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch new file mode 100644 index 00000000000..514212835ce --- /dev/null +++ b/target/linux/econet/patches-6.12/029-11-v6.19-spi-airoha-set-custom-sector-size-equal-to-flash-pag.patch @@ -0,0 +1,142 @@ +From fb81b5cecb8553e3ca2b45288cf340d43c9c2991 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:02 +0300 +Subject: [PATCH 11/14] spi: airoha: set custom sector size equal to flash page + size + +Set custom sector size equal to flash page size including oob. Thus we +will always read a single sector. The maximum custom sector size is +8187, so all possible flash sector sizes are supported. + +This patch is a necessary step to avoid reading flash page settings +from SNFI registers during driver startup. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-12-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -519,7 +519,7 @@ static int airoha_snand_nfi_config(struc + return err; + + /* sec num */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); ++ val = FIELD_PREP(SPI_NFI_SEC_NUM, 1); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, val); + if (err) +@@ -532,7 +532,8 @@ static int airoha_snand_nfi_config(struc + return err; + + /* set cust sec size */ +- val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size); ++ val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, ++ as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); + return regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE, val); +@@ -635,10 +636,13 @@ static ssize_t airoha_snand_dirmap_read( + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; + u32 val, rd_mode, opcode; ++ size_t bytes; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, + * replace them with supported opcodes. +@@ -697,18 +701,17 @@ static ssize_t airoha_snand_dirmap_read( + goto error_dma_mode_off; + + /* Set number of sector will be read */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); ++ SPI_NFI_SEC_NUM, ++ FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ +- val = as_ctrl->nfi_cfg.sec_size; + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, +- FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; +@@ -733,11 +736,10 @@ static ssize_t airoha_snand_dirmap_read( + * = NFI_SNF_MISC_CTL2.read_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ +- val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; +- val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, +- SPI_NFI_READ_DATA_BYTE_NUM, val); ++ SPI_NFI_READ_DATA_BYTE_NUM, ++ FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; + +@@ -826,10 +828,13 @@ static ssize_t airoha_snand_dirmap_write + struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; + u32 wr_mode, val, opcode; ++ size_t bytes; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + ++ bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: +@@ -880,18 +885,17 @@ static ssize_t airoha_snand_dirmap_write + goto error_dma_mode_off; + + /* Set number of sector will be written */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); ++ SPI_NFI_SEC_NUM, ++ FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ +- val = as_ctrl->nfi_cfg.sec_size; + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, +- FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, val) | ++ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; +@@ -916,11 +920,10 @@ static ssize_t airoha_snand_dirmap_write + * = NFI_SNF_MISC_CTL2.write_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ +- val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; +- val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, +- SPI_NFI_PROG_LOAD_BYTE_NUM, val); ++ SPI_NFI_PROG_LOAD_BYTE_NUM, ++ FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; + diff --git a/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch b/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch new file mode 100644 index 00000000000..00fd100bc36 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-12-v6.19-spi-airoha-avoid-reading-flash-page-settings-from-SN.patch @@ -0,0 +1,206 @@ +From 902c0ea18a97b1a6eeee5799cb1fd9a79ef9208e Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:03 +0300 +Subject: [PATCH 12/14] spi: airoha: avoid reading flash page settings from + SNFI registers during driver startup + +The spinand driver do 3 type of dirmap requests: + * read/write whole flash page without oob + (offs = 0, len = page_size) + * read/write whole flash page including oob + (offs = 0, len = page_size + oob_size) + * read/write oob area only + (offs = page_size, len = oob_size) + +The trick is: + * read/write a single "sector" + * set a custom sector size equal to offs + len. It's a bit safer to + rounded up "sector size" value 64. + * set the transfer length equal to custom sector size + +And it works! + +Thus we can remove a dirty hack that reads flash page settings from +SNFI registers during driver startup. Also airoha_snand_adjust_op_size() +function becomes unnecessary. + +Signed-off-by: Mikhail Kshevetskiy +Link: https://patch.msgid.link/20251012121707.2296160-13-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 115 ++-------------------------------- + 1 file changed, 5 insertions(+), 110 deletions(-) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -223,13 +223,6 @@ struct airoha_snand_ctrl { + struct regmap *regmap_ctrl; + struct regmap *regmap_nfi; + struct clk *spi_clk; +- +- struct { +- size_t page_size; +- size_t sec_size; +- u8 sec_num; +- u8 spare_size; +- } nfi_cfg; + }; + + static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl, +@@ -490,55 +483,6 @@ static int airoha_snand_nfi_init(struct + SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); + } + +-static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl) +-{ +- int err; +- u32 val; +- +- err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); +- if (err) +- return err; +- +- /* auto FDM */ +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_AUTO_FDM_EN); +- if (err) +- return err; +- +- /* HW ECC */ +- err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_HW_ECC_EN); +- if (err) +- return err; +- +- /* DMA Burst */ +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, +- SPI_NFI_DMA_BURST_EN); +- if (err) +- return err; +- +- /* sec num */ +- val = FIELD_PREP(SPI_NFI_SEC_NUM, 1); +- err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, +- SPI_NFI_SEC_NUM, val); +- if (err) +- return err; +- +- /* enable cust sec size */ +- err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, +- SPI_NFI_CUS_SEC_SIZE_EN); +- if (err) +- return err; +- +- /* set cust sec size */ +- val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, +- as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); +- return regmap_update_bits(as_ctrl->regmap_nfi, +- REG_SPI_NFI_SECCUS_SIZE, +- SPI_NFI_CUS_SEC_SIZE, val); +-} +- + static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) + { + if (op->addr.nbytes != 2) +@@ -571,26 +515,6 @@ static bool airoha_snand_is_page_ops(con + } + } + +-static int airoha_snand_adjust_op_size(struct spi_mem *mem, +- struct spi_mem_op *op) +-{ +- size_t max_len; +- +- if (airoha_snand_is_page_ops(op)) { +- struct airoha_snand_ctrl *as_ctrl; +- +- as_ctrl = spi_controller_get_devdata(mem->spi->controller); +- max_len = as_ctrl->nfi_cfg.sec_size; +- max_len += as_ctrl->nfi_cfg.spare_size; +- max_len *= as_ctrl->nfi_cfg.sec_num; +- +- if (op->data.nbytes > max_len) +- op->data.nbytes = max_len; +- } +- +- return 0; +-} +- + static bool airoha_snand_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) + { +@@ -641,7 +565,8 @@ static ssize_t airoha_snand_dirmap_read( + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ /* minimum oob size is 64 */ ++ bytes = round_up(offs + len, 64); + + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, +@@ -833,7 +758,8 @@ static ssize_t airoha_snand_dirmap_write + + as_ctrl = spi_controller_get_devdata(spi->controller); + +- bytes = as_ctrl->nfi_cfg.sec_num * as_ctrl->nfi_cfg.sec_size; ++ /* minimum oob size is 64 */ ++ bytes = round_up(offs + len, 64); + + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { +@@ -1076,7 +1002,6 @@ static int airoha_snand_exec_op(struct s + } + + static const struct spi_controller_mem_ops airoha_snand_mem_ops = { +- .adjust_op_size = airoha_snand_adjust_op_size, + .supports_op = airoha_snand_supports_op, + .exec_op = airoha_snand_exec_op, + .dirmap_create = airoha_snand_dirmap_create, +@@ -1106,36 +1031,6 @@ static int airoha_snand_setup(struct spi + return 0; + } + +-static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) +-{ +- u32 val, sec_size, sec_num; +- int err; +- +- err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val); +- if (err) +- return err; +- +- sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val); +- +- err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val); +- if (err) +- return err; +- +- sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val); +- +- /* init default value */ +- as_ctrl->nfi_cfg.sec_size = sec_size; +- as_ctrl->nfi_cfg.sec_num = sec_num; +- as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); +- as_ctrl->nfi_cfg.spare_size = 16; +- +- err = airoha_snand_nfi_init(as_ctrl); +- if (err) +- return err; +- +- return airoha_snand_nfi_config(as_ctrl); +-} +- + static const struct regmap_config spi_ctrl_regmap_config = { + .name = "ctrl", + .reg_bits = 32, +@@ -1227,7 +1122,7 @@ static int airoha_snand_probe(struct pla + ctrl->setup = airoha_snand_setup; + device_set_node(&ctrl->dev, dev_fwnode(dev)); + +- err = airoha_snand_nfi_setup(as_ctrl); ++ err = airoha_snand_nfi_init(as_ctrl); + if (err) + return err; + diff --git a/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch b/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch new file mode 100644 index 00000000000..669f9b2dd43 --- /dev/null +++ b/target/linux/econet/patches-6.12/029-13-v6.19-spi-airoha-buffer-must-be-0xff-ed-before-writing.patch @@ -0,0 +1,32 @@ +From 0743acf746a81e0460a56fd5ff847d97fa7eb370 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Sun, 12 Oct 2025 15:17:04 +0300 +Subject: [PATCH 13/14] spi: airoha: buffer must be 0xff-ed before writing + +During writing, the entire flash page (including OOB) will be updated +with the values from the temporary buffer, so we need to fill the +untouched areas of the buffer with 0xff value to prevent accidental +data overwriting. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: AngeloGioacchino Del Regno +Link: https://patch.msgid.link/20251012121707.2296160-14-mikhail.kshevetskiy@iopsys.eu +Signed-off-by: Mark Brown +--- + drivers/spi/spi-airoha-snfi.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/spi/spi-airoha-snfi.c ++++ b/drivers/spi/spi-airoha-snfi.c +@@ -776,7 +776,11 @@ static ssize_t airoha_snand_dirmap_write + return -EOPNOTSUPP; + } + ++ if (offs > 0) ++ memset(txrx_buf, 0xff, offs); + memcpy(txrx_buf + offs, buf, len); ++ if (bytes > offs + len) ++ memset(txrx_buf + offs + len, 0xff, bytes - offs - len); + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) 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/300-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch b/target/linux/econet/patches-6.12/300-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch new file mode 100644 index 00000000000..d3f3054fe75 --- /dev/null +++ b/target/linux/econet/patches-6.12/300-spi-Add-support-for-the-Airoha-EN7523-SoC-SPI-contro.patch @@ -0,0 +1,341 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -370,6 +370,12 @@ config SPI_DLN2 + This driver can also be built as a module. If so, the module + will be called spi-dln2. + ++config SPI_AIROHA_EN7523 ++ bool "Airoha EN7523 SPI controller support" ++ depends on ARCH_AIROHA ++ help ++ This enables SPI controller support for the Airoha EN7523 SoC. ++ + config SPI_EP93XX + tristate "Cirrus Logic EP93xx SPI controller" + depends on ARCH_EP93XX || COMPILE_TEST +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -52,6 +52,7 @@ obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1. + obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o + obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o + obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o ++obj-$(CONFIG_SPI_AIROHA_EN7523) += spi-en7523.o + obj-$(CONFIG_SPI_FALCON) += spi-falcon.o + obj-$(CONFIG_SPI_FSI) += spi-fsi.o + obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o +--- /dev/null ++++ b/drivers/spi/spi-en7523.c +@@ -0,0 +1,313 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++ ++ ++#define ENSPI_READ_IDLE_EN 0x0004 ++#define ENSPI_MTX_MODE_TOG 0x0014 ++#define ENSPI_RDCTL_FSM 0x0018 ++#define ENSPI_MANUAL_EN 0x0020 ++#define ENSPI_MANUAL_OPFIFO_EMPTY 0x0024 ++#define ENSPI_MANUAL_OPFIFO_WDATA 0x0028 ++#define ENSPI_MANUAL_OPFIFO_FULL 0x002C ++#define ENSPI_MANUAL_OPFIFO_WR 0x0030 ++#define ENSPI_MANUAL_DFIFO_FULL 0x0034 ++#define ENSPI_MANUAL_DFIFO_WDATA 0x0038 ++#define ENSPI_MANUAL_DFIFO_EMPTY 0x003C ++#define ENSPI_MANUAL_DFIFO_RD 0x0040 ++#define ENSPI_MANUAL_DFIFO_RDATA 0x0044 ++#define ENSPI_IER 0x0090 ++#define ENSPI_NFI2SPI_EN 0x0130 ++ ++// TODO not in spi block ++#define ENSPI_CLOCK_DIVIDER ((void __iomem *)0x1fa201c4) ++ ++#define OP_CSH 0x00 ++#define OP_CSL 0x01 ++#define OP_CK 0x02 ++#define OP_OUTS 0x08 ++#define OP_OUTD 0x09 ++#define OP_OUTQ 0x0A ++#define OP_INS 0x0C ++#define OP_INS0 0x0D ++#define OP_IND 0x0E ++#define OP_INQ 0x0F ++#define OP_OS2IS 0x10 ++#define OP_OS2ID 0x11 ++#define OP_OS2IQ 0x12 ++#define OP_OD2IS 0x13 ++#define OP_OD2ID 0x14 ++#define OP_OD2IQ 0x15 ++#define OP_OQ2IS 0x16 ++#define OP_OQ2ID 0x17 ++#define OP_OQ2IQ 0x18 ++#define OP_OSNIS 0x19 ++#define OP_ODNID 0x1A ++ ++#define MATRIX_MODE_AUTO 1 ++#define CONF_MTX_MODE_AUTO 0 ++#define MANUALEN_AUTO 0 ++#define MATRIX_MODE_MANUAL 0 ++#define CONF_MTX_MODE_MANUAL 9 ++#define MANUALEN_MANUAL 1 ++ ++#define _ENSPI_MAX_XFER 0x1ff ++ ++#define REG(x) (iobase + x) ++ ++ ++static void __iomem *iobase; ++ ++ ++static void opfifo_write(u32 cmd, u32 len) ++{ ++ u32 tmp = ((cmd & 0x1f) << 9) | (len & 0x1ff); ++ ++ writel(tmp, REG(ENSPI_MANUAL_OPFIFO_WDATA)); ++ ++ /* Wait for room in OPFIFO */ ++ while (readl(REG(ENSPI_MANUAL_OPFIFO_FULL))) ++ ; ++ ++ /* Shift command into OPFIFO */ ++ writel(1, REG(ENSPI_MANUAL_OPFIFO_WR)); ++ ++ /* Wait for command to finish */ ++ while (!readl(REG(ENSPI_MANUAL_OPFIFO_EMPTY))) ++ ; ++} ++ ++static void set_cs(int state) ++{ ++ if (state) ++ opfifo_write(OP_CSH, 1); ++ else ++ opfifo_write(OP_CSL, 1); ++} ++ ++static void manual_begin_cmd(void) ++{ ++ /* Disable read idle state */ ++ writel(0, REG(ENSPI_READ_IDLE_EN)); ++ ++ /* Wait for FSM to reach idle state */ ++ while (readl(REG(ENSPI_RDCTL_FSM))) ++ ; ++ ++ /* Set SPI core to manual mode */ ++ writel(CONF_MTX_MODE_MANUAL, REG(ENSPI_MTX_MODE_TOG)); ++ writel(MANUALEN_MANUAL, REG(ENSPI_MANUAL_EN)); ++} ++ ++static void manual_end_cmd(void) ++{ ++ /* Set SPI core to auto mode */ ++ writel(CONF_MTX_MODE_AUTO, REG(ENSPI_MTX_MODE_TOG)); ++ writel(MANUALEN_AUTO, REG(ENSPI_MANUAL_EN)); ++ ++ /* Enable read idle state */ ++ writel(1, REG(ENSPI_READ_IDLE_EN)); ++} ++ ++static void dfifo_read(u8 *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ /* Wait for requested data to show up in DFIFO */ ++ while (readl(REG(ENSPI_MANUAL_DFIFO_EMPTY))) ++ ; ++ buf[i] = readl(REG(ENSPI_MANUAL_DFIFO_RDATA)); ++ /* Queue up next byte */ ++ writel(1, REG(ENSPI_MANUAL_DFIFO_RD)); ++ } ++} ++ ++static void dfifo_write(const u8 *buf, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ /* Wait for room in DFIFO */ ++ while (readl(REG(ENSPI_MANUAL_DFIFO_FULL))) ++ ; ++ writel(buf[i], REG(ENSPI_MANUAL_DFIFO_WDATA)); ++ } ++} ++ ++#if 0 ++static void set_spi_clock_speed(int freq_mhz) ++{ ++ u32 tmp, val; ++ ++ tmp = readl(ENSPI_CLOCK_DIVIDER); ++ tmp &= 0xffff0000; ++ writel(tmp, ENSPI_CLOCK_DIVIDER); ++ ++ val = (400 / (freq_mhz * 2)); ++ tmp |= (val << 8) | 1; ++ writel(tmp, ENSPI_CLOCK_DIVIDER); ++} ++#endif ++ ++static void init_hw(void) ++{ ++ /* Disable manual/auto mode clash interrupt */ ++ writel(0, REG(ENSPI_IER)); ++ ++ // TODO via clk framework ++ // set_spi_clock_speed(50); ++ ++ /* Disable DMA */ ++ writel(0, REG(ENSPI_NFI2SPI_EN)); ++} ++ ++static int xfer_read(struct spi_transfer *xfer) ++{ ++ int opcode; ++ uint8_t *buf = xfer->rx_buf; ++ ++ switch (xfer->rx_nbits) { ++ case SPI_NBITS_SINGLE: ++ opcode = OP_INS; ++ break; ++ case SPI_NBITS_DUAL: ++ opcode = OP_IND; ++ break; ++ case SPI_NBITS_QUAD: ++ opcode = OP_INQ; ++ break; ++ } ++ ++ opfifo_write(opcode, xfer->len); ++ dfifo_read(buf, xfer->len); ++ ++ return xfer->len; ++} ++ ++static int xfer_write(struct spi_transfer *xfer, int next_xfer_is_rx) ++{ ++ int opcode; ++ const uint8_t *buf = xfer->tx_buf; ++ ++ if (next_xfer_is_rx) { ++ /* need to use Ox2Ix opcode to set the core to input afterwards */ ++ switch (xfer->tx_nbits) { ++ case SPI_NBITS_SINGLE: ++ opcode = OP_OS2IS; ++ break; ++ case SPI_NBITS_DUAL: ++ opcode = OP_OS2ID; ++ break; ++ case SPI_NBITS_QUAD: ++ opcode = OP_OS2IQ; ++ break; ++ } ++ } else { ++ switch (xfer->tx_nbits) { ++ case SPI_NBITS_SINGLE: ++ opcode = OP_OUTS; ++ break; ++ case SPI_NBITS_DUAL: ++ opcode = OP_OUTD; ++ break; ++ case SPI_NBITS_QUAD: ++ opcode = OP_OUTQ; ++ break; ++ } ++ } ++ ++ opfifo_write(opcode, xfer->len); ++ dfifo_write(buf, xfer->len); ++ ++ return xfer->len; ++} ++ ++size_t max_transfer_size(struct spi_device *spi) ++{ ++ return _ENSPI_MAX_XFER; ++} ++ ++int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg) ++{ ++ struct spi_transfer *xfer; ++ int next_xfer_is_rx = 0; ++ ++ manual_begin_cmd(); ++ set_cs(0); ++ list_for_each_entry(xfer, &msg->transfers, transfer_list) { ++ if (xfer->tx_buf) { ++ if (!list_is_last(&xfer->transfer_list, &msg->transfers) ++ && list_next_entry(xfer, transfer_list)->rx_buf != NULL) ++ next_xfer_is_rx = 1; ++ else ++ next_xfer_is_rx = 0; ++ msg->actual_length += xfer_write(xfer, next_xfer_is_rx); ++ } else if (xfer->rx_buf) { ++ msg->actual_length += xfer_read(xfer); ++ } ++ } ++ set_cs(1); ++ manual_end_cmd(); ++ ++ msg->status = 0; ++ spi_finalize_current_message(ctrl); ++ ++ return 0; ++} ++ ++static int spi_probe(struct platform_device *pdev) ++{ ++ struct spi_controller *ctrl; ++ int err; ++ ++ ctrl = devm_spi_alloc_master(&pdev->dev, 0); ++ if (!ctrl) { ++ dev_err(&pdev->dev, "Error allocating SPI controller\n"); ++ return -ENOMEM; ++ } ++ ++ iobase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); ++ if (IS_ERR(iobase)) { ++ dev_err(&pdev->dev, "Could not map SPI register address"); ++ return -ENOMEM; ++ } ++ ++ init_hw(); ++ ++ ctrl->dev.of_node = pdev->dev.of_node; ++ ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX; ++ ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL; ++ ctrl->max_transfer_size = max_transfer_size; ++ ctrl->transfer_one_message = transfer_one_message; ++ err = devm_spi_register_controller(&pdev->dev, ctrl); ++ if (err) { ++ dev_err(&pdev->dev, "Could not register SPI controller\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id spi_of_ids[] = { ++ { .compatible = "airoha,en7523-spi" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, spi_of_ids); ++ ++static struct platform_driver spi_driver = { ++ .probe = spi_probe, ++ .driver = { ++ .name = "airoha-en7523-spi", ++ .of_match_table = spi_of_ids, ++ }, ++}; ++ ++module_platform_driver(spi_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Bert Vermeulen "); ++MODULE_DESCRIPTION("Airoha EN7523 SPI driver"); diff --git a/target/linux/econet/patches-6.12/301-spi-Airoha-adapt-to-support-en75-mips.patch b/target/linux/econet/patches-6.12/301-spi-Airoha-adapt-to-support-en75-mips.patch new file mode 100644 index 00000000000..888df7552e8 --- /dev/null +++ b/target/linux/econet/patches-6.12/301-spi-Airoha-adapt-to-support-en75-mips.patch @@ -0,0 +1,56 @@ +Subject: Adapt Airoha EN7523 SPI to work with EcoNet EN751221 + +The SPI driver from Airoha EN7523 is copied here in it's original form +so this patch makes three updates to it in order to make it work +correctly in the EcoNet EN751221 context. + +The main change here is that the chip select operation is sent twice. +This pattern is borrowed from the vendor code and it prevents write +operations from being lost sporadically on the EN751221. + +Signed-off-by: Caleb James DeLisle +--- +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -372,7 +372,7 @@ config SPI_DLN2 + + config SPI_AIROHA_EN7523 + bool "Airoha EN7523 SPI controller support" +- depends on ARCH_AIROHA ++ depends on ARCH_AIROHA || ECONET + help + This enables SPI controller support for the Airoha EN7523 SoC. + +--- a/drivers/spi/spi-en7523.c ++++ b/drivers/spi/spi-en7523.c +@@ -82,10 +82,11 @@ static void opfifo_write(u32 cmd, u32 le + + static void set_cs(int state) + { +- if (state) +- opfifo_write(OP_CSH, 1); +- else +- opfifo_write(OP_CSL, 1); ++ u32 cmd = state ? OP_CSH : OP_CSL; ++ ++ /* EN751221 drops writes if we don't send this twice. */ ++ opfifo_write(cmd, 1); ++ opfifo_write(cmd, 1); + } + + static void manual_begin_cmd(void) +@@ -226,12 +227,12 @@ static int xfer_write(struct spi_transfe + return xfer->len; + } + +-size_t max_transfer_size(struct spi_device *spi) ++static size_t max_transfer_size(struct spi_device *spi) + { + return _ENSPI_MAX_XFER; + } + +-int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg) ++static int transfer_one_message(struct spi_controller *ctrl, struct spi_message *msg) + { + struct spi_transfer *xfer; + int next_xfer_is_rx = 0; 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 new file mode 100644 index 00000000000..a550bbfae5c --- /dev/null +++ b/target/linux/econet/patches-6.12/310-usb-enable-econet-usb.patch @@ -0,0 +1,21 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -391,6 +391,7 @@ config MACH_DECSTATION + config ECONET + bool "EcoNet MIPS family" + select BOOT_RAW ++ select DMA_NONCOHERENT + select DEBUG_ZBOOT if DEBUG_KERNEL + select EARLY_PRINTK_8250 + select ECONET_EN751221_TIMER +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -71,7 +71,7 @@ config USB_XHCI_HISTB + config USB_XHCI_MTK + tristate "xHCI support for MediaTek SoCs" + select MFD_SYSCON +- depends on (MIPS && SOC_MT7621) || ARCH_MEDIATEK || COMPILE_TEST ++ depends on (MIPS && SOC_MT7621) || ECONET || ARCH_MEDIATEK || COMPILE_TEST + help + Say 'Y' to enable the support for the xHCI host controller + found in MediaTek SoCs. diff --git a/target/linux/econet/patches-6.12/320-gpio-en7523-enable-for-econet-mips.patch b/target/linux/econet/patches-6.12/320-gpio-en7523-enable-for-econet-mips.patch new file mode 100644 index 00000000000..09e86ff5c9f --- /dev/null +++ b/target/linux/econet/patches-6.12/320-gpio-en7523-enable-for-econet-mips.patch @@ -0,0 +1,17 @@ +gpio: en7523: enable for EcoNet MIPS platform + +The Airoha EN7523 GPIO controller is also found on EcoNet EN7528 +MIPS SoC. Allow building the driver when ECONET is selected. + +Signed-off-by: Ahmed Naseef +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -271,7 +271,7 @@ config GPIO_EM + + config GPIO_EN7523 + tristate "Airoha GPIO support" +- depends on ARCH_AIROHA ++ depends on ARCH_AIROHA || ECONET + default ARCH_AIROHA + select GPIO_GENERIC + select GPIOLIB_IRQCHIP 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..486208f71ad --- /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 */ +@@ -2841,6 +2849,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. diff --git a/target/linux/econet/patches-6.12/901-nand-enable-en75-bbt.patch b/target/linux/econet/patches-6.12/901-nand-enable-en75-bbt.patch new file mode 100644 index 00000000000..91e184bd96a --- /dev/null +++ b/target/linux/econet/patches-6.12/901-nand-enable-en75-bbt.patch @@ -0,0 +1,40 @@ +Subject: Add EcoNet bad block table + +The EcoNet BBT/BMT is used for resolving bad blocks in the flash. +It is implemented in the EcoNet bootloader so you cannot safely +access flash without using it. + +Signed-off-by: Caleb James DeLisle +--- +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -3,7 +3,7 @@ + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +-obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o ++obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o en75_bmt.o + obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o + obj-$(CONFIG_MTD_NAND_QCOM) += qpic_common.o + obj-y += onenand/ +--- a/drivers/mtd/nand/mtk_bmt.h ++++ b/drivers/mtd/nand/mtk_bmt.h +@@ -77,6 +77,7 @@ extern struct bmt_desc bmtd; + extern const struct mtk_bmt_ops mtk_bmt_v2_ops; + extern const struct mtk_bmt_ops mtk_bmt_bbt_ops; + extern const struct mtk_bmt_ops mtk_bmt_nmbm_ops; ++extern const struct mtk_bmt_ops en75_bmt_ops; + + static inline u32 blk_pg(u16 block) + { +--- a/drivers/mtd/nand/mtk_bmt.c ++++ b/drivers/mtd/nand/mtk_bmt.c +@@ -421,6 +421,8 @@ int mtk_bmt_attach(struct mtd_info *mtd) + bmtd.ops = &mtk_bmt_nmbm_ops; + else if (of_property_read_bool(np, "mediatek,bbt")) + bmtd.ops = &mtk_bmt_bbt_ops; ++ else if (of_property_read_bool(np, "econet,bmt")) ++ bmtd.ops = &en75_bmt_ops; + else + return 0; + diff --git a/target/linux/econet/patches-6.12/902-snand-mtk-bmt-support.patch b/target/linux/econet/patches-6.12/902-snand-mtk-bmt-support.patch new file mode 100644 index 00000000000..2dc81292ec4 --- /dev/null +++ b/target/linux/econet/patches-6.12/902-snand-mtk-bmt-support.patch @@ -0,0 +1,34 @@ +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) + { +@@ -1604,6 +1605,7 @@ static int spinand_probe(struct spi_mem + if (ret) + return ret; + ++ mtk_bmt_attach(mtd); + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + goto err_spinand_cleanup; +@@ -1611,6 +1613,7 @@ static int spinand_probe(struct spi_mem + return 0; + + err_spinand_cleanup: ++ mtk_bmt_detach(mtd); + spinand_cleanup(spinand); + + return ret; +@@ -1629,6 +1632,7 @@ static int spinand_remove(struct spi_mem + if (ret) + return ret; + ++ mtk_bmt_detach(mtd); + spinand_cleanup(spinand); + + return 0; diff --git a/target/linux/econet/patches-6.12/910-dt-bindings-clock-reset-add-econet-en751221-bindings.patch b/target/linux/econet/patches-6.12/910-dt-bindings-clock-reset-add-econet-en751221-bindings.patch new file mode 100644 index 00000000000..37dc36cacc3 --- /dev/null +++ b/target/linux/econet/patches-6.12/910-dt-bindings-clock-reset-add-econet-en751221-bindings.patch @@ -0,0 +1,176 @@ +From f3fa5911b1f094e164c497f7b10d94d92852e285 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 14 Jan 2026 17:54:05 +0000 +Subject: [PATCH] dt-bindings: clock, reset: Add econet EN751221 bindings + +Add clock and reset bindings for EN751221 based on the Airoha EN7523 SCU +driver. + +Signed-off-by: Caleb James DeLisle +--- +The EN751221 has the same bifurcation of SCU as EN7581 so we use +the same chip-scu as airoha,en7581-chip-scu. +--- + .../bindings/clock/airoha,en7523-scu.yaml | 17 +++++++- + .../mips/econet,en751221-chip-scu.yaml | 42 +++++++++++++++++++ + .../dt-bindings/clock/econet,en751221-scu.h | 14 +++++++ + .../dt-bindings/reset/econet,en751221-scu.h | 41 ++++++++++++++++++ + 4 files changed, 113 insertions(+), 1 deletion(-) + create mode 100644 Documentation/devicetree/bindings/mips/econet,en751221-chip-scu.yaml + create mode 100644 include/dt-bindings/clock/econet,en751221-scu.h + create mode 100644 include/dt-bindings/reset/econet,en751221-scu.h + +--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml ++++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +@@ -32,6 +32,7 @@ properties: + - enum: + - airoha,en7523-scu + - airoha,en7581-scu ++ - econet,en751221-scu + + reg: + items: +@@ -67,7 +68,10 @@ allOf: + - if: + properties: + compatible: +- const: airoha,en7581-scu ++ items: ++ - enum: ++ - airoha,en7581-scu ++ - econet,en751221-scu + then: + properties: + reg: +@@ -98,3 +102,14 @@ examples: + #reset-cells = <1>; + }; + }; ++ ++ - | ++ soc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ scuclk: clock-controller@1fb00000 { ++ compatible = "econet,en751221-scu"; ++ reg = <0x1fb00000 0x970>; ++ }; ++ }; +\ No newline at end of file +--- /dev/null ++++ b/Documentation/devicetree/bindings/mips/econet,en751221-chip-scu.yaml +@@ -0,0 +1,42 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/arm/airoha,en7581-chip-scu.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: EcoNet Chip SCU Controller for EN751221 SoC ++ ++maintainers: ++ - Caleb James DeLisle ++ ++description: ++ The EcoNet chip-scu block provides a configuration interface for clock, ++ io-muxing and other functionalities used by multiple controllers (e.g. clock, ++ pinctrl, ecc) on EN751221 SoC. ++ ++properties: ++ compatible: ++ items: ++ - enum: ++ - econet,en751221-chip-scu ++ - const: syscon ++ ++ reg: ++ maxItems: 1 ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: false ++ ++examples: ++ - | ++ soc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ syscon@1fa20000 { ++ compatible = "econet,en751221-chip-scu", "syscon"; ++ reg = <0x1fa20000 0x388>; ++ }; ++ }; +--- /dev/null ++++ b/include/dt-bindings/clock/econet,en751221-scu.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ ++ ++#ifndef _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_ ++#define _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_ ++ ++#define EN751221_CLK_PCIE 0 ++#define EN751221_CLK_SPI 1 ++#define EN751221_CLK_BUS 2 ++#define EN751221_CLK_CPU 3 ++#define EN751221_CLK_HPT 4 ++#define EN751221_CLK_GSW 5 ++ ++#define EN751221_MAX_CLKS 6 ++ ++#endif /* _DT_BINDINGS_CLOCK_ECONET_EN751221_SCU_H_ */ +\ No newline at end of file +--- /dev/null ++++ b/include/dt-bindings/reset/econet,en751221-scu.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ ++ ++#ifndef __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_ ++#define __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_ ++ ++#define EN751221_XPON_PHY_RST 0 ++#define EN751221_PCM1_ZSI_ISI_RST 1 ++#define EN751221_FE_QDMA1_RST 2 ++#define EN751221_FE_QDMA2_RST 3 ++#define EN751221_FE_UNZIP_RST 4 ++#define EN751221_PCM2_RST 5 ++#define EN751221_PTM_MAC_RST 6 ++#define EN751221_CRYPTO_RST 7 ++#define EN751221_SAR_RST 8 ++#define EN751221_TIMER_RST 9 ++#define EN751221_INTC_RST 10 ++#define EN751221_BONDING_RST 11 ++#define EN751221_PCM1_RST 12 ++#define EN751221_UART_RST 13 ++#define EN751221_GPIO_RST 14 ++#define EN751221_GDMA_RST 15 ++#define EN751221_I2C_MASTER_RST 16 ++#define EN751221_PCM2_ZSI_ISI_RST 17 ++#define EN751221_SFC_RST 18 ++#define EN751221_UART2_RST 19 ++#define EN751221_GDMP_RST 20 ++#define EN751221_FE_RST 21 ++#define EN751221_USB_HOST_P0_RST 22 ++#define EN751221_GSW_RST 23 ++#define EN751221_SFC2_PCM_RST 24 ++#define EN751221_PCIE0_RST 25 ++#define EN751221_PCIE1_RST 26 ++#define EN751221_CPU_TIMER_RST 27 ++#define EN751221_PCIE_HB_RST 28 ++#define EN751221_SIMIF_RST 29 ++#define EN751221_XPON_MAC_RST 30 ++#define EN751221_GFAST_RST 31 ++#define EN751221_CPU_TIMER2_RST 32 ++#define EN751221_UART3_RST 33 ++#define EN751221_UART4_RST 34 ++#define EN751221_UART5_RST 35 ++#define EN751221_I2C2_RST 36 ++#define EN751221_XSI_MAC_RST 37 ++#define EN751221_XSI_PHY_RST 38 ++#define EN751221_DMT_RST 39 ++#define EN751221_USB_PHY_P0_RST 40 ++#define EN751221_USB_PHY_P1_RST 41 ++ ++#endif /* __DT_BINDINGS_RESET_CONTROLLER_ECONET_EN751221_H_ */ diff --git a/target/linux/econet/patches-6.12/911-clk-airoha-add-econet-en751221-clock-reset-support-t.patch b/target/linux/econet/patches-6.12/911-clk-airoha-add-econet-en751221-clock-reset-support-t.patch new file mode 100644 index 00000000000..021043a13d2 --- /dev/null +++ b/target/linux/econet/patches-6.12/911-clk-airoha-add-econet-en751221-clock-reset-support-t.patch @@ -0,0 +1,364 @@ +From 1dfb29374a040ba80d378b3465f4e0bcb67f4ba3 Mon Sep 17 00:00:00 2001 +From: Caleb James DeLisle +Date: Wed, 14 Jan 2026 18:06:13 +0000 +Subject: [PATCH] clk: airoha: Add econet EN751221 clock/reset support to + en7523-scu + +EcoNet EN751221 clock/reset driver is significantly similar to the +EN7523 / EN7581, however the EN751221 does not have a neat batch of clock +divider registers so there are fewer known clocks, and the frequency of +each clock is derived differently. This clock driver will probably work +correctly on EN751627, EN7528, and EN7580. + +Signed-off-by: Caleb James DeLisle +--- + drivers/clk/Kconfig | 6 +- + drivers/clk/clk-en7523.c | 182 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 185 insertions(+), 3 deletions(-) + +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -210,13 +210,13 @@ config COMMON_CLK_CS2000_CP + If you say yes here you get support for the CS2000 clock multiplier. + + config COMMON_CLK_EN7523 +- bool "Clock driver for Airoha EN7523 SoC system clocks" ++ bool "Clock driver for Airoha/EcoNet SoC system clocks" + depends on OF +- depends on ARCH_AIROHA || COMPILE_TEST ++ depends on ARCH_AIROHA || ECONET || COMPILE_TEST + default ARCH_AIROHA + help + This driver provides the fixed clocks and gates present on Airoha +- ARM silicon. ++ and EcoNet silicon. + + config COMMON_CLK_EP93XX + tristate "Clock driver for Cirrus Logic ep93xx SoC" +--- a/drivers/clk/clk-en7523.c ++++ b/drivers/clk/clk-en7523.c +@@ -1,5 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0-only + ++#include + #include + #include + #include +@@ -11,6 +12,8 @@ + #include + #include + #include ++#include ++#include + + #define RST_NR_PER_BANK 32 + +@@ -33,15 +36,47 @@ + #define REG_RESET_CONTROL_PCIEHB BIT(29) + #define REG_RESET_CONTROL_PCIE1 BIT(27) + #define REG_RESET_CONTROL_PCIE2 BIT(26) ++#define REG_HIR 0x064 ++#define REG_HIR_MASK GENMASK(31, 16) + /* EN7581 */ + #define REG_NP_SCU_PCIC 0x88 + #define REG_NP_SCU_SSTR 0x9c + #define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13) + #define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11) + #define REG_CRYPTO_CLKSRC2 0x20c ++/* EN751221 */ ++#define EN751221_REG_SPI_DIV 0x0cc ++#define EN751221_REG_SPI_DIV_MASK GENMASK(31,8) ++#define EN751221_SPI_BASE 500000000 ++#define EN751221_SPI_BASE_EN7526C 400000000 ++#define EN751221_REG_BUS 0x284 ++#define EN751221_REG_BUS_MASK GENMASK(21,12) ++#define EN751221_REG_SSR3 0x094 ++#define EN751221_REG_SSR3_GSW_MASK GENMASK(9,8) + + #define REG_RST_CTRL2 0x830 + #define REG_RST_CTRL1 0x834 ++#define EN751221_REG_RST_DMT 0x84 ++#define EN751221_REG_RST_USB 0xec ++ ++enum en_hir { ++ HIR_UNKNOWN = -1, ++ HIR_TC3169 = 0, ++ HIR_TC3182 = 1, ++ HIR_RT65168 = 2, ++ HIR_RT63165 = 3, ++ HIR_RT63365 = 4, ++ HIR_MT751020 = 5, ++ HIR_MT7505 = 6, ++ HIR_EN751221 = 7, ++ HIR_EN7526C = 8, ++ HIR_EN751627 = 9, ++ HIR_EN7580 = 10, ++ HIR_EN7528 = 11, ++ HIR_EN7523 = 12, ++ HIR_EN7581 = 13, ++ HIR_MAX = 14, ++}; + + struct en_clk_desc { + int id; +@@ -93,6 +128,8 @@ static const u32 bus7581_base[] = { 6000 + static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 }; + static const u32 crypto_base[] = { 540000000, 480000000 }; + static const u32 emmc7581_base[] = { 200000000, 150000000 }; ++/* EN751221 */ ++static const u32 gsw751221_base[] = { 500000000, 250000000, 400000000, 200000000 }; + + static const struct en_clk_desc en7523_base_clks[] = { + { +@@ -300,6 +337,13 @@ static const u16 en7581_rst_ofs[] = { + REG_RST_CTRL1, + }; + ++static const u16 en751221_rst_ofs[] = { ++ REG_RST_CTRL2, ++ REG_RST_CTRL1, ++ EN751221_REG_RST_DMT, ++ EN751221_REG_RST_USB, ++}; ++ + static const u16 en7523_rst_map[] = { + /* RST_CTRL2 */ + [EN7523_XPON_PHY_RST] = 0, +@@ -405,8 +449,61 @@ static const u16 en7581_rst_map[] = { + [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31, + }; + ++static const u16 en751221_rst_map[] = { ++ /* RST_CTRL2 */ ++ [EN751221_XPON_PHY_RST] = 0, ++ [EN751221_GFAST_RST] = 1, ++ [EN751221_CPU_TIMER2_RST] = 2, ++ [EN751221_UART3_RST] = 3, ++ [EN751221_UART4_RST] = 4, ++ [EN751221_UART5_RST] = 5, ++ [EN751221_I2C2_RST] = 6, ++ [EN751221_XSI_MAC_RST] = 7, ++ [EN751221_XSI_PHY_RST] = 8, ++ ++ /* RST_CTRL1 */ ++ [EN751221_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0, ++ [EN751221_FE_QDMA1_RST] = RST_NR_PER_BANK + 1, ++ [EN751221_FE_QDMA2_RST] = RST_NR_PER_BANK + 2, ++ [EN751221_FE_UNZIP_RST] = RST_NR_PER_BANK + 3, ++ [EN751221_PCM2_RST] = RST_NR_PER_BANK + 4, ++ [EN751221_PTM_MAC_RST] = RST_NR_PER_BANK + 5, ++ [EN751221_CRYPTO_RST] = RST_NR_PER_BANK + 6, ++ [EN751221_SAR_RST] = RST_NR_PER_BANK + 7, ++ [EN751221_TIMER_RST] = RST_NR_PER_BANK + 8, ++ [EN751221_INTC_RST] = RST_NR_PER_BANK + 9, ++ [EN751221_BONDING_RST] = RST_NR_PER_BANK + 10, ++ [EN751221_PCM1_RST] = RST_NR_PER_BANK + 11, ++ [EN751221_UART_RST] = RST_NR_PER_BANK + 12, ++ [EN751221_GPIO_RST] = RST_NR_PER_BANK + 13, ++ [EN751221_GDMA_RST] = RST_NR_PER_BANK + 14, ++ [EN751221_I2C_MASTER_RST] = RST_NR_PER_BANK + 16, ++ [EN751221_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17, ++ [EN751221_SFC_RST] = RST_NR_PER_BANK + 18, ++ [EN751221_UART2_RST] = RST_NR_PER_BANK + 19, ++ [EN751221_GDMP_RST] = RST_NR_PER_BANK + 20, ++ [EN751221_FE_RST] = RST_NR_PER_BANK + 21, ++ [EN751221_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22, ++ [EN751221_GSW_RST] = RST_NR_PER_BANK + 23, ++ [EN751221_SFC2_PCM_RST] = RST_NR_PER_BANK + 25, ++ [EN751221_PCIE0_RST] = RST_NR_PER_BANK + 26, ++ [EN751221_PCIE1_RST] = RST_NR_PER_BANK + 27, ++ [EN751221_CPU_TIMER_RST] = RST_NR_PER_BANK + 28, ++ [EN751221_PCIE_HB_RST] = RST_NR_PER_BANK + 29, ++ [EN751221_SIMIF_RST] = RST_NR_PER_BANK + 30, ++ [EN751221_XPON_MAC_RST] = RST_NR_PER_BANK + 31, ++ ++ /* RST_DMT */ ++ [EN751221_DMT_RST] = 2 * RST_NR_PER_BANK + 0, ++ ++ /* RST_USB */ ++ [EN751221_USB_PHY_P0_RST] = 3 * RST_NR_PER_BANK + 6, ++ [EN751221_USB_PHY_P1_RST] = 3 * RST_NR_PER_BANK + 7, ++}; ++ + static int en7581_reset_register(struct device *dev, void __iomem *base, +- const u16 *rst_map, int nr_resets); ++ const u16 *rst_map, int nr_resets, ++ const u16 *rst_reg_ofs); + + static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val) + { +@@ -604,7 +701,8 @@ static int en7523_clk_hw_init(struct pla + en7523_register_clocks(&pdev->dev, clk_data, base, np_base); + + return en7581_reset_register(&pdev->dev, np_base, en7523_rst_map, +- ARRAY_SIZE(en7523_rst_map)); ++ ARRAY_SIZE(en7523_rst_map), ++ en7581_rst_ofs); + } + + static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data, +@@ -705,7 +803,8 @@ static const struct reset_control_ops en + }; + + static int en7581_reset_register(struct device *dev, void __iomem *base, +- const u16 *rst_map, int nr_resets) ++ const u16 *rst_map, int nr_resets, ++ const u16 *rst_reg_ofs) + { + struct en_rst_data *rst_data; + +@@ -713,7 +812,7 @@ static int en7581_reset_register(struct + if (!rst_data) + return -ENOMEM; + +- rst_data->bank_ofs = en7581_rst_ofs; ++ rst_data->bank_ofs = rst_reg_ofs; + rst_data->idx_map = rst_map; + rst_data->base = base; + +@@ -752,7 +851,123 @@ static int en7581_clk_hw_init(struct pla + writel(val | 3, base + REG_NP_SCU_PCIC); + + return en7581_reset_register(&pdev->dev, base, en7581_rst_map, +- ARRAY_SIZE(en7581_rst_map)); ++ ARRAY_SIZE(en7581_rst_map), ++ en7581_rst_ofs); ++} ++ ++static enum en_hir get_hw_id(void __iomem *np_base) ++{ ++ u32 val = FIELD_GET(REG_HIR_MASK, readl(np_base + REG_HIR)); ++ ++ if (val < HIR_MAX) ++ return (enum en_hir) val; ++ ++ return HIR_UNKNOWN; ++} ++ ++static void en751221_try_register_clk(struct device *dev, int key, ++ struct clk_hw_onecell_data *clk_data, ++ const char *name, u32 rate) ++{ ++ struct clk_hw *hw; ++ ++ hw = clk_hw_register_fixed_rate(dev, name, NULL, 0, rate); ++ if (IS_ERR(hw)) ++ pr_err("Failed to register clk %s: %pe\n", name, hw); ++ else ++ clk_data->hws[key] = hw; ++} ++ ++static void en751221_register_clocks(struct device *dev, ++ struct clk_hw_onecell_data *clk_data, ++ struct regmap *map, void __iomem *np_base) ++{ ++ enum en_hir hid = get_hw_id(np_base); ++ struct clk_hw *hw; ++ u32 rate; ++ u32 div; ++ int err; ++ ++ /* PCI */ ++ hw = en7523_register_pcie_clk(dev, np_base); ++ clk_data->hws[EN751221_CLK_PCIE] = hw; ++ ++ /* SPI */ ++ rate = EN751221_SPI_BASE; ++ if (hid == HIR_EN7526C) ++ rate = EN751221_SPI_BASE_EN7526C; ++ ++ err = regmap_read(map, EN751221_REG_SPI_DIV, &div); ++ if (err) { ++ pr_err("Failed reading fixed clk div %s: %d\n", ++ "spi", err); ++ } else { ++ div = FIELD_GET(EN751221_REG_SPI_DIV_MASK, div) * 2; ++ if (!div) ++ div = 40; ++ ++ en751221_try_register_clk(dev, EN751221_CLK_SPI, clk_data, ++ "spi", rate / div); ++ } ++ ++ /* BUS */ ++ rate = FIELD_GET(EN751221_REG_BUS_MASK, ++ readl(np_base + EN751221_REG_BUS)); ++ rate *= 1000000; ++ en751221_try_register_clk(dev, EN751221_CLK_BUS, clk_data, "bus", ++ rate); ++ ++ /* CPU */ ++ en751221_try_register_clk(dev, EN751221_CLK_CPU, clk_data, "cpu", ++ rate * 4); ++ ++ /* HPT */ ++ switch (hid) { ++ case HIR_EN751221: ++ case HIR_EN751627: ++ case HIR_EN7526C: ++ case HIR_EN7580: ++ case HIR_EN7528: ++ rate = 200000000; ++ break; ++ case HIR_MT7505: ++ rate = 100000000; ++ break; ++ case HIR_MT751020: ++ rate = 800000000 / 3; ++ break; ++ default: ++ rate = 250000000; ++ } ++ en751221_try_register_clk(dev, EN751221_CLK_HPT, clk_data, "hpt", ++ rate); ++ ++ /* GSW */ ++ rate = FIELD_GET(EN751221_REG_SSR3_GSW_MASK, ++ readl(np_base + EN751221_REG_SSR3)); ++ en751221_try_register_clk(dev, EN751221_CLK_GSW, clk_data, "gsw", ++ gsw751221_base[rate]); ++} ++ ++static int en751221_clk_hw_init(struct platform_device *pdev, ++ struct clk_hw_onecell_data *clk_data) ++{ ++ struct regmap *map; ++ void __iomem *base; ++ ++ map = syscon_regmap_lookup_by_compatible("econet,en751221-chip-scu"); ++ if (IS_ERR(map)) ++ return PTR_ERR(map); ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ en751221_register_clocks(&pdev->dev, clk_data, map, base); ++ ++ return en7581_reset_register(&pdev->dev, base, en751221_rst_map, ++ ARRAY_SIZE(en751221_rst_map), ++ en751221_rst_ofs); + } + + static int en7523_clk_probe(struct platform_device *pdev) +@@ -799,9 +1014,20 @@ static const struct en_clk_soc_data en75 + .hw_init = en7581_clk_hw_init, + }; + ++static const struct en_clk_soc_data en751221_data = { ++ .num_clocks = EN751221_MAX_CLKS, ++ .pcie_ops = { ++ .is_enabled = en7523_pci_is_enabled, ++ .prepare = en7523_pci_prepare, ++ .unprepare = en7523_pci_unprepare, ++ }, ++ .hw_init = en751221_clk_hw_init, ++}; ++ + static const struct of_device_id of_match_clk_en7523[] = { + { .compatible = "airoha,en7523-scu", .data = &en7523_data }, + { .compatible = "airoha,en7581-scu", .data = &en7581_data }, ++ { .compatible = "econet,en751221-scu", .data = &en751221_data }, + { /* sentinel */ } + }; + diff --git a/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch b/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch new file mode 100644 index 00000000000..ee8d1bdab9d --- /dev/null +++ b/target/linux/econet/patches-6.12/912-pcie-add-en7528-pcie-and-phy-support.patch @@ -0,0 +1,373 @@ +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -187,7 +187,7 @@ config PCI_MVEBU + + config PCIE_MEDIATEK + tristate "MediaTek PCIe controller" +- depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST ++ depends on ARCH_AIROHA || ARCH_MEDIATEK || ECONET || COMPILE_TEST + depends on OF + depends on PCI_MSI + help +--- a/arch/mips/econet/Kconfig ++++ b/arch/mips/econet/Kconfig +@@ -14,7 +14,9 @@ choice + select COMMON_CLK + select CPU_BIG_ENDIAN + select ECONET_EN751221_INTC ++ select HAVE_PCI + select IRQ_MIPS_CPU ++ select PCI_DRIVERS_GENERIC + select SMP + select SMP_UP + select SYS_SUPPORTS_SMP +@@ -28,9 +30,11 @@ choice + bool "EN7528 family" + select COMMON_CLK + select CPU_LITTLE_ENDIAN ++ select HAVE_PCI + select IRQ_MIPS_CPU + select MIPS_CPU_SCACHE + select MIPS_GIC ++ select PCI_DRIVERS_GENERIC + select SMP + select SMP_UP + select SYS_SUPPORTS_HIGHMEM +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -76,6 +76,7 @@ + + #define PCIE_CONF_VEND_ID 0x100 + #define PCIE_CONF_DEVICE_ID 0x102 ++#define PCIE_CONF_REV_CLASS 0x104 + #define PCIE_CONF_CLASS_ID 0x106 + + #define PCIE_INT_MASK 0x420 +@@ -88,6 +89,11 @@ + #define MSI_MASK BIT(23) + #define MTK_MSI_IRQS_NUM 32 + ++#define EN7528_HOST_MODE 0x00804201 ++#define EN7528_LINKUP_REG 0x50 ++#define EN7528_RC0_LINKUP BIT(1) ++#define EN7528_RC1_LINKUP BIT(2) ++ + #define PCIE_AHB_TRANS_BASE0_L 0x438 + #define PCIE_AHB_TRANS_BASE0_H 0x43c + #define AHB2PCIE_SIZE(x) ((x) & GENMASK(4, 0)) +@@ -750,6 +756,86 @@ static int mtk_pcie_startup_port_v2(stru + return 0; + } + ++static int mtk_pcie_startup_port_en7528(struct mtk_pcie_port *port) ++{ ++ struct mtk_pcie *pcie = port->pcie; ++ struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); ++ struct resource *mem = NULL; ++ struct resource_entry *entry; ++ u32 val, link_mask; ++ int err; ++ ++ entry = resource_list_first_type(&host->windows, IORESOURCE_MEM); ++ if (entry) ++ mem = entry->res; ++ if (!mem) ++ return -EINVAL; ++ ++ if (!pcie->cfg) { ++ dev_err(pcie->dev, "EN7528: pciecfg syscon not available\n"); ++ return -EINVAL; ++ } ++ ++ /* Assert all reset signals */ ++ writel(0, port->base + PCIE_RST_CTRL); ++ ++ /* ++ * Enable PCIe link down reset, if link status changed from link up to ++ * link down, this will reset MAC control registers and configuration ++ * space. ++ */ ++ writel(PCIE_LINKDOWN_RST_EN, port->base + PCIE_RST_CTRL); ++ ++ /* ++ * Described in PCIe CEM specification sections 2.2 (PERST# Signal) and ++ * 2.2.1 (Initial Power-Up (G3 to S0)). The deassertion of PERST# ++ * should be delayed 100ms (TPVPERL) for the power and clock to become ++ * stable. ++ */ ++ msleep(100); ++ ++ /* De-assert PHY, PE, PIPE, MAC and configuration reset */ ++ val = readl(port->base + PCIE_RST_CTRL); ++ val |= PCIE_PHY_RSTB | PCIE_PERSTB | PCIE_PIPE_SRSTB | ++ PCIE_MAC_SRSTB | PCIE_CRSTB; ++ writel(val, port->base + PCIE_RST_CTRL); ++ ++ writel(PCIE_CLASS_CODE | PCIE_REVISION_ID, ++ port->base + PCIE_CONF_REV_CLASS); ++ writel(EN7528_HOST_MODE, port->base); ++ ++ link_mask = (port->slot == 0) ? EN7528_RC0_LINKUP : EN7528_RC1_LINKUP; ++ ++ /* 100ms timeout value should be enough for Gen1/2 training */ ++ err = regmap_read_poll_timeout(pcie->cfg, EN7528_LINKUP_REG, val, ++ !!(val & link_mask), 20, ++ 100 * USEC_PER_MSEC); ++ if (err) { ++ dev_err(pcie->dev, "EN7528: port%d link timeout\n", port->slot); ++ return -ETIMEDOUT; ++ } ++ ++ /* Set INTx mask */ ++ val = readl(port->base + PCIE_INT_MASK); ++ val &= ~INTX_MASK; ++ writel(val, port->base + PCIE_INT_MASK); ++ ++ if (IS_ENABLED(CONFIG_PCI_MSI)) ++ mtk_pcie_enable_msi(port); ++ ++ /* Set AHB to PCIe translation windows */ ++ val = lower_32_bits(mem->start) | ++ AHB2PCIE_SIZE(fls(resource_size(mem))); ++ writel(val, port->base + PCIE_AHB_TRANS_BASE0_L); ++ ++ val = upper_32_bits(mem->start); ++ writel(val, port->base + PCIE_AHB_TRANS_BASE0_H); ++ ++ writel(WIN_ENABLE, port->base + PCIE_AXI_WINDOW0); ++ ++ return 0; ++} ++ + static void __iomem *mtk_pcie_map_bus(struct pci_bus *bus, + unsigned int devfn, int where) + { +@@ -1116,6 +1202,20 @@ static int mtk_pcie_probe(struct platfor + if (err) + goto put_resources; + ++ /* Retrain Gen1 links to reach Gen2 where supported */ ++ if (pcie->soc->startup == mtk_pcie_startup_port_en7528) { ++ struct pci_bus *bus = host->bus; ++ struct pci_dev *rc = NULL; ++ ++ while ((rc = pci_get_class(PCI_CLASS_BRIDGE_PCI << 8, rc))) { ++ if (rc->bus != bus) ++ continue; ++ if (!pcie_retrain_link(rc, true)) ++ dev_info(dev, "port%d link retrained\n", ++ PCI_SLOT(rc->devfn)); ++ } ++ } ++ + return 0; + + put_resources: +@@ -1225,12 +1325,19 @@ static const struct mtk_pcie_soc mtk_pci + .setup_irq = mtk_pcie_setup_irq, + }; + ++static const struct mtk_pcie_soc mtk_pcie_soc_en7528 = { ++ .ops = &mtk_pcie_ops_v2, ++ .startup = mtk_pcie_startup_port_en7528, ++ .setup_irq = mtk_pcie_setup_irq, ++}; ++ + static const struct of_device_id mtk_pcie_ids[] = { + { .compatible = "mediatek,mt2701-pcie", .data = &mtk_pcie_soc_v1 }, + { .compatible = "mediatek,mt7623-pcie", .data = &mtk_pcie_soc_v1 }, + { .compatible = "mediatek,mt2712-pcie", .data = &mtk_pcie_soc_mt2712 }, + { .compatible = "mediatek,mt7622-pcie", .data = &mtk_pcie_soc_mt7622 }, + { .compatible = "mediatek,mt7629-pcie", .data = &mtk_pcie_soc_mt7629 }, ++ { .compatible = "econet,en7528-pcie", .data = &mtk_pcie_soc_en7528 }, + {}, + }; + MODULE_DEVICE_TABLE(of, mtk_pcie_ids); +--- a/drivers/phy/Kconfig ++++ b/drivers/phy/Kconfig +@@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE + This driver create the basic PHY instance and provides initialize + callback for PCIe GEN3 port. + ++config PHY_EN7528_PCIE ++ tristate "EcoNet EN7528 PCIe PHY Driver" ++ depends on ECONET || COMPILE_TEST ++ depends on OF ++ select GENERIC_PHY ++ select REGMAP_MMIO ++ help ++ Say Y here to add support for EcoNet EN7528 PCIe PHY driver. ++ This driver provides PHY initialization for the two PCIe ports ++ on EN7528 SoC. ++ + source "drivers/phy/allwinner/Kconfig" + source "drivers/phy/amlogic/Kconfig" + source "drivers/phy/broadcom/Kconfig" +--- a/drivers/phy/Makefile ++++ b/drivers/phy/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o + obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o + obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o + obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o ++obj-$(CONFIG_PHY_EN7528_PCIE) += phy-en7528-pcie.o + obj-y += allwinner/ \ + amlogic/ \ + broadcom/ \ +--- /dev/null ++++ b/drivers/phy/phy-en7528-pcie.c +@@ -0,0 +1,155 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2026 Ahmed Naseef ++ * ++ * EcoNet EN7528 PCIe PHY Driver ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct en7528_pcie_phy_op { ++ u32 reg; ++ u32 mask; ++ u32 val; ++}; ++ ++struct en7528_pcie_phy { ++ struct regmap *regmap; ++ const struct en7528_pcie_phy_op *data; ++}; ++ ++/* Port 0 PHY: set LCDDS_CLK_PH_INV for PLL operation */ ++static const struct en7528_pcie_phy_op en7528_phy_port0[] = { ++ { ++ .reg = 0x4a0, ++ .mask = BIT(5), ++ .val = BIT(5), ++ }, ++ { /* sentinel */ } ++}; ++ ++/* Port 1 PHY: Rx impedance tuning, target R -5 Ohm */ ++static const struct en7528_pcie_phy_op en7528_phy_port1[] = { ++ { ++ .reg = 0xb2c, ++ .mask = GENMASK(13, 12), ++ .val = BIT(12), ++ }, ++ { /* sentinel */ } ++}; ++ ++/* EN751221 Port 1 PHY */ ++static const struct en7528_pcie_phy_op en751221_phy_port1[] = { ++ /* Rx Detection Timing for 7512 E1, 16*8 clock cycles */ ++ { ++ .reg = 0xa28, ++ .mask = GENMASK(17, 9), ++ .val = 16 << 9, ++ }, ++ /* Same for different power mode */ ++ { ++ .reg = 0xa2c, ++ .mask = GENMASK(8, 0), ++ .val = 16, ++ }, ++ { /* sentinel */ } ++}; ++ ++static int en7528_pcie_phy_init(struct phy *phy) ++{ ++ struct en7528_pcie_phy *ephy = phy_get_drvdata(phy); ++ const struct en7528_pcie_phy_op *data = ephy->data; ++ int i, ret; ++ ++ for (i = 0; data[i].mask || data[i].val; i++) { ++ if (i) ++ usleep_range(1000, 2000); ++ ++ ret = regmap_update_bits(ephy->regmap, data[i].reg, ++ data[i].mask, data[i].val); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct phy_ops en7528_pcie_phy_ops = { ++ .init = en7528_pcie_phy_init, ++ .owner = THIS_MODULE, ++}; ++ ++static int en7528_pcie_phy_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct en7528_pcie_phy_op *data; ++ struct regmap_config regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ }; ++ struct phy_provider *provider; ++ struct en7528_pcie_phy *ephy; ++ void __iomem *base; ++ struct phy *phy; ++ int i; ++ ++ data = of_device_get_match_data(dev); ++ if (!data) ++ return -EINVAL; ++ ++ ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL); ++ if (!ephy) ++ return -ENOMEM; ++ ++ ephy->data = data; ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ for (i = 0; data[i].mask || data[i].val; i++) ++ if (data[i].reg > regmap_config.max_register) ++ regmap_config.max_register = data[i].reg; ++ ++ ephy->regmap = devm_regmap_init_mmio(dev, base, ®map_config); ++ if (IS_ERR(ephy->regmap)) ++ return PTR_ERR(ephy->regmap); ++ ++ phy = devm_phy_create(dev, dev->of_node, &en7528_pcie_phy_ops); ++ if (IS_ERR(phy)) ++ return PTR_ERR(phy); ++ ++ phy_set_drvdata(phy, ephy); ++ ++ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(provider); ++} ++ ++static const struct of_device_id en7528_pcie_phy_ids[] = { ++ { .compatible = "econet,en7528-pcie-phy0", .data = en7528_phy_port0 }, ++ { .compatible = "econet,en7528-pcie-phy1", .data = en7528_phy_port1 }, ++ { .compatible = "econet,en751221-pcie-phy0", .data = en7528_phy_port0 }, ++ { .compatible = "econet,en751221-pcie-phy1", .data = en751221_phy_port1 }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, en7528_pcie_phy_ids); ++ ++static struct platform_driver en7528_pcie_phy_driver = { ++ .probe = en7528_pcie_phy_probe, ++ .driver = { ++ .name = "en7528-pcie-phy", ++ .of_match_table = en7528_pcie_phy_ids, ++ }, ++}; ++module_platform_driver(en7528_pcie_phy_driver); ++ ++MODULE_AUTHOR("Ahmed Naseef "); ++MODULE_DESCRIPTION("EcoNet EN7528 PCIe PHY driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch b/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch new file mode 100644 index 00000000000..872843549d1 --- /dev/null +++ b/target/linux/econet/patches-6.12/913-pcie-fix-bogus-prefetch-window.patch @@ -0,0 +1,38 @@ +Subject: [PATCH] PCI: Skip bridge window reads when window is not supported + +pci_read_bridge_io() and pci_read_bridge_mmio_pref() read bridge window +registers unconditionally. If the registers are hardwired to zero +(not implemented), both base and limit will be 0. Since (0 <= 0) is +true, a bogus window [mem 0x00000000-0x000fffff] or [io 0x0000-0x0fff] +gets created. + +pci_read_bridge_windows() already detects unsupported windows by +testing register writability and sets io_window/pref_window flags +accordingly. Check these flags at the start of pci_read_bridge_io() +and pci_read_bridge_mmio_pref() to skip reading registers when the +window is not supported. + +Suggested-by: Bjorn Helgaas +Signed-off-by: Ahmed Naseef +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -349,6 +349,9 @@ static void pci_read_bridge_io(struct pc + unsigned long io_mask, io_granularity, base, limit; + struct pci_bus_region region; + ++ if (!dev->io_window) ++ return; ++ + io_mask = PCI_IO_RANGE_MASK; + io_granularity = 0x1000; + if (dev->io_window_1k) { +@@ -410,6 +413,9 @@ static void pci_read_bridge_mmio_pref(st + pci_bus_addr_t base, limit; + struct pci_bus_region region; + ++ if (!dev->pref_window) ++ return; ++ + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; diff --git a/target/linux/econet/patches-6.12/914-phy-add-en7528-usb-phy-driver.patch b/target/linux/econet/patches-6.12/914-phy-add-en7528-usb-phy-driver.patch new file mode 100644 index 00000000000..308703c630a --- /dev/null +++ b/target/linux/econet/patches-6.12/914-phy-add-en7528-usb-phy-driver.patch @@ -0,0 +1,358 @@ +From: Ahmed Naseef +Subject: phy: add EN7528 USB PHY driver + +Add USB PHY driver for EcoNet EN7528 SoC. + +Based on GPL vendor code at https://github.com/keenetic/kernel-49 +and the Airoha AN7581 USB PHY driver by Christian Marangi. + +Signed-off-by: Ahmed Naseef +--- a/drivers/phy/Kconfig ++++ b/drivers/phy/Kconfig +@@ -93,6 +93,17 @@ config PHY_EN7528_PCIE + This driver provides PHY initialization for the two PCIe ports + on EN7528 SoC. + ++config PHY_EN7528_USB ++ tristate "EcoNet EN7528 USB PHY Driver" ++ depends on ECONET || COMPILE_TEST ++ depends on OF ++ select GENERIC_PHY ++ select REGMAP_MMIO ++ help ++ Say 'Y' here to add support for EcoNet EN7528 USB PHY driver. ++ This driver creates the basic PHY instance and provides ++ initialization callback for the USB port. ++ + source "drivers/phy/allwinner/Kconfig" + source "drivers/phy/amlogic/Kconfig" + source "drivers/phy/broadcom/Kconfig" +--- a/drivers/phy/Makefile ++++ b/drivers/phy/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy- + obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o + obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o + obj-$(CONFIG_PHY_EN7528_PCIE) += phy-en7528-pcie.o ++obj-$(CONFIG_PHY_EN7528_USB) += phy-en7528-usb.o + obj-y += allwinner/ \ + amlogic/ \ + broadcom/ \ +--- /dev/null ++++ b/drivers/phy/phy-en7528-usb.c +@@ -0,0 +1,316 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * EcoNet EN7528 USB PHY driver ++ * ++ * Based on GPL vendor code at https://github.com/keenetic/kernel-49 ++ * and the Airoha AN7581 USB PHY driver by ++ * Christian Marangi ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Frequency Meter registers (shared across ports) */ ++#define EN7528_USB_PHY_FMCR0 0x100 ++#define EN7528_USB_PHY_MONCLK_SEL GENMASK(27, 26) ++#define EN7528_USB_PHY_FREQDET_EN BIT(24) ++#define EN7528_USB_PHY_CYCLECNT GENMASK(23, 0) ++#define EN7528_USB_PHY_FMMONR0 0x10c ++#define EN7528_USB_PHY_FMMONR1 0x110 ++#define EN7528_USB_PHY_FRCK_EN BIT(8) ++ ++/* U2 PHY port bases */ ++#define EN7528_USB_PHY_U2_P0_BASE 0x300 ++#define EN7528_USB_PHY_U2_P1_BASE 0x1300 ++#define EN7528_USB_PHY_NUM_U2_PORTS 2 ++ ++/* U2 PHY register offsets (relative to port base) */ ++#define EN7528_USB_PHY_ACR0 0x10 ++#define EN7528_USB_PHY_HSTX_SRCAL_EN BIT(23) ++#define EN7528_USB_PHY_HSTX_SRCTRL GENMASK(18, 16) ++#define EN7528_USB_PHY_ACR3 0x1c ++#define EN7528_USB_PHY_ACR3_ENABLE 0xC0240000 ++ ++/* U3 PHYA registers (base at +0xb00) */ ++#define EN7528_USB_PHY_U3_PHYA_REG11 0xb2c ++#define EN7528_USB_PHY_RX_IMPSEL GENMASK(13, 12) ++ ++#define EN7528_USB_PHY_FM_DET_CYCLE_CNT 1024 ++#define EN7528_USB_PHY_REF_CK 20 /* MHz */ ++#define EN7528_USB_PHY_SR_COEF 28 ++#define EN7528_USB_PHY_SR_COEF_DIVISOR 1000 ++#define EN7528_USB_PHY_DEFAULT_SR 4 ++ ++#define EN7528_USB_PHY_FREQDET_SLEEP 1000 /* 1ms */ ++#define EN7528_USB_PHY_FREQDET_TIMEOUT (EN7528_USB_PHY_FREQDET_SLEEP * 10) ++ ++static const unsigned int en7528_u2_port_bases[EN7528_USB_PHY_NUM_U2_PORTS] = { ++ EN7528_USB_PHY_U2_P0_BASE, ++ EN7528_USB_PHY_U2_P1_BASE, ++}; ++ ++struct en7528_usb_phy_instance { ++ struct phy *phy; ++ u32 type; ++}; ++ ++enum en7528_usb_phy_type { ++ EN7528_PHY_USB2, ++ EN7528_PHY_USB3, ++ ++ EN7528_PHY_USB_MAX, ++}; ++ ++struct en7528_usb_phy_priv { ++ struct device *dev; ++ struct regmap *regmap; ++ ++ struct en7528_usb_phy_instance *phys[EN7528_PHY_USB_MAX]; ++}; ++ ++static void en7528_usb_phy_slew_rate_calibration(struct en7528_usb_phy_priv *priv, ++ unsigned int port_id, ++ unsigned int port_base) ++{ ++ unsigned int acr0 = port_base + EN7528_USB_PHY_ACR0; ++ u32 fm_out; ++ u32 srctrl; ++ ++ /* Enable HS TX SR calibration */ ++ regmap_set_bits(priv->regmap, acr0, ++ EN7528_USB_PHY_HSTX_SRCAL_EN); ++ ++ usleep_range(1000, 1500); ++ ++ /* Enable free run clock */ ++ regmap_set_bits(priv->regmap, EN7528_USB_PHY_FMMONR1, ++ EN7528_USB_PHY_FRCK_EN); ++ ++ /* Select monitor clock: port 0 = MONCLK_SEL 0, port 1 = MONCLK_SEL 1 */ ++ regmap_update_bits(priv->regmap, EN7528_USB_PHY_FMCR0, ++ EN7528_USB_PHY_MONCLK_SEL, ++ FIELD_PREP(EN7528_USB_PHY_MONCLK_SEL, port_id)); ++ ++ /* Set cycle count */ ++ regmap_update_bits(priv->regmap, EN7528_USB_PHY_FMCR0, ++ EN7528_USB_PHY_CYCLECNT, ++ FIELD_PREP(EN7528_USB_PHY_CYCLECNT, ++ EN7528_USB_PHY_FM_DET_CYCLE_CNT)); ++ ++ /* Enable frequency meter */ ++ regmap_set_bits(priv->regmap, EN7528_USB_PHY_FMCR0, ++ EN7528_USB_PHY_FREQDET_EN); ++ ++ /* Timeout can happen and we will apply default value at the end */ ++ (void)regmap_read_poll_timeout(priv->regmap, EN7528_USB_PHY_FMMONR0, ++ fm_out, fm_out, ++ EN7528_USB_PHY_FREQDET_SLEEP, ++ EN7528_USB_PHY_FREQDET_TIMEOUT); ++ ++ /* Disable frequency meter */ ++ regmap_clear_bits(priv->regmap, EN7528_USB_PHY_FMCR0, ++ EN7528_USB_PHY_FREQDET_EN); ++ ++ /* Disable free run clock */ ++ regmap_clear_bits(priv->regmap, EN7528_USB_PHY_FMMONR1, ++ EN7528_USB_PHY_FRCK_EN); ++ ++ /* Disable HS TX SR calibration */ ++ regmap_clear_bits(priv->regmap, acr0, ++ EN7528_USB_PHY_HSTX_SRCAL_EN); ++ ++ usleep_range(1000, 1500); ++ ++ if (!fm_out) { ++ srctrl = EN7528_USB_PHY_DEFAULT_SR; ++ dev_err(priv->dev, "port%u: frequency not detected, using default SR calibration.\n", ++ port_id); ++ } else { ++ /* (1024 / FM_OUT) * REF_CK * SR_COEF */ ++ srctrl = EN7528_USB_PHY_REF_CK * EN7528_USB_PHY_SR_COEF; ++ srctrl = (srctrl * EN7528_USB_PHY_FM_DET_CYCLE_CNT) / fm_out; ++ srctrl = DIV_ROUND_CLOSEST(srctrl, EN7528_USB_PHY_SR_COEF_DIVISOR); ++ dev_dbg(priv->dev, "port%u: SR calibration applied: %x\n", ++ port_id, srctrl); ++ } ++ ++ regmap_update_bits(priv->regmap, acr0, ++ EN7528_USB_PHY_HSTX_SRCTRL, ++ FIELD_PREP(EN7528_USB_PHY_HSTX_SRCTRL, srctrl)); ++} ++ ++static int en7528_usb_phy_init(struct phy *phy) ++{ ++ struct en7528_usb_phy_instance *instance = phy_get_drvdata(phy); ++ struct en7528_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent); ++ unsigned int i; ++ ++ switch (instance->type) { ++ case PHY_TYPE_USB2: ++ /* Enable both U2 PHY ports before calibration */ ++ for (i = 0; i < EN7528_USB_PHY_NUM_U2_PORTS; i++) ++ regmap_write(priv->regmap, ++ en7528_u2_port_bases[i] + EN7528_USB_PHY_ACR3, ++ EN7528_USB_PHY_ACR3_ENABLE); ++ break; ++ case PHY_TYPE_USB3: ++ /* Combo PHY Rx R mean value too high, tune -5 Ohm */ ++ regmap_update_bits(priv->regmap, ++ EN7528_USB_PHY_U3_PHYA_REG11, ++ EN7528_USB_PHY_RX_IMPSEL, ++ FIELD_PREP(EN7528_USB_PHY_RX_IMPSEL, 0x1)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int en7528_usb_phy_power_on(struct phy *phy) ++{ ++ struct en7528_usb_phy_instance *instance = phy_get_drvdata(phy); ++ struct en7528_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent); ++ unsigned int i; ++ ++ if (instance->type != PHY_TYPE_USB2) ++ return 0; ++ ++ /* Calibrate slew rate for both U2 PHY ports */ ++ for (i = 0; i < EN7528_USB_PHY_NUM_U2_PORTS; i++) ++ en7528_usb_phy_slew_rate_calibration(priv, i, ++ en7528_u2_port_bases[i]); ++ ++ return 0; ++} ++ ++static const struct phy_ops en7528_usb_phy_ops = { ++ .init = en7528_usb_phy_init, ++ .power_on = en7528_usb_phy_power_on, ++ .owner = THIS_MODULE, ++}; ++ ++static struct phy *en7528_usb_phy_xlate(struct device *dev, ++ const struct of_phandle_args *args) ++{ ++ struct en7528_usb_phy_priv *priv = dev_get_drvdata(dev); ++ struct en7528_usb_phy_instance *instance = NULL; ++ unsigned int index, phy_type; ++ ++ if (args->args_count != 1) { ++ dev_err(dev, "invalid number of cells in 'phy' property\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ phy_type = args->args[0]; ++ if (!(phy_type == PHY_TYPE_USB2 || phy_type == PHY_TYPE_USB3)) { ++ dev_err(dev, "unsupported device type: %d\n", phy_type); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ for (index = 0; index < EN7528_PHY_USB_MAX; index++) ++ if (priv->phys[index] && ++ phy_type == priv->phys[index]->type) { ++ instance = priv->phys[index]; ++ break; ++ } ++ ++ if (!instance) { ++ dev_err(dev, "failed to find appropriate phy\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ return instance->phy; ++} ++ ++static const struct regmap_config en7528_usb_phy_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = EN7528_USB_PHY_U2_P1_BASE + EN7528_USB_PHY_ACR3, ++}; ++ ++static int en7528_usb_phy_probe(struct platform_device *pdev) ++{ ++ struct phy_provider *phy_provider; ++ struct en7528_usb_phy_priv *priv; ++ struct device *dev = &pdev->dev; ++ unsigned int index; ++ void *base; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ priv->regmap = devm_regmap_init_mmio(dev, base, ++ &en7528_usb_phy_regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ for (index = 0; index < EN7528_PHY_USB_MAX; index++) { ++ struct en7528_usb_phy_instance *instance; ++ enum en7528_usb_phy_type phy_type; ++ ++ switch (index) { ++ case EN7528_PHY_USB2: ++ phy_type = PHY_TYPE_USB2; ++ break; ++ case EN7528_PHY_USB3: ++ phy_type = PHY_TYPE_USB3; ++ break; ++ default: ++ continue; ++ } ++ ++ instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); ++ if (!instance) ++ return -ENOMEM; ++ ++ instance->type = phy_type; ++ priv->phys[index] = instance; ++ ++ instance->phy = devm_phy_create(dev, NULL, &en7528_usb_phy_ops); ++ if (IS_ERR(instance->phy)) ++ return dev_err_probe(dev, PTR_ERR(instance->phy), ++ "failed to create phy\n"); ++ ++ phy_set_drvdata(instance->phy, instance); ++ } ++ ++ phy_provider = devm_of_phy_provider_register(dev, ++ en7528_usb_phy_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id en7528_usb_phy_match[] = { ++ { .compatible = "econet,en7528-usb-phy" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, en7528_usb_phy_match); ++ ++static struct platform_driver en7528_usb_phy_driver = { ++ .probe = en7528_usb_phy_probe, ++ .driver = { ++ .name = "en7528-usb-phy", ++ .of_match_table = en7528_usb_phy_match, ++ }, ++}; ++ ++module_platform_driver(en7528_usb_phy_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("EcoNet EN7528 USB PHY driver"); diff --git a/target/linux/econet/patches-6.12/915-usb-xhci-mtk-add-en7528-ltssm-quirk.patch b/target/linux/econet/patches-6.12/915-usb-xhci-mtk-add-en7528-ltssm-quirk.patch new file mode 100644 index 00000000000..78e5ca5d4cd --- /dev/null +++ b/target/linux/econet/patches-6.12/915-usb-xhci-mtk-add-en7528-ltssm-quirk.patch @@ -0,0 +1,58 @@ +From: Ahmed Naseef +Subject: usb: xhci-mtk: add EN7528 LTSSM timing quirk + +EN7528 needs LTSSM Timing Parameter 5 configured to fix +TD 6.5 compliance test failures. + +Based on GPL vendor code: +https://github.com/keenetic/kernel-49/commit/ee0e0b7cf28c208cd5b892ea96180ffae0de9b7f + +Signed-off-by: Ahmed Naseef +--- a/drivers/usb/host/xhci-mtk.c ++++ b/drivers/usb/host/xhci-mtk.c +@@ -80,6 +80,8 @@ + #define SS_GEN2_EOF_CFG 0x990 + #define SSG2EOF_OFFSET 0x3c + ++#define XHCI_MTK_LTSSM_TIMING_PARAMETER5 0x251c ++ + #define XSEOF_OFFSET_MASK GENMASK(11, 0) + + /* usb remote wakeup registers in syscon */ +@@ -191,6 +193,18 @@ static void xhci_mtk_rxfifo_depth_set(st + writel(value, hcd->regs + HSCH_CFG1); + } + ++/* EN7528: fix TD 6.5 compliance test failure */ ++static void xhci_mtk_ltssm_quirk(struct xhci_hcd_mtk *mtk) ++{ ++ struct device *dev = mtk->dev; ++ struct usb_hcd *hcd = mtk->hcd; ++ ++ if (!of_device_is_compatible(dev->of_node, "econet,en7528-xhci")) ++ return; ++ ++ writel(0x203e8, hcd->regs + XHCI_MTK_LTSSM_TIMING_PARAMETER5); ++} ++ + static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk) + { + /* workaround only for mt8195 */ +@@ -198,6 +212,9 @@ static void xhci_mtk_init_quirk(struct x + + /* workaround for SoCs using SSUSB about before IPM v1.6.0 */ + xhci_mtk_rxfifo_depth_set(mtk); ++ ++ /* EN7528 LTSSM timing fix */ ++ xhci_mtk_ltssm_quirk(mtk); + } + + static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) +@@ -846,6 +863,7 @@ static const struct dev_pm_ops xhci_mtk_ + static const struct of_device_id mtk_xhci_of_match[] = { + { .compatible = "mediatek,mt8173-xhci"}, + { .compatible = "mediatek,mt8195-xhci"}, ++ { .compatible = "econet,en7528-xhci"}, + { .compatible = "mediatek,mtk-xhci"}, + { }, + };