--- /dev/null
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2025.07
+PKG_HASH:=0f933f6c5a426895bf306e93e6ac53c60870e4b54cda56d95211bec99e63bec7
+PKG_BUILD_DEPENDS:=arm-trusted-firmware-tools/host
+
+UBOOT_USE_INTREE_DTC:=1
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define U-Boot/Default
+ BUILD_TARGET:=airoha
+ HIDDEN:=1
+ FIP_COMPRESS:=1
+endef
+
+define U-Boot/an7581_rfb
+ NAME:=AN7581 Reference Board
+ UBOOT_CONFIG:=an7581_evb
+ BUILD_DEVICES:=airoha_an7581-evb
+ BUILD_SUBTARGET:=an7581
+ UBOOT_IMAGE:=u-boot.fip
+ BL2_IMAGE:=an7581-bl2.bin
+ BL31_IMAGE:=an7581-bl31.bin
+endef
+
+define U-Boot/an7583_rfb
+ NAME:=AN7583 Reference Board
+ UBOOT_CONFIG:=an7583_evb
+ BUILD_DEVICES:=airoha_an7583-evb
+ BUILD_SUBTARGET:=an7583
+ UBOOT_IMAGE:=u-boot.fip
+ BL2_IMAGE:=an7583-bl2.bin
+ BL31_IMAGE:=an7583-bl31.bin
+endef
+
+UBOOT_TARGETS := \
+ an7581_rfb \
+ an7583_rfb
+
+UBOOT_CUSTOMIZE_CONFIG := \
+ --disable TOOLS_KWBIMAGE \
+ --disable TOOLS_LIBCRYPTO \
+ --disable TOOLS_MKEFICAPSULE \
+ --enable SERIAL_RX_BUFFER \
+ --set-val SERIAL_RX_BUFFER_SIZE 256
+
+define Build/fip-image-bl2
+ $(STAGING_DIR_HOST)/bin/fiptool create \
+ --tb-fw files/$(BL2_IMAGE) \
+ $(PKG_BUILD_DIR)/bl2.fip
+endef
+
+define Build/fip-image
+ $(if $(FIP_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
+ $(PKG_BUILD_DIR)/u-boot.bin \
+ $(PKG_BUILD_DIR)/u-boot.bin.lzma)
+ $(if $(FIP_COMPRESS), $(STAGING_DIR_HOST)/bin/lzma e \
+ files/$(BL31_IMAGE) \
+ $(PKG_BUILD_DIR)/bl31.bin.lzma)
+ $(STAGING_DIR_HOST)/bin/fiptool create \
+ --soc-fw $(PKG_BUILD_DIR)/bl31.bin$(if $(FIP_COMPRESS),.lzma) \
+ --nt-fw $(PKG_BUILD_DIR)/u-boot.bin$(if $(FIP_COMPRESS),.lzma) \
+ $(PKG_BUILD_DIR)/u-boot.fip
+endef
+
+define Build/Configure
+ $(call Build/Configure/U-Boot)
+ sed -i 's/CONFIG_TOOLS_LIBCRYPTO=y/# CONFIG_TOOLS_LIBCRYPTO is not set/' $(PKG_BUILD_DIR)/.config
+endef
+
+define Build/Compile
+ $(call Build/Compile/U-Boot)
+ifeq ($(UBOOT_IMAGE),u-boot.fip)
+ $(call Build/fip-image-bl2)
+ $(call Build/fip-image)
+endif
+endef
+
+# don't stage files to bindir, let target/linux/airoha/image/*.mk do that
+define Package/u-boot/install
+endef
+
+define Build/InstallDev
+ $(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+ifeq ($(UBOOT_IMAGE),u-boot.fip)
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/bl2.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl2.fip
+ $(INSTALL_DATA) $(PKG_BUILD_DIR)/u-boot.fip $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl31-u-boot.fip
+endif
+endef
+
+$(eval $(call BuildPackage/U-Boot))
--- /dev/null
+From 4f1fcf5281ee4e22b1e89a62bd0417878bcbeca5 Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Jun 2025 10:41:18 +0200
+Subject: [PATCH 1/2] linux/bitfield.h: import FIELD_PREP_CONST macro from
+ Linux Kernel
+
+Import FIELD_PREP_CONST macro from Linux Kernel to permit usage of
+FIELD_PREP with scenario where a constant value is needed.
+
+Refer to commit e2192de59e45 ("bitfield: add FIELD_PREP_CONST()") in
+Linux kernel for extensive explaination of why this is useful.
+
+This is also to better align with the Linux Kernel for easier porting of
+driver.
+
+---
+ include/linux/bitfield.h | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/include/linux/bitfield.h
++++ b/include/linux/bitfield.h
+@@ -90,6 +90,32 @@
+ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
+ })
+
++#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
++
++/**
++ * FIELD_PREP_CONST() - prepare a constant bitfield element
++ * @_mask: shifted mask defining the field's length and position
++ * @_val: value to put in the field
++ *
++ * FIELD_PREP_CONST() masks and shifts up the value. The result should
++ * be combined with other fields of the bitfield using logical OR.
++ *
++ * Unlike FIELD_PREP() this is a constant expression and can therefore
++ * be used in initializers. Error checking is less comfortable for this
++ * version, and non-constant masks cannot be used.
++ */
++#define FIELD_PREP_CONST(_mask, _val) \
++ ( \
++ /* mask must be non-zero */ \
++ BUILD_BUG_ON_ZERO((_mask) == 0) + \
++ /* check if value fits */ \
++ BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \
++ /* check if mask is contiguous */ \
++ __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \
++ /* and create the value */ \
++ (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \
++ )
++
+ /**
+ * FIELD_GET() - extract a bitfield element
+ * @_mask: shifted mask defining the field's length and position
--- /dev/null
+From 00e8038b8be74d599f7bc8078731cc2505832f57 Mon Sep 17 00:00:00 2001
+Date: Tue, 3 Jun 2025 10:47:15 +0200
+Subject: [PATCH 2/2] mtd: spinand: winbond: add Winbond W25N04KV flash support
+
+Add Winbond W25N04KV flash support that use a different value to detect
+ECC bitflip.
+
+---
+ drivers/mtd/nand/spi/winbond.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/mtd/nand/spi/winbond.c
++++ b/drivers/mtd/nand/spi/winbond.c
+@@ -11,6 +11,7 @@
+ #include <linux/device.h>
+ #include <linux/kernel.h>
+ #endif
++#include <linux/bitfield.h>
+ #include <linux/bug.h>
+ #include <linux/mtd/spinand.h>
+
+@@ -18,6 +19,8 @@
+
+ #define WINBOND_CFG_BUF_READ BIT(3)
+
++#define W25N04KV_STATUS_ECC_5_8_BITFLIPS FIELD_PREP_CONST(STATUS_ECC_MASK, 0x3)
++
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+@@ -121,6 +124,7 @@ static int w25n02kv_ecc_get_status(struc
+ return -EBADMSG;
+
+ case STATUS_ECC_HAS_BITFLIPS:
++ case W25N04KV_STATUS_ECC_5_8_BITFLIPS:
+ /*
+ * Let's try to retrieve the real maximum number of bitflips
+ * in order to avoid forcing the wear-leveling layer to move
+@@ -169,6 +173,15 @@ static const struct spinand_info winbond
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
++ &update_cache_variants),
++ 0,
++ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
++ SPINAND_INFO("W25N04KV",
++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
++ NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
++ NAND_ECCREQ(8, 512),
++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
--- /dev/null
+From 0ee8053a17e6f4d6dbde0828e775309cba38c171 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Apr 2025 13:06:59 +0200
+Subject: [PATCH 1/3] airoha: add support for Airoha AN7583 SoC
+
+Add support for Airoha AN7583 SoC. This adds the Kconfig and Makefile
+entry for the SoC, DTSI and initial config for it. Also add the code for
+CPU and RAM initialization. Everything is mostly based on AN7581 that
+share lots of common piece.
+
+---
+ arch/arm/dts/an7583-evb.dts | 67 +++++
+ arch/arm/dts/an7583.dtsi | 387 +++++++++++++++++++++++++++
+ arch/arm/mach-airoha/Kconfig | 14 +
+ arch/arm/mach-airoha/Makefile | 1 +
+ arch/arm/mach-airoha/an7583/Makefile | 3 +
+ arch/arm/mach-airoha/an7583/init.c | 47 ++++
+ board/airoha/an7583/MAINTAINERS | 5 +
+ board/airoha/an7583/Makefile | 3 +
+ board/airoha/an7583/an7583_rfb.c | 16 ++
+ configs/an7583_evb_defconfig | 83 ++++++
+ include/configs/an7583.h | 19 ++
+ 11 files changed, 645 insertions(+)
+ create mode 100644 arch/arm/dts/an7583-evb.dts
+ create mode 100644 arch/arm/dts/an7583.dtsi
+ create mode 100644 arch/arm/mach-airoha/an7583/Makefile
+ create mode 100644 arch/arm/mach-airoha/an7583/init.c
+ create mode 100644 board/airoha/an7583/MAINTAINERS
+ create mode 100644 board/airoha/an7583/Makefile
+ create mode 100644 board/airoha/an7583/an7583_rfb.c
+ create mode 100644 configs/an7583_evb_defconfig
+ create mode 100644 include/configs/an7583.h
+
+--- /dev/null
++++ b/arch/arm/dts/an7583-evb.dts
+@@ -0,0 +1,67 @@
++// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++/dts-v1/;
++
++/* Bootloader installs ATF here */
++/memreserve/ 0x80000000 0x200000;
++
++#include <dt-bindings/leds/common.h>
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/input/input.h>
++#include "an7583.dtsi"
++
++/ {
++ model = "Airoha AN7583 Evaluation Board";
++ compatible = "airoha,an7583-evb", "airoha,an7583", "airoha,en7583";
++
++ aliases {
++ serial0 = &uart1;
++ };
++
++ chosen {
++ bootargs = "console=ttyS0,115200 earlycon";
++ stdout-path = "serial0:115200n8";
++ linux,usable-memory-range = <0x0 0x80200000 0x0 0x1fe00000>;
++ };
++
++ /* When running as a first-stage bootloader this isn't filled in automatically */
++ memory@80000000 {
++ device_type = "memory";
++ reg = <0x0 0x80000000 0x0 0x20000000>;
++ };
++};
++
++&an7583_pinctrl {
++ pcie0_rst_pins: pcie0-rst-pins {
++ conf {
++ pins = "pcie_reset0";
++ drive-open-drain = <1>;
++ };
++ };
++
++ pcie1_rst_pins: pcie1-rst-pins {
++ conf {
++ pins = "pcie_reset1";
++ drive-open-drain = <1>;
++ };
++ };
++};
++
++&pcie0 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pcie0_rst_pins>;
++ status = "okay";
++};
++
++&pcie1 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pcie1_rst_pins>;
++ status = "okay";
++};
++
++&i2c0 {
++ status = "okay";
++};
++
++&snfi {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/dts/an7583.dtsi
+@@ -0,0 +1,387 @@
++// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
++
++#include <dt-bindings/interrupt-controller/irq.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
++#include <dt-bindings/clock/en7523-clk.h>
++#include <dt-bindings/reset/airoha,an7583-reset.h>
++#include <dt-bindings/leds/common.h>
++#include <dt-bindings/thermal/thermal.h>
++
++/ {
++ interrupt-parent = <&gic>;
++ #address-cells = <2>;
++ #size-cells = <2>;
++
++ reserved-memory {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++
++ atf-reserved-memory@80000000 {
++ no-map;
++ reg = <0x0 0x80000000 0x0 0x40000>;
++ };
++
++ npu-binary@84000000 {
++ no-map;
++ reg = <0x0 0x84000000 0x0 0xa00000>;
++ };
++
++ npu-flag@84b0000 {
++ no-map;
++ reg = <0x0 0x84b00000 0x0 0x100000>;
++ };
++
++ npu-pkt@85000000 {
++ no-map;
++ reg = <0x0 0x85000000 0x0 0x1a00000>;
++ };
++
++ npu-phyaddr@86b00000 {
++ no-map;
++ reg = <0x0 0x86b00000 0x0 0x100000>;
++ };
++
++ npu-rxdesc@86d00000 {
++ no-map;
++ reg = <0x0 0x86d00000 0x0 0x100000>;
++ };
++ };
++
++ psci {
++ compatible = "arm,psci-1.0";
++ method = "smc";
++ };
++
++ cpus {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ cpu-map {
++ cluster0 {
++ core0 {
++ cpu = <&cpu0>;
++ };
++
++ core1 {
++ cpu = <&cpu1>;
++ };
++ };
++ };
++
++ cpu0: cpu@0 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <0x0>;
++ enable-method = "psci";
++ next-level-cache = <&l2>;
++ #cooling-cells = <2>;
++ };
++
++ cpu1: cpu@1 {
++ device_type = "cpu";
++ compatible = "arm,cortex-a53";
++ reg = <0x1>;
++ enable-method = "psci";
++ next-level-cache = <&l2>;
++ #cooling-cells = <2>;
++ };
++
++ l2: l2-cache {
++ compatible = "cache";
++ cache-size = <0x80000>;
++ cache-line-size = <64>;
++ cache-level = <2>;
++ cache-unified;
++ };
++ };
++
++ timer {
++ compatible = "arm,armv8-timer";
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
++ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
++ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
++ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
++ };
++
++ soc {
++ compatible = "simple-bus";
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++
++ gic: interrupt-controller@9000000 {
++ compatible = "arm,gic-v3";
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = <0x0 0x09000000 0x0 0x20000>,
++ <0x0 0x09080000 0x0 0x80000>,
++ <0x0 0x09400000 0x0 0x2000>,
++ <0x0 0x09500000 0x0 0x2000>,
++ <0x0 0x09600000 0x0 0x20000>;
++ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_LOW>;
++ };
++
++ chip_scu: syscon@1fa20000 {
++ compatible = "airoha,en7581-chip-scu", "syscon";
++ reg = <0x0 0x1fa20000 0x0 0x388>;
++ };
++
++ syscon@1fbe3400 {
++ compatible = "airoha,en7581-pbus-csr", "syscon";
++ reg = <0x0 0x1fbe3400 0x0 0xff>;
++ };
++
++ system-controller@1fa20000 {
++ compatible = "syscon", "simple-mfd";
++ reg = <0x0 0x1fb00000 0x0 0x970>;
++
++ scuclk: scuclk {
++ compatible = "airoha,an7583-scu";
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ };
++
++ mdio_0: mdio-0 {
++ compatible = "airoha,an7583-mdio";
++ resets = <&scuclk AN7583_MDIO0>;
++
++ airoha,bus-id = <0>;
++ };
++
++ mdio_1: mdio-1 {
++ compatible = "airoha,an7583-mdio";
++ resets = <&scuclk AN7583_MDIO1>;
++
++ airoha,bus-id = <1>;
++ };
++ };
++
++ system-controller@1fbf0200 {
++ compatible = "syscon", "simple-mfd";
++ reg = <0x0 0x1fbf0200 0x0 0xc0>;
++
++ an7583_pinctrl: pinctrl {
++ compatible = "airoha,en7583-pinctrl";
++
++ interrupt-parent = <&gic>;
++ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
++
++ gpio-controller;
++ #gpio-cells = <2>;
++
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++ };
++
++ i2cclock: i2cclock@0 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++
++ /* 20 MHz */
++ clock-frequency = <20000000>;
++ };
++
++ i2c0: i2c0@1fbf8000 {
++ compatible = "mediatek,mt7621-i2c";
++ reg = <0x0 0x1fbf8000 0x0 0x100>;
++
++ clocks = <&i2cclock>;
++
++ /* 100 kHz */
++ clock-frequency = <100000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "disable";
++ };
++
++ i2c1: i2c1@1fbf8100 {
++ compatible = "mediatek,mt7621-i2c";
++ reg = <0x0 0x1fbf8100 0x0 0x100>;
++
++ clocks = <&i2cclock>;
++
++ /* 100 kHz */
++ clock-frequency = <100000>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "disable";
++ };
++
++ snfi: spi@1fa10000 {
++ compatible = "airoha,en7581-snand";
++ reg = <0x0 0x1fa10000 0x0 0x140>,
++ <0x0 0x1fa11000 0x0 0x600>;
++
++ clocks = <&scuclk EN7523_CLK_SPI>;
++ clock-names = "spi";
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ status = "disabled";
++
++ spi_nand: nand@0 {
++ compatible = "spi-nand";
++ reg = <0>;
++ spi-max-frequency = <50000000>;
++ spi-tx-bus-width = <1>;
++ spi-rx-bus-width = <2>;
++ };
++ };
++
++ uart1: serial@1fbf0000 {
++ compatible = "ns16550";
++ reg = <0x0 0x1fbf0000 0x0 0x30>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <1843200>;
++ bootph-all;
++ };
++
++ uart2: serial@1fbf0300 {
++ compatible = "airoha,en7523-uart";
++ reg = <0x0 0x1fbf0300 0x0 0x30>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <7372800>;
++
++ status = "disabled";
++ };
++
++ hsuart3: serial@1fbe1000 {
++ compatible = "airoha,en7523-uart";
++ reg = <0x0 0x1fbe1000 0x0 0x40>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <7372800>;
++
++ status = "disabled";
++ };
++
++ uart4: serial@1fbf0600 {
++ compatible = "airoha,en7523-uart";
++ reg = <0x0 0x1fbf0600 0x0 0x30>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <7372800>;
++
++ status = "disabled";
++ };
++
++ uart5: serial@1fbf0700 {
++ compatible = "airoha,en7523-uart";
++ reg = <0x0 0x1fbf0700 0x0 0x30>;
++ reg-io-width = <4>;
++ reg-shift = <2>;
++ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
++ clock-frequency = <7372800>;
++
++ status = "disabled";
++ };
++
++ pciephy: phy@1fa5a000 {
++ compatible = "airoha,en7581-pcie-phy";
++ reg = <0x0 0x1fa5a000 0x0 0xfff>,
++ <0x0 0x1fa5b000 0x0 0xfff>,
++ <0x0 0x1fa5c000 0x0 0xfff>,
++ <0x0 0x1fc10044 0x0 0x4>,
++ <0x0 0x1fc30044 0x0 0x4>,
++ <0x0 0x1fc15030 0x0 0x104>;
++ reg-names = "csr-2l", "pma0", "pma1",
++ "p0-xr-dtime", "p1-xr-dtime",
++ "rx-aeq";
++ #phy-cells = <0>;
++ };
++
++ pcie0: pcie@1fc00000 {
++ compatible = "airoha,an7583-pcie";
++ device_type = "pci";
++ linux,pci-domain = <0>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++
++ reg = <0x0 0x1fc20000 0x0 0x1670>;
++ reg-names = "pcie-mac";
++
++ clocks = <&scuclk EN7523_CLK_PCIE>;
++ clock-names = "sys-ck";
++
++ phys = <&pciephy>;
++ phy-names = "pcie-phy";
++
++ ranges = <0x02000000 0 0x20000000 0x0 0x20000000 0 0x4000000>;
++
++ resets = <&scuclk AN7583_PCIE0_RST>,
++ <&scuclk AN7583_PCIE1_RST>;
++ reset-names = "phy-lane0", "phy-lane1";
++
++ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
++ bus-range = <0x00 0xff>;
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 7>;
++ interrupt-map = <0 0 0 1 &pcie_intc0 0>,
++ <0 0 0 2 &pcie_intc0 1>,
++ <0 0 0 3 &pcie_intc0 2>,
++ <0 0 0 4 &pcie_intc0 3>;
++
++ status = "disabled";
++
++ pcie_intc0: interrupt-controller {
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ };
++ };
++
++ pcie1: pcie@1fc20000 {
++ compatible = "airoha,an7583-pcie";
++ device_type = "pci";
++ linux,pci-domain = <1>;
++ #address-cells = <3>;
++ #size-cells = <2>;
++
++ reg = <0x0 0x1fa92000 0x0 0x1670>;
++ reg-names = "pcie-mac";
++
++ clocks = <&scuclk EN7523_CLK_PCIE>;
++ clock-names = "sys-ck";
++
++ phys = <&pciephy>;
++ phy-names = "pcie-phy";
++
++ ranges = <0x02000000 0 0x24000000 0x0 0x24000000 0 0x4000000>;
++
++ resets = <&scuclk AN7583_PCIE0_RST>,
++ <&scuclk AN7583_PCIE1_RST>;
++ reset-names = "phy-lane0", "phy-lane1";
++
++ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
++ bus-range = <0x00 0xff>;
++ #interrupt-cells = <1>;
++ interrupt-map-mask = <0 0 0 7>;
++ interrupt-map = <0 0 0 1 &pcie_intc1 0>,
++ <0 0 0 2 &pcie_intc1 1>,
++ <0 0 0 3 &pcie_intc1 2>,
++ <0 0 0 4 &pcie_intc1 3>;
++
++ status = "disabled";
++
++ pcie_intc1: interrupt-controller {
++ interrupt-controller;
++ #address-cells = <0>;
++ #interrupt-cells = <1>;
++ };
++ };
++ };
++};
+--- a/arch/arm/mach-airoha/Kconfig
++++ b/arch/arm/mach-airoha/Kconfig
+@@ -17,16 +17,30 @@ config TARGET_AN7581
+ Peripherals include Gigabit Ethernet, switch, USB3.0 and OTG, PCIe,
+ I2S, PCM, S/PDIF, UART, SPI, I2C, IR TX/RX, and PWM.
+
++config TARGET_AN7583
++ bool "Airoha AN7583 SoC"
++ select ARM64
++ help
++ The Airoha AN7583 is a ARM-based SoC with a quad-core Cortex-A7
++ including NEON and GPU, Mali-450 graphics, several DDR3 options,
++ crypto engine, built-in Wi-Fi / Bluetooth combo chip, JPEG decoder,
++ video interfaces supporting HDMI and MIPI, and video codec support.
++ Peripherals include Gigabit Ethernet, switch, USB3.0 and OTG, PCIe,
++ I2S, PCM, S/PDIF, UART, SPI, I2C, IR TX/RX, and PWM.
++
+ endchoice
+
+ config SYS_SOC
+ default "an7581" if TARGET_AN7581
++ default "an7583" if TARGET_AN7583
+
+ config SYS_BOARD
+ default "an7581" if TARGET_AN7581
++ default "an7583" if TARGET_AN7583
+
+ config SYS_CONFIG_NAME
+ default "an7581" if TARGET_AN7581
++ default "an7583" if TARGET_AN7583
+
+ endif
+
+--- a/arch/arm/mach-airoha/Makefile
++++ b/arch/arm/mach-airoha/Makefile
+@@ -3,3 +3,4 @@
+ obj-y += cpu.o
+
+ obj-$(CONFIG_TARGET_AN7581) += an7581/
++obj-$(CONFIG_TARGET_AN7583) += an7583/
+--- /dev/null
++++ b/arch/arm/mach-airoha/an7583/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++
++obj-y += init.o
+--- /dev/null
++++ b/arch/arm/mach-airoha/an7583/init.c
+@@ -0,0 +1,47 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <fdtdec.h>
++#include <init.h>
++#include <asm/armv8/mmu.h>
++#include <asm/system.h>
++
++int print_cpuinfo(void)
++{
++ printf("CPU: Airoha AN7583\n");
++ return 0;
++}
++
++int dram_init(void)
++{
++ return fdtdec_setup_mem_size_base();
++}
++
++int dram_init_banksize(void)
++{
++ return fdtdec_setup_memory_banksize();
++}
++
++void reset_cpu(ulong addr)
++{
++ psci_system_reset();
++}
++
++static struct mm_region an7583_mem_map[] = {
++ {
++ /* DDR */
++ .virt = 0x80000000UL,
++ .phys = 0x80000000UL,
++ .size = 0x80000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_OUTER_SHARE,
++ }, {
++ .virt = 0x00000000UL,
++ .phys = 0x00000000UL,
++ .size = 0x20000000UL,
++ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
++ PTE_BLOCK_NON_SHARE |
++ PTE_BLOCK_PXN | PTE_BLOCK_UXN
++ }, {
++ 0,
++ }
++};
++struct mm_region *mem_map = an7583_mem_map;
+--- /dev/null
++++ b/board/airoha/an7583/MAINTAINERS
+@@ -0,0 +1,5 @@
++AN7581
++S: Maintained
++N: airoha
++N: an7583
+--- /dev/null
++++ b/board/airoha/an7583/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0
++
++obj-y += an7583_rfb.o
+--- /dev/null
++++ b/board/airoha/an7583/an7583_rfb.c
+@@ -0,0 +1,16 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ */
++
++#include <asm/global_data.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++int board_init(void)
++{
++ /* address of boot parameters */
++ gd->bd->bi_boot_params = CFG_SYS_SDRAM_BASE + 0x100;
++
++ return 0;
++}
+--- /dev/null
++++ b/configs/an7583_evb_defconfig
+@@ -0,0 +1,81 @@
++CONFIG_ARM=y
++CONFIG_ARCH_AIROHA=y
++CONFIG_TARGET_AN7583=y
++CONFIG_TEXT_BASE=0x81E00000
++CONFIG_SYS_MALLOC_F_LEN=0x4000
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_ENV_SIZE=0x4000
++CONFIG_ENV_OFFSET=0x7c000
++CONFIG_DM_GPIO=y
++CONFIG_DEFAULT_DEVICE_TREE="an7583-evb"
++CONFIG_DM_RESET=y
++CONFIG_SYS_LOAD_ADDR=0x81800000
++CONFIG_BUILD_TARGET="u-boot.bin"
++# CONFIG_EFI_LOADER is not set
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_BOOTDELAY=3
++CONFIG_DEFAULT_FDT_FILE="an7583-evb"
++CONFIG_SYS_PBSIZE=1049
++CONFIG_SYS_CONSOLE_IS_IN_ENV=y
++# CONFIG_DISPLAY_BOARDINFO is not set
++CONFIG_HUSH_PARSER=y
++CONFIG_SYS_PROMPT="U-Boot> "
++CONFIG_SYS_MAXARGS=8
++CONFIG_CMD_BOOTZ=y
++CONFIG_CMD_BOOTMENU=y
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_XIMG is not set
++CONFIG_CMD_BIND=y
++CONFIG_CMD_GPIO=y
++CONFIG_CMD_MMC=y
++CONFIG_CMD_MTD=y
++CONFIG_CMD_SF_TEST=y
++CONFIG_CMD_SPI=y
++# CONFIG_CMD_SETEXPR is not set
++CONFIG_CMD_PING=y
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_FS_GENERIC=y
++CONFIG_CMD_MTDPARTS=y
++CONFIG_CMD_LOG=y
++CONFIG_ENV_OVERWRITE=y
++CONFIG_ENV_IS_IN_MMC=y
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
++CONFIG_NET_RANDOM_ETHADDR=y
++CONFIG_REGMAP=y
++CONFIG_SYSCON=y
++CONFIG_CLK=y
++CONFIG_DMA=y
++CONFIG_LED=y
++CONFIG_LED_GPIO=y
++CONFIG_MMC_HS200_SUPPORT=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_MTD_SPI_NAND=y
++CONFIG_DM_SPI_FLASH=y
++CONFIG_SPI_FLASH_EON=y
++CONFIG_SPI_FLASH_GIGADEVICE=y
++CONFIG_SPI_FLASH_ISSI=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_SPANSION=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_SPI_FLASH_WINBOND=y
++CONFIG_SPI_FLASH_MTD=y
++CONFIG_PHYLIB=y
++CONFIG_PHY=y
++CONFIG_PINCTRL=y
++CONFIG_PINCONF=y
++CONFIG_POWER_DOMAIN=y
++CONFIG_DM_REGULATOR=y
++CONFIG_DM_REGULATOR_FIXED=y
++CONFIG_RAM=y
++CONFIG_DM_SERIAL=y
++CONFIG_SYS_NS16550=y
++CONFIG_SPI=y
++CONFIG_DM_SPI=y
++CONFIG_SHA512=y
++CONFIG_AIROHA_ETH=y
++CONFIG_MMC_MTK=y
++CONFIG_AIROHA_SNFI_SPI=y
+--- /dev/null
++++ b/include/configs/an7583.h
+@@ -0,0 +1,19 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Configuration for Airoha AN7583
++ */
++
++#ifndef __AN7583_H
++#define __AN7583_H
++
++#include <linux/sizes.h>
++
++#define CFG_SYS_UBOOT_BASE CONFIG_TEXT_BASE
++
++#define CFG_SYS_INIT_RAM_ADDR CONFIG_TEXT_BASE
++#define CFG_SYS_INIT_RAM_SIZE SZ_2M
++
++/* DRAM */
++#define CFG_SYS_SDRAM_BASE 0x80000000
++
++#endif
--- /dev/null
+From 62ab067847b30d73d4f661bdc99e9f32ff03f338 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Apr 2025 13:19:11 +0200
+Subject: [PATCH] clk: airoha: add support for Airoha AN7583 SoC clock
+
+Add support for Airoha AN7583 SoC clock that implement more base values
+for clocks compared to AN7581.
+
+---
+ drivers/clk/airoha/clk-airoha.c | 131 ++++++++++++++++++++++++++++++++
+ 1 file changed, 131 insertions(+)
+
+--- a/drivers/clk/airoha/clk-airoha.c
++++ b/drivers/clk/airoha/clk-airoha.c
+@@ -73,6 +73,14 @@ 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 };
++/* AN7583 */
++static const u32 gsw7583_base[] = { 540672000, 270336000, 400000000, 200000000 };
++static const u32 emi7583_base[] = { 540672000, 480000000, 400000000, 300000000 };
++static const u32 bus7583_base[] = { 600000000, 540672000, 480000000, 400000000 };
++static const u32 spi7583_base[] = { 100000000, 12500000 };
++static const u32 npu7583_base[] = { 666000000, 800000000, 720000000, 600000000 };
++static const u32 crypto7583_base[] = { 540672000, 400000000 };
++static const u32 emmc7583_base[] = { 150000000, 200000000 };
+
+ static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = {
+ [EN7523_CLK_GSW] = {
+@@ -186,6 +194,121 @@ static const struct airoha_clk_desc en75
+ }
+ };
+
++static const struct airoha_clk_desc an7583_base_clks[EN7581_MAX_CLKS] = {
++ [EN7523_CLK_GSW] = {
++ .id = EN7523_CLK_GSW,
++ .name = "gsw",
++
++ .base_reg = REG_GSW_CLK_DIV_SEL,
++ .base_bits = 2,
++ .base_shift = 8,
++ .base_values = gsw7583_base,
++ .n_base_values = ARRAY_SIZE(gsw7583_base),
++
++ .div_bits = 3,
++ .div_shift = 0,
++ .div_step = 1,
++ .div_offset = 1,
++ },
++ [EN7523_CLK_EMI] = {
++ .id = EN7523_CLK_EMI,
++ .name = "emi",
++
++ .base_reg = REG_EMI_CLK_DIV_SEL,
++ .base_bits = 2,
++ .base_shift = 8,
++ .base_values = emi7583_base,
++ .n_base_values = ARRAY_SIZE(emi7583_base),
++
++ .div_bits = 3,
++ .div_shift = 0,
++ .div_step = 1,
++ .div_offset = 1,
++ },
++ [EN7523_CLK_BUS] = {
++ .id = EN7523_CLK_BUS,
++ .name = "bus",
++
++ .base_reg = REG_BUS_CLK_DIV_SEL,
++ .base_bits = 2,
++ .base_shift = 8,
++ .base_values = bus7583_base,
++ .n_base_values = ARRAY_SIZE(bus7583_base),
++
++ .div_bits = 3,
++ .div_shift = 0,
++ .div_step = 1,
++ .div_offset = 1,
++ },
++ [EN7523_CLK_SLIC] = {
++ .id = EN7523_CLK_SLIC,
++ .name = "slic",
++
++ .base_reg = REG_SPI_CLK_FREQ_SEL,
++ .base_bits = 1,
++ .base_shift = 0,
++ .base_values = slic_base,
++ .n_base_values = ARRAY_SIZE(slic_base),
++
++ .div_reg = REG_SPI_CLK_DIV_SEL,
++ .div_bits = 5,
++ .div_shift = 24,
++ .div_val0 = 20,
++ .div_step = 2,
++ },
++ [EN7523_CLK_SPI] = {
++ .id = EN7523_CLK_SPI,
++ .name = "spi",
++
++ .base_reg = REG_SPI_CLK_FREQ_SEL,
++ .base_bits = 1,
++ .base_shift = 1,
++ .base_values = spi7583_base,
++ .n_base_values = ARRAY_SIZE(spi7583_base),
++
++ .div_reg = REG_SPI_CLK_DIV_SEL,
++ .div_bits = 5,
++ .div_shift = 8,
++ .div_val0 = 40,
++ .div_step = 2,
++ },
++ [EN7523_CLK_NPU] = {
++ .id = EN7523_CLK_NPU,
++ .name = "npu",
++
++ .base_reg = REG_NPU_CLK_DIV_SEL,
++ .base_bits = 2,
++ .base_shift = 9,
++ .base_values = npu7583_base,
++ .n_base_values = ARRAY_SIZE(npu7583_base),
++
++ .div_bits = 3,
++ .div_shift = 0,
++ .div_step = 1,
++ .div_offset = 1,
++ },
++ [EN7523_CLK_CRYPTO] = {
++ .id = EN7523_CLK_CRYPTO,
++ .name = "crypto",
++
++ .base_reg = REG_CRYPTO_CLKSRC2,
++ .base_bits = 1,
++ .base_shift = 0,
++ .base_values = crypto7583_base,
++ .n_base_values = ARRAY_SIZE(crypto7583_base),
++ },
++ [EN7581_CLK_EMMC] = {
++ .id = EN7581_CLK_EMMC,
++ .name = "emmc",
++
++ .base_reg = REG_CRYPTO_CLKSRC2,
++ .base_bits = 1,
++ .base_shift = 13,
++ .base_values = emmc7583_base,
++ .n_base_values = ARRAY_SIZE(emmc7583_base),
++ }
++};
++
+ static u32 airoha_clk_get_base_rate(const struct airoha_clk_desc *desc, u32 val)
+ {
+ if (!desc->base_bits)
+@@ -436,10 +559,18 @@ static const struct airoha_clk_soc_data
+ .descs = en7581_base_clks,
+ };
+
++static const struct airoha_clk_soc_data an7583_data = {
++ .num_clocks = ARRAY_SIZE(an7583_base_clks),
++ .descs = an7583_base_clks,
++};
++
+ static const struct udevice_id airoha_clk_ids[] = {
+ { .compatible = "airoha,en7581-scu",
+ .data = (ulong)&en7581_data,
+ },
++ { .compatible = "airoha,an7583-scu",
++ .data = (ulong)&an7583_data,
++ },
+ { }
+ };
+
--- /dev/null
+From 7daf0565460e548eb766a0bcc171c34e02dd6eba Mon Sep 17 00:00:00 2001
+Date: Mon, 19 May 2025 14:22:55 +0200
+Subject: [PATCH 3/6] reset: airoha: convert to regmap API
+
+In preparation for support for Airoha AN7583, convert the driver to
+regmap API. This is needed as Airoha AN7583 will use syscon to access
+reset registers.
+
+---
+ drivers/reset/reset-airoha.c | 35 ++++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 17 deletions(-)
+
+--- a/drivers/reset/reset-airoha.c
++++ b/drivers/reset/reset-airoha.c
+@@ -10,6 +10,7 @@
+ #include <dm.h>
+ #include <linux/io.h>
+ #include <reset-uclass.h>
++#include <regmap.h>
+
+ #include <dt-bindings/reset/airoha,en7581-reset.h>
+
+@@ -21,7 +22,7 @@
+ struct airoha_reset_priv {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
+- void __iomem *base;
++ struct regmap *map;
+ };
+
+ static const u16 en7581_rst_ofs[] = {
+@@ -90,17 +91,11 @@ static const u16 en7581_rst_map[] = {
+ static int airoha_reset_update(struct airoha_reset_priv *priv,
+ unsigned long id, bool assert)
+ {
+- void __iomem *addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
+- u32 val;
+-
+- val = readl(addr);
+- if (assert)
+- val |= BIT(id % RST_NR_PER_BANK);
+- else
+- val &= ~BIT(id % RST_NR_PER_BANK);
+- writel(val, addr);
++ u16 offset = priv->bank_ofs[id / RST_NR_PER_BANK];
+
+- return 0;
++ return regmap_update_bits(priv->map, offset,
++ BIT(id % RST_NR_PER_BANK),
++ assert ? BIT(id % RST_NR_PER_BANK) : 0);
+ }
+
+ static int airoha_reset_assert(struct reset_ctl *reset_ctl)
+@@ -123,11 +118,16 @@ static int airoha_reset_status(struct re
+ {
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+ int id = reset_ctl->id;
+- void __iomem *addr;
++ u16 offset;
++ u32 val;
++ int ret;
+
+- addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK];
++ offset = priv->bank_ofs[id / RST_NR_PER_BANK];
++ ret = regmap_read(priv->map, offset, &val);
++ if (ret)
++ return ret;
+
+- return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
++ return !!(val & BIT(id % RST_NR_PER_BANK));
+ }
+
+ static int airoha_reset_xlate(struct reset_ctl *reset_ctl,
+@@ -153,10 +153,11 @@ static struct reset_ops airoha_reset_ops
+ static int airoha_reset_probe(struct udevice *dev)
+ {
+ struct airoha_reset_priv *priv = dev_get_priv(dev);
++ int ret;
+
+- priv->base = dev_remap_addr(dev);
+- if (!priv->base)
+- return -ENOMEM;
++ ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
++ if (ret)
++ return ret;
+
+ priv->bank_ofs = en7581_rst_ofs;
+ priv->idx_map = en7581_rst_map;
--- /dev/null
+From 23031ad51d55361be507b83307f55995e0204188 Mon Sep 17 00:00:00 2001
+Date: Tue, 29 Apr 2025 13:33:35 +0200
+Subject: [PATCH 4/6] reset: airoha: Add support for Airoha AN7583 reset
+
+Adapt the Airoha reset driver to support Airoha AN7583 node structure.
+In AN7583 the register is exposed by the parent syscon hence a different
+logic needs to be applied. Also the reset line differ from AN7581 hence
+a dedicated table is needed.
+
+---
+ drivers/reset/reset-airoha.c | 94 ++++++++++++++++++-
+ .../dt-bindings/reset/airoha,an7583-reset.h | 61 ++++++++++++
+ 2 files changed, 153 insertions(+), 2 deletions(-)
+ create mode 100644 include/dt-bindings/reset/airoha,an7583-reset.h
+
+--- a/drivers/reset/reset-airoha.c
++++ b/drivers/reset/reset-airoha.c
+@@ -11,8 +11,10 @@
+ #include <linux/io.h>
+ #include <reset-uclass.h>
+ #include <regmap.h>
++#include <syscon.h>
+
+ #include <dt-bindings/reset/airoha,en7581-reset.h>
++#include <dt-bindings/reset/airoha,an7583-reset.h>
+
+ #define RST_NR_PER_BANK 32
+
+@@ -22,6 +24,7 @@
+ struct airoha_reset_priv {
+ const u16 *bank_ofs;
+ const u16 *idx_map;
++ int num_rsts;
+ struct regmap *map;
+ };
+
+@@ -88,6 +91,59 @@ static const u16 en7581_rst_map[] = {
+ [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
+ };
+
++static const u16 an7583_rst_map[] = {
++ /* RST_CTRL2 */
++ [AN7583_XPON_PHY_RST] = 0,
++ [AN7583_GPON_OLT_RST] = 1,
++ [AN7583_CPU_TIMER2_RST] = 2,
++ [AN7583_HSUART_RST] = 3,
++ [AN7583_UART4_RST] = 4,
++ [AN7583_UART5_RST] = 5,
++ [AN7583_I2C2_RST] = 6,
++ [AN7583_XSI_MAC_RST] = 7,
++ [AN7583_XSI_PHY_RST] = 8,
++ [AN7583_NPU_RST] = 9,
++ [AN7583_TRNG_MSTART_RST] = 12,
++ [AN7583_DUAL_HSI0_RST] = 13,
++ [AN7583_DUAL_HSI1_RST] = 14,
++ [AN7583_DUAL_HSI0_MAC_RST] = 16,
++ [AN7583_DUAL_HSI1_MAC_RST] = 17,
++ [AN7583_WDMA_RST] = 19,
++ [AN7583_WOE0_RST] = 20,
++ [AN7583_HSDMA_RST] = 22,
++ [AN7583_TDMA_RST] = 24,
++ [AN7583_EMMC_RST] = 25,
++ [AN7583_SOE_RST] = 26,
++ [AN7583_XFP_MAC_RST] = 28,
++ [AN7583_MDIO0] = 30,
++ [AN7583_MDIO1] = 31,
++ /* RST_CTRL1 */
++ [AN7583_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0,
++ [AN7583_FE_PDMA_RST] = RST_NR_PER_BANK + 1,
++ [AN7583_FE_QDMA_RST] = RST_NR_PER_BANK + 2,
++ [AN7583_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4,
++ [AN7583_CRYPTO_RST] = RST_NR_PER_BANK + 6,
++ [AN7583_TIMER_RST] = RST_NR_PER_BANK + 8,
++ [AN7583_PCM1_RST] = RST_NR_PER_BANK + 11,
++ [AN7583_UART_RST] = RST_NR_PER_BANK + 12,
++ [AN7583_GPIO_RST] = RST_NR_PER_BANK + 13,
++ [AN7583_GDMA_RST] = RST_NR_PER_BANK + 14,
++ [AN7583_I2C_MASTER_RST] = RST_NR_PER_BANK + 16,
++ [AN7583_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17,
++ [AN7583_SFC_RST] = RST_NR_PER_BANK + 18,
++ [AN7583_UART2_RST] = RST_NR_PER_BANK + 19,
++ [AN7583_GDMP_RST] = RST_NR_PER_BANK + 20,
++ [AN7583_FE_RST] = RST_NR_PER_BANK + 21,
++ [AN7583_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22,
++ [AN7583_GSW_RST] = RST_NR_PER_BANK + 23,
++ [AN7583_SFC2_PCM_RST] = RST_NR_PER_BANK + 25,
++ [AN7583_PCIE0_RST] = RST_NR_PER_BANK + 26,
++ [AN7583_PCIE1_RST] = RST_NR_PER_BANK + 27,
++ [AN7583_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
++ [AN7583_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
++ [AN7583_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
++};
++
+ static int airoha_reset_update(struct airoha_reset_priv *priv,
+ unsigned long id, bool assert)
+ {
+@@ -135,7 +191,7 @@ static int airoha_reset_xlate(struct res
+ {
+ struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+
+- if (args->args[0] >= ARRAY_SIZE(en7581_rst_map))
++ if (args->args[0] >= priv->num_rsts)
+ return -EINVAL;
+
+ reset_ctl->id = priv->idx_map[args->args[0]];
+@@ -150,7 +206,7 @@ static struct reset_ops airoha_reset_ops
+ .rst_status = airoha_reset_status,
+ };
+
+-static int airoha_reset_probe(struct udevice *dev)
++static int an7581_reset_probe(struct udevice *dev)
+ {
+ struct airoha_reset_priv *priv = dev_get_priv(dev);
+ int ret;
+@@ -161,10 +217,44 @@ static int airoha_reset_probe(struct ude
+
+ priv->bank_ofs = en7581_rst_ofs;
+ priv->idx_map = en7581_rst_map;
++ priv->num_rsts = ARRAY_SIZE(en7581_rst_map);
+
+ return 0;
+ }
+
++static int an7583_reset_probe(struct udevice *dev)
++{
++ struct airoha_reset_priv *priv = dev_get_priv(dev);
++ ofnode pnode, scu_node = dev_ofnode(dev);
++
++ pnode = ofnode_get_parent(scu_node);
++ if (!ofnode_valid(pnode))
++ return -EINVAL;
++
++ priv->map = syscon_node_to_regmap(pnode);
++ if (IS_ERR(priv->map))
++ return PTR_ERR(priv->map);
++
++ priv->bank_ofs = en7581_rst_ofs;
++ priv->idx_map = an7583_rst_map;
++ priv->num_rsts = ARRAY_SIZE(an7583_rst_map);
++
++ return 0;
++}
++
++static int airoha_reset_probe(struct udevice *dev)
++{
++ if (ofnode_device_is_compatible(dev_ofnode(dev),
++ "airoha,en7581-scu"))
++ return an7581_reset_probe(dev);
++
++ if (ofnode_device_is_compatible(dev_ofnode(dev),
++ "airoha,an7583-scu"))
++ return an7583_reset_probe(dev);
++
++ return -ENODEV;
++}
++
+ U_BOOT_DRIVER(airoha_reset) = {
+ .name = "airoha-reset",
+ .id = UCLASS_RESET,
+--- /dev/null
++++ b/include/dt-bindings/reset/airoha,an7583-reset.h
+@@ -0,0 +1,61 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2024 AIROHA Inc
++ */
++
++#ifndef __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_
++#define __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_
++
++/* RST_CTRL2 */
++#define AN7583_XPON_PHY_RST 0
++#define AN7583_GPON_OLT_RST 1
++#define AN7583_CPU_TIMER2_RST 2
++#define AN7583_HSUART_RST 3
++#define AN7583_UART4_RST 4
++#define AN7583_UART5_RST 5
++#define AN7583_I2C2_RST 6
++#define AN7583_XSI_MAC_RST 7
++#define AN7583_XSI_PHY_RST 8
++#define AN7583_NPU_RST 9
++#define AN7583_TRNG_MSTART_RST 10
++#define AN7583_DUAL_HSI0_RST 11
++#define AN7583_DUAL_HSI1_RST 12
++#define AN7583_DUAL_HSI0_MAC_RST 13
++#define AN7583_DUAL_HSI1_MAC_RST 14
++#define AN7583_WDMA_RST 15
++#define AN7583_WOE0_RST 16
++#define AN7583_HSDMA_RST 17
++#define AN7583_TDMA_RST 18
++#define AN7583_EMMC_RST 19
++#define AN7583_SOE_RST 20
++#define AN7583_XFP_MAC_RST 21
++#define AN7583_MDIO0 22
++#define AN7583_MDIO1 23
++/* RST_CTRL1 */
++#define AN7583_PCM1_ZSI_ISI_RST 24
++#define AN7583_FE_PDMA_RST 25
++#define AN7583_FE_QDMA_RST 26
++#define AN7583_PCM_SPIWP_RST 27
++#define AN7583_CRYPTO_RST 28
++#define AN7583_TIMER_RST 29
++#define AN7583_PCM1_RST 30
++#define AN7583_UART_RST 31
++#define AN7583_GPIO_RST 32
++#define AN7583_GDMA_RST 33
++#define AN7583_I2C_MASTER_RST 34
++#define AN7583_PCM2_ZSI_ISI_RST 35
++#define AN7583_SFC_RST 36
++#define AN7583_UART2_RST 37
++#define AN7583_GDMP_RST 38
++#define AN7583_FE_RST 39
++#define AN7583_USB_HOST_P0_RST 40
++#define AN7583_GSW_RST 41
++#define AN7583_SFC2_PCM_RST 42
++#define AN7583_PCIE0_RST 43
++#define AN7583_PCIE1_RST 44
++#define AN7583_CPU_TIMER_RST 45
++#define AN7583_PCIE_HB_RST 46
++#define AN7583_XPON_MAC_RST 47
++
++#endif /* __DT_BINDINGS_RESET_CONTROLLER_AIROHA_AN7583_H_ */
--- /dev/null
+From 289503869e5580658035e82d91b02a43c775f1a1 Mon Sep 17 00:00:00 2001
+Date: Mon, 19 May 2025 14:29:53 +0200
+Subject: [PATCH 1/4] net: airoha: add support for Airoha AN7583
+
+Add support for Ethernet controller present in Airoha AN7583. This
+follow the same implementation of Airoha AN7581 with the only difference
+of having a different reset number and a different logic to reach the
+SCU node.
+
+Generalize the driver for these 2 part to account for these minor
+difference.
+
+The switch init part also required some care as the Switch Internal PHY
+enable BMCR_PDOWN by default and tweak to GEPHY_CONN_CFG is also needed.
+
+---
+ drivers/net/airoha_eth.c | 168 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 147 insertions(+), 21 deletions(-)
+
+--- a/drivers/net/airoha_eth.c
++++ b/drivers/net/airoha_eth.c
+@@ -20,6 +20,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
++#include <linux/mii.h>
+ #include <linux/time.h>
+
+ #define AIROHA_MAX_NUM_GDM_PORTS 1
+@@ -27,6 +28,11 @@
+ #define AIROHA_MAX_NUM_RSTS 3
+ #define AIROHA_MAX_NUM_XSI_RSTS 4
+
++#define AIROHA_MAX_NUM_SWITCH_PORT 4
++#define AIROHA_MAX_PBUS_TRY 10
++#define AIROHA_PBUS_SLEEP 100
++#define AIROHA_PBUS_C22_MASK 0x800000
++
+ #define AIROHA_MAX_PACKET_SIZE 2048
+ #define AIROHA_NUM_TX_RING 1
+ #define AIROHA_NUM_RX_RING 1
+@@ -77,6 +83,19 @@
+ #define SWITCH_PHY_PRE_EN BIT(15)
+ #define SWITCH_PHY_END_ADDR GENMASK(12, 8)
+ #define SWITCH_PHY_ST_ADDR GENMASK(4, 0)
++#define SWITCH_GEPHY_CONN_CFG 0x7c14
++#define SWITCH_DPHY_CKIN_SEL BIT(31)
++#define SWITCH_PHY_CORE_REG_CLK_SEL BIT(30)
++#define SWITCH_ETHER_AFE_PWD GENMASK(28, 24)
++#define SWITCH_PBUS_PHY_IAC 0x7c20
++#define SWITCH_PBUS_PHY_START BIT(31)
++#define SWITCH_PBUS_PHY_CMD BIT(30)
++#define SWITCH_PBUS_PHY_CMD_READ FIELD_PREP(SWITCH_PBUS_PHY_CMD, 0x0)
++#define SWITCH_PBUS_PHY_CMD_WRITE FIELD_PREP(SWITCH_PBUS_PHY_CMD, 0x1)
++#define SWITCH_PBUS_PHY_PORTADDR GENMASK(28, 24)
++#define SWITCH_PBUS_PHY_REGADDR GENMASK(23, 0)
++#define SWITCH_PBUS_PHY_IAWD 0x7c24
++#define SWITCH_PBUS_PHY_IARD 0x7c28
+
+ /* FE */
+ #define PSE_BASE 0x0100
+@@ -311,6 +330,26 @@ struct airoha_eth {
+ struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
+ };
+
++struct airoha_eth_soc_data {
++ int num_xsi_rsts;
++ const char * const *xsi_rsts_names;
++ ofnode (*get_scu_node)(struct udevice *dev);
++ const char *switch_compatible;
++};
++
++static const char * const en7581_xsi_rsts_names[] = {
++ "hsi0-mac",
++ "hsi1-mac",
++ "hsi-mac",
++ "xfp-mac",
++};
++
++static const char * const an7583_xsi_rsts_names[] = {
++ "hsi0-mac",
++ "hsi1-mac",
++ "xfp-mac",
++};
++
+ static u32 airoha_rr(void __iomem *base, u32 offset)
+ {
+ return readl(base + offset);
+@@ -351,8 +390,12 @@ static u32 airoha_rmw(void __iomem *base
+ #define airoha_qdma_clear(qdma, offset, val) \
+ airoha_rmw((qdma)->regs, (offset), (val), 0)
+
++#define airoha_switch_rr(eth, offset) \
++ airoha_rr((eth)->switch_regs, (offset))
+ #define airoha_switch_wr(eth, offset, val) \
+ airoha_wr((eth)->switch_regs, (offset), (val))
++#define airoha_switch_rmw(eth, offset, mask, val) \
++ airoha_rmw((eth)->switch_regs, (offset), (mask), (val))
+
+ static void airoha_fe_maccr_init(struct airoha_eth *eth)
+ {
+@@ -652,10 +695,12 @@ static int airoha_hw_init(struct udevice
+
+ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
+ {
++ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
+ ofnode switch_node;
+ fdt_addr_t addr;
+
+- switch_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-switch");
++ switch_node = ofnode_by_compatible(ofnode_null(),
++ data->switch_compatible);
+ if (!ofnode_valid(switch_node))
+ return -EINVAL;
+
+@@ -687,17 +732,71 @@ static int airoha_switch_init(struct ude
+ FIELD_PREP(SWITCH_PHY_END_ADDR, 0xc) |
+ FIELD_PREP(SWITCH_PHY_ST_ADDR, 0x8));
+
++ /* AN7583 require tweak to GEPHY_CONN_CFG and clear PHY BMCR_PDOWN */
++ if (!strcmp(data->switch_compatible, "airoha,an7583-switch")) {
++ int i;
++
++ airoha_switch_rmw(eth, SWITCH_GEPHY_CONN_CFG,
++ SWITCH_DPHY_CKIN_SEL |
++ SWITCH_PHY_CORE_REG_CLK_SEL |
++ SWITCH_ETHER_AFE_PWD,
++ SWITCH_DPHY_CKIN_SEL |
++ SWITCH_PHY_CORE_REG_CLK_SEL |
++ FIELD_PREP(SWITCH_ETHER_AFE_PWD, 0));
++
++ /* Disable BMCR_PDOWN for every PHY */
++ for (i = 0; i < AIROHA_MAX_NUM_SWITCH_PORT; i++) {
++ int try;
++ u32 val;
++
++ airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAC,
++ SWITCH_PBUS_PHY_START |
++ SWITCH_PBUS_PHY_CMD_READ |
++ FIELD_PREP(SWITCH_PBUS_PHY_PORTADDR, i) |
++ FIELD_PREP(SWITCH_PBUS_PHY_REGADDR,
++ AIROHA_PBUS_C22_MASK | MII_BMCR));
++
++ for (try = 0; try < AIROHA_MAX_PBUS_TRY; try++) {
++ val = airoha_switch_rr(eth, SWITCH_PBUS_PHY_IAC);
++ if (!(val & SWITCH_PBUS_PHY_START))
++ break;
++
++ udelay(AIROHA_PBUS_SLEEP);
++ }
++
++ val = airoha_switch_rr(eth, SWITCH_PBUS_PHY_IARD);
++ val &= ~BMCR_PDOWN;
++
++ airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAWD, val);
++ airoha_switch_wr(eth, SWITCH_PBUS_PHY_IAC,
++ SWITCH_PBUS_PHY_START |
++ SWITCH_PBUS_PHY_CMD_WRITE |
++ FIELD_PREP(SWITCH_PBUS_PHY_PORTADDR, i) |
++ FIELD_PREP(SWITCH_PBUS_PHY_REGADDR,
++ AIROHA_PBUS_C22_MASK | MII_BMCR));
++
++ for (try = 0; try < AIROHA_MAX_PBUS_TRY; try++) {
++ val = airoha_switch_rr(eth, SWITCH_PBUS_PHY_IAC);
++ if (!(val & SWITCH_PBUS_PHY_START))
++ break;
++
++ udelay(AIROHA_PBUS_SLEEP);
++ }
++ }
++ }
++
+ return 0;
+ }
+
+ static int airoha_eth_probe(struct udevice *dev)
+ {
++ struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct regmap *scu_regmap;
+ ofnode scu_node;
+- int ret;
++ int i, ret;
+
+- scu_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu");
++ scu_node = data->get_scu_node(dev);
+ if (!ofnode_valid(scu_node))
+ return -EINVAL;
+
+@@ -721,11 +820,11 @@ static int airoha_eth_probe(struct udevi
+ return -ENOMEM;
+ eth->rsts.count = AIROHA_MAX_NUM_RSTS;
+
+- eth->xsi_rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_XSI_RSTS,
++ eth->xsi_rsts.resets = devm_kcalloc(dev, data->num_xsi_rsts,
+ sizeof(struct reset_ctl), GFP_KERNEL);
+ if (!eth->xsi_rsts.resets)
+ return -ENOMEM;
+- eth->xsi_rsts.count = AIROHA_MAX_NUM_XSI_RSTS;
++ eth->xsi_rsts.count = data->num_xsi_rsts;
+
+ ret = reset_get_by_name(dev, "fe", ð->rsts.resets[0]);
+ if (ret)
+@@ -739,21 +838,12 @@ static int airoha_eth_probe(struct udevi
+ if (ret)
+ return ret;
+
+- ret = reset_get_by_name(dev, "hsi0-mac", ð->xsi_rsts.resets[0]);
+- if (ret)
+- return ret;
+-
+- ret = reset_get_by_name(dev, "hsi1-mac", ð->xsi_rsts.resets[1]);
+- if (ret)
+- return ret;
+-
+- ret = reset_get_by_name(dev, "hsi-mac", ð->xsi_rsts.resets[2]);
+- if (ret)
+- return ret;
+-
+- ret = reset_get_by_name(dev, "xfp-mac", ð->xsi_rsts.resets[3]);
+- if (ret)
+- return ret;
++ for (i = 0; i < data->num_xsi_rsts; i++) {
++ ret = reset_get_by_name(dev, data->xsi_rsts_names[i],
++ ð->xsi_rsts.resets[i]);
++ if (ret)
++ return ret;
++ }
+
+ ret = airoha_hw_init(dev, eth);
+ if (ret)
+@@ -924,8 +1014,44 @@ static int arht_eth_write_hwaddr(struct
+ return 0;
+ }
+
++
++static ofnode en7581_get_scu_node(struct udevice *dev)
++{
++ return ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu");
++}
++
++static ofnode an7583_get_scu_node(struct udevice *dev)
++{
++ ofnode scu_node;
++
++ scu_node = ofnode_by_compatible(ofnode_null(), "airoha,an7583-scu");
++ if (!ofnode_valid(scu_node))
++ return scu_node;
++
++ return ofnode_get_parent(scu_node);
++}
++
++static const struct airoha_eth_soc_data en7581_data = {
++ .xsi_rsts_names = en7581_xsi_rsts_names,
++ .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
++ .get_scu_node = en7581_get_scu_node,
++ .switch_compatible = "airoha,en7581-switch",
++};
++
++static const struct airoha_eth_soc_data an7583_data = {
++ .xsi_rsts_names = an7583_xsi_rsts_names,
++ .num_xsi_rsts = ARRAY_SIZE(an7583_xsi_rsts_names),
++ .get_scu_node = an7583_get_scu_node,
++ .switch_compatible = "airoha,an7583-switch",
++};
++
+ static const struct udevice_id airoha_eth_ids[] = {
+- { .compatible = "airoha,en7581-eth" },
++ { .compatible = "airoha,en7581-eth",
++ .data = (ulong)&en7581_data,
++ },
++ { .compatible = "airoha,an7583-eth",
++ .data = (ulong)&an7583_data,
++ },
+ };
+
+ static const struct eth_ops airoha_eth_ops = {
--- /dev/null
+From 613d695d0939cbbe6b66933267e3a4be263e1c7b Mon Sep 17 00:00:00 2001
+Date: Mon, 19 May 2025 14:31:59 +0200
+Subject: [PATCH 2/4] airoha: add Ethernet node in AN7583 dtsi
+
+Add Ethernet node in AN7583 dtsi to add support for the integrated
+Ethernet Controller.
+
+---
+ arch/arm/dts/an7583.dtsi | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/arch/arm/dts/an7583.dtsi
++++ b/arch/arm/dts/an7583.dtsi
+@@ -130,6 +130,29 @@
+ reg = <0x0 0x1fa20000 0x0 0x388>;
+ };
+
++ eth: ethernet@1fb50000 {
++ compatible = "airoha,an7583-eth";
++ reg = <0 0x1fb50000 0 0x2600>,
++ <0 0x1fb54000 0 0x2000>,
++ <0 0x1fb56000 0 0x2000>;
++ reg-names = "fe", "qdma0", "qdma1";
++
++ resets = <&scuclk AN7583_FE_RST>,
++ <&scuclk AN7583_FE_PDMA_RST>,
++ <&scuclk AN7583_FE_QDMA_RST>,
++ <&scuclk AN7583_DUAL_HSI0_MAC_RST>,
++ <&scuclk AN7583_DUAL_HSI1_MAC_RST>,
++ <&scuclk AN7583_XFP_MAC_RST>;
++ reset-names = "fe", "pdma", "qdma",
++ "hsi0-mac", "hsi1-mac",
++ "xfp-mac";
++ };
++
++ switch: switch@1fb58000 {
++ compatible = "airoha,an7583-switch";
++ reg = <0 0x1fb58000 0 0x8000>;
++ };
++
+ syscon@1fbe3400 {
+ compatible = "airoha,en7581-pbus-csr", "syscon";
+ reg = <0x0 0x1fbe3400 0x0 0xff>;
--- /dev/null
+From 1a3039c1e3a194b3f1e72b4506f8bdcd5b10fbbf Mon Sep 17 00:00:00 2001
+Date: Mon, 19 May 2025 14:52:26 +0200
+Subject: [PATCH] airoha: add MMC node for Airoha AN7583
+
+Add MMC node for Airoha AN7583. These follow the same node of Airoha
+AN7581.
+
+Similar to Airoha AN7581, add the fixed regulator and fixed clock for
+MMC.
+
+---
+ arch/arm/dts/an7583.dtsi | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/arch/arm/dts/an7583.dtsi
++++ b/arch/arm/dts/an7583.dtsi
+@@ -105,6 +105,21 @@
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
++ clk25m: oscillator {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <25000000>;
++ clock-output-names = "clkxtal";
++ };
++
++ vmmc_3v3: regulator-vmmc-3v3 {
++ compatible = "regulator-fixed";
++ regulator-name = "vmmc";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+@@ -259,6 +274,24 @@
+ };
+ };
+
++ mmc0: mmc@1fa0e000 {
++ compatible = "mediatek,mt7622-mmc";
++ reg = <0x0 0x1fa0e000 0x0 0x1000>,
++ <0x0 0x1fa0c000 0x0 0x60>;
++ interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
++ clocks = <&scuclk EN7581_CLK_EMMC>, <&clk25m>;
++ clock-names = "source", "hclk";
++ bus-width = <4>;
++ max-frequency = <52000000>;
++ vmmc-supply = <&vmmc_3v3>;
++ disable-wp;
++ cap-mmc-highspeed;
++ non-removable;
++
++ assigned-clocks = <&scuclk EN7581_CLK_EMMC>;
++ assigned-clock-rates = <200000000>;
++ };
++
+ uart1: serial@1fbf0000 {
+ compatible = "ns16550";
+ reg = <0x0 0x1fbf0000 0x0 0x30>;
--- /dev/null
+From 0343b5c2a754ca20f5155a8f3c6d58e887b9dd4f Mon Sep 17 00:00:00 2001
+Date: Tue, 20 May 2025 16:32:31 +0200
+Subject: [PATCH] net: airoha: Fix spurious Airoha Ethernet stall
+
+It was reported that sometimes the Airoha Ethernet driver stall and a
+reset is needed to actually receive packet.
+
+This seems to be related in the logic with how the CPU and DMA counter
+are handled for the RX path. The problem seems to be more evident when
+multiple device are connected to the Ethernet port.
+
+To handle this, drop local tracking of the current CPU/DMA counter and
+base everything on the current register by reading them and using the
+descriptor directly.
+
+Fixes: ee0f4afa982e ("net: airoha: Add Airoha Ethernet driver")
+---
+ drivers/net/airoha_eth.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/airoha_eth.c
++++ b/drivers/net/airoha_eth.c
+@@ -286,7 +286,6 @@ struct airoha_qdma_fwd_desc {
+
+ struct airoha_queue {
+ struct airoha_qdma_desc *desc;
+- u16 head;
+
+ int ndesc;
+ };
+@@ -452,7 +451,6 @@ static int airoha_qdma_init_rx_queue(str
+ unsigned long dma_addr;
+
+ q->ndesc = ndesc;
+- q->head = 0;
+
+ q->desc = dma_alloc_coherent(q->ndesc * sizeof(*q->desc), &dma_addr);
+ if (!q->desc)
+@@ -471,7 +469,7 @@ static int airoha_qdma_init_rx_queue(str
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+ FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1));
+ airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
+- FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head));
++ FIELD_PREP(RX_RING_DMA_IDX_MASK, 0));
+
+ return 0;
+ }
+@@ -499,7 +497,6 @@ static int airoha_qdma_init_tx_queue(str
+ unsigned long dma_addr;
+
+ q->ndesc = size;
+- q->head = 0;
+
+ q->desc = dma_alloc_coherent(q->ndesc * sizeof(*q->desc), &dma_addr);
+ if (!q->desc)
+@@ -510,9 +507,9 @@ static int airoha_qdma_init_tx_queue(str
+
+ airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr);
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+- FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head));
++ FIELD_PREP(TX_RING_CPU_IDX_MASK, 0));
+ airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK,
+- FIELD_PREP(TX_RING_DMA_IDX_MASK, q->head));
++ FIELD_PREP(TX_RING_DMA_IDX_MASK, 0));
+
+ return 0;
+ }
+@@ -898,8 +895,10 @@ static int airoha_eth_send(struct udevic
+
+ qid = 0;
+ q = &qdma->q_tx[qid];
+- desc = &q->desc[q->head];
+- index = (q->head + 1) % q->ndesc;
++
++ index = airoha_qdma_rr(qdma, REG_TX_CPU_IDX(qid));
++ desc = &q->desc[index];
++ index = (index + 1) % q->ndesc;
+
+ fport = 1;
+
+@@ -934,7 +933,6 @@ static int airoha_eth_send(struct udevic
+ if (!(desc->ctrl & QDMA_DESC_DONE_MASK))
+ return -EAGAIN;
+
+- q->head = index;
+ airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(0),
+ IRQ_CLEAR_LEN_MASK, 1);
+
+@@ -947,12 +945,15 @@ static int airoha_eth_recv(struct udevic
+ struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_qdma_desc *desc;
+ struct airoha_queue *q;
++ int qid, index;
+ u16 length;
+- int qid;
+
+ qid = 0;
+ q = &qdma->q_rx[qid];
+- desc = &q->desc[q->head];
++
++ index = airoha_qdma_rr(qdma, REG_RX_CPU_IDX(qid));
++ index = (index + 1) % q->ndesc;
++ desc = &q->desc[index];
+
+ dma_unmap_single(virt_to_phys(desc), sizeof(*desc),
+ DMA_FROM_DEVICE);
+@@ -974,7 +975,7 @@ static int arht_eth_free_pkt(struct udev
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_queue *q;
+- int qid;
++ int qid, index;
+
+ if (!packet)
+ return 0;
+@@ -984,11 +985,12 @@ static int arht_eth_free_pkt(struct udev
+
+ dma_map_single(packet, length, DMA_TO_DEVICE);
+
+- airoha_qdma_reset_rx_desc(q, q->head, packet);
++ index = airoha_qdma_rr(qdma, REG_RX_DMA_IDX(qid));
++ airoha_qdma_reset_rx_desc(q, index, packet);
+
++ index = (index + 1) % q->ndesc;
+ airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK,
+- FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head));
+- q->head = (q->head + 1) % q->ndesc;
++ FIELD_PREP(RX_RING_CPU_IDX_MASK, index));
+
+ return 0;
+ }
--- /dev/null
+From 28a72d957b897e7f7212c11f99052a32b0f6abc4 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 May 2025 03:10:53 +0200
+Subject: [PATCH 1/2] airoha: enable UBI support and define default partition
+
+---
+ arch/arm/dts/an7581-u-boot.dtsi | 16 ++++++++++++++++
+ arch/arm/dts/an7583-evb.dts | 22 ++++++++++++++++++++++
+ configs/an7581_evb_defconfig | 16 ++++++++++++++++
+ configs/an7583_evb_defconfig | 16 ++++++++++++++++
+ 4 files changed, 70 insertions(+)
+
+--- a/arch/arm/dts/an7581-u-boot.dtsi
++++ b/arch/arm/dts/an7581-u-boot.dtsi
+@@ -76,6 +76,22 @@
+ spi-max-frequency = <50000000>;
+ spi-tx-bus-width = <1>;
+ spi-rx-bus-width = <2>;
++
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bl2@0 {
++ label = "bl2";
++ reg = <0x0 0x20000>;
++ };
++
++ ubi@20000 {
++ label = "ubi";
++ reg = <0x20000 0x0>;
++ };
++ };
+ };
+ };
+
+--- a/arch/arm/dts/an7583-evb.dts
++++ b/arch/arm/dts/an7583-evb.dts
+@@ -46,6 +46,28 @@
+ };
+ };
+
++&snfi {
++ status = "okay";
++};
++
++&spi_nand {
++ partitions {
++ compatible = "fixed-partitions";
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ bl2@0 {
++ label = "bl2";
++ reg = <0x0 0x20000>;
++ };
++
++ ubi@20000 {
++ label = "ubi";
++ reg = <0x20000 0x0>;
++ };
++ };
++};
++
+ &pcie0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie0_rst_pins>;
+--- a/configs/an7581_evb_defconfig
++++ b/configs/an7581_evb_defconfig
+@@ -77,3 +77,19 @@ CONFIG_SPI=y
+ CONFIG_DM_SPI=y
+ CONFIG_AIROHA_SNFI_SPI=y
+ CONFIG_SHA512=y
++CONFIG_CMD_UBI=y
++# CONFIG_CMD_UBI_RENAME is not set
++CONFIG_CMD_UBIFS=y
++CONFIG_ENV_IS_IN_UBI=y
++CONFIG_ENV_UBI_PART="ubi"
++CONFIG_ENV_UBI_VOLUME="ubootenv"
++CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2"
++CONFIG_ENV_UBI_VID_OFFSET=0
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_MODULE=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++CONFIG_UBI_BLOCK=y
++# CONFIG_UBIFS_SILENCE_MSG is not set
++# CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
+--- a/configs/an7583_evb_defconfig
++++ b/configs/an7583_evb_defconfig
+@@ -79,3 +79,19 @@ CONFIG_SHA512=y
+ CONFIG_AIROHA_ETH=y
+ CONFIG_MMC_MTK=y
+ CONFIG_AIROHA_SNFI_SPI=y
++CONFIG_CMD_UBI=y
++# CONFIG_CMD_UBI_RENAME is not set
++CONFIG_CMD_UBIFS=y
++CONFIG_ENV_IS_IN_UBI=y
++CONFIG_ENV_UBI_PART="ubi"
++CONFIG_ENV_UBI_VOLUME="ubootenv"
++CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2"
++CONFIG_ENV_UBI_VID_OFFSET=0
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_MODULE=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_LIMIT=20
++# CONFIG_MTD_UBI_FASTMAP is not set
++CONFIG_UBI_BLOCK=y
++# CONFIG_UBIFS_SILENCE_MSG is not set
++# CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
--- /dev/null
+From f85e675d7be222d88246bfdb42a1faac92f1eb63 Mon Sep 17 00:00:00 2001
+Date: Wed, 28 May 2025 03:18:32 +0200
+Subject: [PATCH 2/2] airoha: add default configuration
+
+---
+ configs/an7581_evb_defconfig | 2 ++
+ configs/an7583_evb_defconfig | 2 ++
+ defenvs/an7581_rfb_env | 3 +++
+ defenvs/an7583_rfb_env | 3 +++
+ 4 files changed, 10 insertions(+)
+ create mode 100644 defenvs/an7581_rfb_env
+ create mode 100644 defenvs/an7583_rfb_env
+
+--- a/configs/an7581_evb_defconfig
++++ b/configs/an7581_evb_defconfig
+@@ -93,3 +93,5 @@ CONFIG_MTD_UBI_BEB_LIMIT=20
+ CONFIG_UBI_BLOCK=y
+ # CONFIG_UBIFS_SILENCE_MSG is not set
+ # CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
++CONFIG_USE_DEFAULT_ENV_FILE=y
++CONFIG_DEFAULT_ENV_FILE="defenvs/an7581_rfb_env"
+--- a/configs/an7583_evb_defconfig
++++ b/configs/an7583_evb_defconfig
+@@ -95,3 +95,5 @@ CONFIG_MTD_UBI_BEB_LIMIT=20
+ CONFIG_UBI_BLOCK=y
+ # CONFIG_UBIFS_SILENCE_MSG is not set
+ # CONFIG_UBIFS_SILENCE_DEBUG_DUMP is not set
++CONFIG_USE_DEFAULT_ENV_FILE=y
++CONFIG_DEFAULT_ENV_FILE="defenvs/an7583_rfb_env"
+--- /dev/null
++++ b/defenvs/an7581_rfb_env
+@@ -0,0 +1,4 @@
++loadaddr=0x81800000
++ipaddr=192.168.1.1
++serverip=192.168.1.10
++bootargs=ubi.mtd=ubi root=/dev/ubiblock0_5 rootwait
+--- /dev/null
++++ b/defenvs/an7583_rfb_env
+@@ -0,0 +1,4 @@
++loadaddr=0x81800000
++ipaddr=192.168.1.1
++serverip=192.168.1.10
++bootargs=ubi.mtd=ubi root=/dev/ubiblock0_5 rootwait