diff --git a/.github/workflows/build-boot.yml b/.github/workflows/build-boot.yml index e84e582af..4cd741e21 100644 --- a/.github/workflows/build-boot.yml +++ b/.github/workflows/build-boot.yml @@ -19,6 +19,8 @@ jobs: - aarch64_qemu_boot - bpi_r3_sd_boot - bpi_r3_emmc_boot + - bpi_r4_sd_boot + - bpi_r4_emmc_boot - bpi_r64_sd_boot - bpi_r64_emmc_boot - cn9130_crb_boot diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 497ef794f..16c17b7de 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -11,6 +11,7 @@ on: - raspberrypi-rpi2 - raspberrypi-rpi64 - bananapi-bpi-r3 + - bananapi-bpi-r4 - bananapi-bpi-r64 - friendlyarm-nanopi-r2s - microchip-sama7g54-ek @@ -68,6 +69,12 @@ jobs: echo "ARCH=aarch64" >> $GITHUB_ENV echo "BUILD_EMMC=true" >> $GITHUB_ENV ;; + bananapi-bpi-r4) + echo "BOOTLOADER_SD=bpi-r4-sd-boot" >> $GITHUB_ENV + echo "BOOTLOADER_EMMC=bpi-r4-emmc-boot" >> $GITHUB_ENV + echo "ARCH=aarch64" >> $GITHUB_ENV + echo "BUILD_EMMC=true" >> $GITHUB_ENV + ;; bananapi-bpi-r64) echo "BOOTLOADER_SD=bpi-r64-sd-boot" >> $GITHUB_ENV echo "BOOTLOADER_EMMC=bpi-r64-emmc-boot" >> $GITHUB_ENV diff --git a/board/aarch64/Config.in b/board/aarch64/Config.in index a27864e8c..20acf6824 100644 --- a/board/aarch64/Config.in +++ b/board/aarch64/Config.in @@ -2,6 +2,7 @@ if BR2_aarch64 source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/alder-alder/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/bananapi-bpi-r3/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/bananapi-bpi-r4/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/bananapi-bpi-r64/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/freescale-imx8mp-evk/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/friendlyarm-nanopi-r2s/Config.in" diff --git a/board/aarch64/README.md b/board/aarch64/README.md index 074cfab48..61dca726b 100644 --- a/board/aarch64/README.md +++ b/board/aarch64/README.md @@ -4,9 +4,10 @@ aarch64 Board Specific Documentation ---------------------------- -- [Banana Pi BPi-R3](banana-pi-r3/) -- [Banana Pi BPi-R64](banana-pi-r64/) -- [Marvell CN9130-CRB](cn9130-crb/) -- [Microchip SparX-5i PCB135 (eMMC)](sparx5-pcb135/) -- [NanoPi R2S](r2s/) -- [Raspberry Pi 64-bit](raspberry-pi64/) +- [Banana Pi BPi-R3](bananapi-bpi-r3/) +- [Banana Pi BPi-R4](bananapi-bpi-r4/) +- [Banana Pi BPi-R64](bananapi-bpi-r64/) +- [Marvell CN9130-CRB](marvell-cn9130-crb/) +- [Microchip SparX-5i PCB135 (eMMC)](microchip-sparx5-pcb135/) +- [NanoPi R2S](friendlyarm-nanopi-r2s/) +- [Raspberry Pi 64-bit](raspberrypi-rpi64/) diff --git a/board/aarch64/alder-alder/alder-alder.hash b/board/aarch64/alder-alder/alder-alder.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/alder-alder/alder-alder.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/aarch64/bananapi-bpi-r3/bananapi-bpi-r3.hash b/board/aarch64/bananapi-bpi-r3/bananapi-bpi-r3.hash new file mode 100644 index 000000000..d1a69bc36 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r3/bananapi-bpi-r3.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 dbe4eae8debbba8135297e15f24aeefef0b4c03781f3f9328db4398d58a728b3 LICENSE diff --git a/board/aarch64/bananapi-bpi-r4/Config.in b/board/aarch64/bananapi-bpi-r4/Config.in new file mode 100644 index 000000000..cfb7fc863 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/Config.in @@ -0,0 +1,11 @@ +config BR2_PACKAGE_BANANAPI_BPI_R4 + bool "Banana Pi R4" + depends on BR2_aarch64 + select BR2_PACKAGE_FEATURE_WIFI + select BR2_PACKAGE_LINUX_FIRMWARE + select BR2_PACKAGE_LINUX_FIRMWARE_MEDIATEK + select BR2_PACKAGE_LINUX_FIRMWARE_MEDIATEK_MT7988 + select BR2_PACKAGE_LINUX_FIRMWARE_MEDIATEK_MT7996 + select SDCARD_AUX + help + Build Banana PI R4 support diff --git a/board/aarch64/bananapi-bpi-r4/LICENSE b/board/aarch64/bananapi-bpi-r4/LICENSE new file mode 100644 index 000000000..8cdb30a3a --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2026 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/board/aarch64/bananapi-bpi-r4/README.md b/board/aarch64/bananapi-bpi-r4/README.md new file mode 100644 index 000000000..d9cb6eda7 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/README.md @@ -0,0 +1,360 @@ +# Banana Pi BPI-R4 / BPI-R4-2g5 / BPI-R4P + +The board + +## Overview + +The Banana Pi BPI-R4 is a high-performance networking board built around the +MediaTek MT7988A SoC (Filogic 880). It is a successor to the BPI-R3 and +represents a significant step up: the CPU switches from in-order Cortex-A53 +cores to out-of-order Cortex-A73 cores, and the MT7531 switch is now part of +the SOC. The base model comes with two SFP+ cages supporting 1.25/2.5/5/10 +Gbps, and the R4P model comes with one SFP+ cage and one 2.5 Gbps RJ45 jack, +which with an optional PoE board means the board can act as PD. Unlike the +BPi-R3, however, there is no on-board WiFi support, that requires an external +tri-band WiFi 7 (IEEE 802.11be) card. + +### Variants + +| **Feature** | **BPI-R4** | **BPI-R4-2g5** | **BPI-R4P** | +|------------------|------------------|-------------------|---------------------------| +| 1G switch ports | wan, lan1–lan3 | lan0–lan3 | lan0–lan3 | +| 2.5G RJ45 (WAN) | — | wan | wan (PoE input) | +| SFP+ port(s) | sfp1, sfp2 (10G) | sfp1 (10G) | sfp1 (10G) | +| Linux DT | bpi-r4 | bpi-r4-2g5 | bpi-r4-2g5 (same) | + +On the standard BPI-R4 the four 1G switch ports are labeled `wan`, `lan1`, `lan2`, +and `lan3`. On the R4-2g5 and R4P, the port that would otherwise be `wan` on the +switch is relabeled `lan0` via a device tree overlay, since the actual WAN port on +those variants is the dedicated 2.5G internal PHY on the separate RJ45 jack. + +The BPI-R4P is mechanically and electrically identical to the BPI-R4-2g5 +with an additional PoE daughterboard header. From a Linux kernel and +Infix perspective the two boards are treated identically. + +### SoC: MediaTek MT7988A vs MT7986 (BPI-R3) + +The MT7988A (Filogic 880) and MT7986 (Filogic 820) may look similar from +their part numbers, but they are built on entirely different silicon with +distinct system architectures: + +| **Aspect** | **MT7988A (BPI-R4)** | **MT7986 (BPI-R3)** | +|------------------|--------------------------|---------------------------| +| CPU cores | 4x Cortex-A73 @ 1.8 GHz | 4x Cortex-A53 @ 2.0 GHz | +| CPU architecture | ARMv8-A, out-of-order | ARMv8-A, in-order | +| Internal switch | 1 Gbps per port | 1 Gbps per port | +| Uplinks | USXGMII (native 10 Gbps) | USXGMII (native 2.5 Gbps) | +| WiFi | MT7996E PCIe module | MT7915E (built-in) | +| WiFi standard | WiFi 7 (802.11be) | WiFi 6 (802.11ax) | +| WiFi bands | 2.4 / 5 / 6 GHz | 2.4 / 5 GHz | +| Hardware crypto | EIP-197 NPU | EIP-93 | +| PCIe slots | 4 (2x mPCIe, 2x M.2) | 1 mPCIe | +| Boot ROM offset | Sector 1024 (0x80000) | Sector 1024 (0x80000) | + +### Hardware Features + +- **SoC:** MediaTek MT7988A (Filogic 880) +- **CPU:** Quad-core ARM Cortex-A73, up to 1.8 GHz +- **RAM:** 4 GB DDR4 +- **Storage:** 8 GB eMMC, microSD card slot, SPI NAND flash +- **Ethernet switch:** 4-port 1 GbE (10/100/1000) internal DSA switch +- **SFP+ ports:** 2x 10 Gbps USXGMII (standard R4) or 1x SFP+ (R4-2g5/R4P) +- **WiFi:** optional MediaTek MT7996E PCIe module — tri-band WiFi 7 (2.4/5/6 GHz) +- **USB:** 1x USB 3.0 (xHCI) +- **PCIe:** 2x mPCIe (SIM2/SIM3), 1x M.2 Key-B (SIM1), 1x M.2 Key-M (SSD) +- **RTC:** PCF8563 on I2C +- **Fan:** PWM-controlled cooling with thermal management +- **Console:** UART at 115200 8N1 (3.3 V, USB-to-serial adapter required) + +### Default Network Configuration + +Infix ships with the following factory defaults. + +**Standard BPI-R4:** + +- **LAN bridge** (`br0`, 192.168.0.1/24): `lan1`, `lan2`, `lan3` (1G switch ports) +- **WAN port** (`wan`): DHCP client, used for internet uplink (1G switch port) +- **SFP+ ports** (`sfp1`, `sfp2`): Present but unconfigured + +**BPI-R4-2g5 and BPI-R4P:** + +- **LAN bridge** (`br0`, 192.168.0.1/24): `lan0`, `lan1`, `lan2`, `lan3` (1G switch ports) +- **WAN port** (`wan`): DHCP client, used for internet uplink (2.5G internal PHY) +- **SFP+ port** (`sfp1`): Present but unconfigured + +> [!NOTE] +> If an optional WiFi 7 (MT7996E) PCIe card is installed, the radio interfaces +> are bridged into the LAN as access points. WiFi is not included with the board +> and is not part of the factory default configuration. + + +## Getting Started + +Console header pins + +### Quick Start with SD Card + +1. **Download the SD card image:** [infix-bpi-r4-sdcard.img][2] +2. **Flash the image to an SD card:** see [this guide][0] +3. **Set boot switches to SD card mode** (see Boot Switch Reference below) +4. **Insert the SD card, connect power and a serial console (115200 8N1)** +5. Default login: `admin` / `admin` + +### Boot Switch Reference + +DIP switches + +The BPI-R4 has a 2-position DIP switch (SW3) that selects the boot media. +Switch positions are printed on the board near the SD card slot. + +| A | B | Boot media (SW3) | +|-----|-----|------------------| +| OFF | ON | SPI NAND | +| ON | OFF | eMMC | +| ON | ON | SD card | + +> [!NOTE] +> "OFF" = switch in the UP position = logical 0. + +## Installing to eMMC + +For production use or better reliability, install Infix to the internal +eMMC storage. + +> [!IMPORTANT] +> The MT7988A has a single MMC controller that can only operate in one mode +> (SD or eMMC) per boot session. The SD card U-Boot cannot switch to eMMC +> mode mid-session, so an intermediate NAND bootloader step is required to +> write the eMMC — the same approach as BPi-R3. +> +> The MT7988A boot chain is: **BROM → BL2 → FIP (BL31 + U-Boot)**. The FIP +> (Firmware Image Package) bundles ARM Trusted Firmware (BL31) and U-Boot +> together; it is not just a U-Boot binary. When BL2 runs, it loads the FIP +> from a fixed offset and hands off to BL31, which then jumps into U-Boot. +> +> The factory SPI NAND contains a minimal recovery U-Boot that only supports +> TFTP — it has no USB command. You cannot use it to load files from a USB +> drive. Similarly, the factory eMMC ships with a basic OpenWRT image. +> You must first flash a full-featured U-Boot (from Frank-W) to SPI NAND via +> the SD card U-Boot before you can write the eMMC. +> +> This process involves three boot mode changes and multiple flash operations. +> Take your time and verify each step carefully. + +### Prerequisites + +- USB-to-serial adapter (3.3 V) for console access +- USB flash drive (FAT32 formatted) +- microSD card with Infix SD image, for initial boot +- Downloaded files (see below) + +### Required Files + +Place these files on a FAT32-formatted USB drive: + +1. **Infix eMMC image:** [infix-bpi-r4-emmc.img][3] +2. **eMMC bootloader** (from): [bpi-r4-emmc-boot-2026.01-latest.tar.gz][4] + - Extract `bl2.img` from the tarball to your USB drive +3. **Intermediate NAND bootloader** from Frank-W's U-Boot (for BPI-R4, SPI NAND): + - [bpi-r4_spim-nand_bl2.img][13] — BL2 first-stage loader + - [bpi-r4_spim-nand_fip.bin][14] — FIP image (BL31 + U-Boot) + +### Step 1: Boot from SD card + +1. Set boot switches to **SD card mode** (SW3: A=ON, B=ON) +2. Insert the SD card with the Infix image +3. Power on and break into U-Boot (press Ctrl-C during countdown) + +### Step 2: Flash intermediate NAND bootloader + +This installs a full-featured U-Boot to SPI NAND so the board can load files +from USB in the next step. From the SD card U-Boot prompt: + +``` +usb start +mtd erase spi-nand0 +fatload usb 0:1 0x50000000 bpi-r4_spim-nand_bl2.img +mtd write spi-nand0 0x50000000 0x0 0x100000 +fatload usb 0:1 0x50000000 bpi-r4_spim-nand_fip.bin +mtd write spi-nand0 0x50000000 0x580000 0x200000 +``` + +### Step 3: Boot from NAND + +1. Power off the board +2. Set boot switches to **SPI NAND mode** (SW3: A=OFF, B=ON) +3. Power on — you should boot into U-Boot again + +### Step 4: Write Infix image to eMMC + +From the U-Boot prompt: + +``` +usb start +fatload usb 0:1 0x50000000 infix-bpi-r4-emmc.img +setexpr blocks ${filesize} / 0x200 +mmc write 0x50000000 0x0 ${blocks} +``` + +### Step 5: Configure eMMC boot partition + +Write the BL2 bootloader to the eMMC boot partition: + +``` +mmc partconf 0 1 1 1 +mmc erase 0x0 0x400 +fatload usb 0:1 0x50000000 bl2.img +mmc write 0x50000000 0x0 0x400 +mmc partconf 0 1 1 0 +``` + +### Step 6: Boot from eMMC + +1. Power off the board +2. Set boot switches to **eMMC mode** (SW3: A=ON, B=OFF) +3. Remove the SD card (optional, recommended to verify eMMC boot) +4. Power on + +Your BPI-R4 should now boot Infix from internal eMMC storage. + +## Troubleshooting + +### Board won't boot + +- Verify boot switch positions — double-check against the wiki +- Ensure the power supply provides adequate current (12 V / 3 A recommended) +- Check the serial console output at 115200 8N1 + +### Can't break into U-Boot + +- Connect the serial console before powering on +- Press Ctrl-C immediately when boot messages appear +- Try power cycling and pressing Ctrl-C repeatedly during the countdown + +### eMMC boot fails after installation + +- Boot from NAND (SW3=ON) and verify the eMMC write completed without errors +- Re-run the `mmc partconf` sequence — a missed step is the most common + cause of failure +- Use `mmc info` to confirm the eMMC is detected + +### No network connectivity + +The interface names on BPI-R4 differ from BPI-R3. Confirm what Linux +has created with `ip link` and compare with the factory configuration: + +- `wan`, `lan1`–`lan3`: 1G switch ports (standard R4) +- `wan`, `lan0`–`lan3`: on R4-2g5/R4P, `wan` is the 2.5G internal PHY; `lan0`–`lan3` are 1G switch ports +- `sfp1` (and `sfp2` on standard R4): 10G SFP+ cage(s) + +If interface renames look wrong, check `dmesg | grep renamed` and if +you spot any errors, please report as an issue to the Infix tracker +on GitHub. + +## Board Variants + +### BPI-R4 + +The base model BPi-R4 ports look like this, the `wan` port is the same physical +switch port as `lan0` on the R4-2g5/R4P, but here it serves as the WAN port in +the factory default configuration. + +``` +.-. +| | .-----.-----.-----.-----. +| | _______ _______ | | | | | .---. +| | | | | | | | | | | | | .-----. +'-' '-------' '-------' '-----'-----'-----'-----' '---' '-----' +USB1 sfp1 sfp2 wan lan1 lan2 lan3 DC12V PD20V +``` + +### BPI-R4-2g5 and BPI-R4P + +These variants substitute one SFP+ cage for an internal 2.5 Gbps PHY +connected to a standard RJ45 jack. From a kernel perspective they use +the `mt7988a-bananapi-bpi-r4-2g5` device tree. + +The BPI-R4P additionally supports an optional PoE input daughterboard on +the 2.5 Gbps RJ45 port. The PoE circuitry is passive with respect to +Linux — no special kernel driver is required for basic operation. + +For these board variants, the WAN role moves to the dedicated 2.5G internal PHY, +so all four switch ports become LAN ports (`lan0`–`lan3`) instead of three: + +``` +.-. +| | .-----. .-----.-----.-----.-----. +| | _______ | | | | | | | .---. +| | | | | | | | | | | | | .-----. +'-' '-------' '-----' '-----'-----'-----'-----' '---' '-----' +USB1 sfp1 wan lan0 lan1 lan2 lan3 DC12V PD20V +``` + +### Selecting the Board Variant + +U-Boot cannot automatically distinguish the standard R4 from the R4-2g5/R4P at +boot time (the on-board EEPROM is not programmed from factory). Instead, the +variant is read from the persistent U-Boot environment on the `aux` partition, +and you have to set it manually using `fw_setenv` from a UNIX shell: + +```bash +# For BPI-R4-2g5 or BPI-R4P (1x SFP+ + 1x 2.5 Gbps RJ45): +sudo fw_setenv BOARD_VARIANT 2g5 + +# To revert to the standard BPI-R4 (2x SFP+) clear the setting: +sudo fw_setenv BOARD_VARIANT +``` + +> [!IMPORTANT] +> The change takes effect on the next reboot. No re-flashing is required, but +> you may want to do a factory reset to activate the changes in your system +> `startup-config`: `sudo factory -y` from shell, or the CLI. + +`fw_setenv` writes to the `uboot.env` file on the aux partition. U-Boot +reads this at every boot (before loading the kernel) and selects the +matching device tree: + +| `BOARD_VARIANT` | Device tree loaded | +|-----------------|-----------------------------------| +| *(unset)* | `mt7988a-bananapi-bpi-r4.dtb` | +| `2g5` | `mt7988a-bananapi-bpi-r4-2g5.dtb` | + +## Additional Resources + +- [Infix Documentation][1] +- [Official BPI-R4 Page][7] +- [BPI-R4 Forum][8] +- [Frank-W's site][9] +- [Release Downloads][10] +- [Bootloader Builds][11] + +## Building Custom Images + +```bash +# Build bootloaders for SD and eMMC +make x-bpi-r4-sd-boot +make x-bpi-r4-emmc-boot + +# Build main system +make aarch64 + +# Create SD card image +./utils/mkimage.sh -od bananapi-bpi-r4 + +# Create eMMC image +./utils/mkimage.sh -odt emmc bananapi-bpi-r4 +``` + +[0]: https://www.kernelkit.org/posts/flashing-sdcard/ +[1]: https://www.kernelkit.org/infix/latest/ +[2]: https://github.com/kernelkit/infix/releases/download/latest-boot/infix-bpi-r4-sdcard.img +[3]: https://github.com/kernelkit/infix/releases/download/latest-boot/infix-bpi-r4-emmc.img +[4]: https://github.com/kernelkit/infix/releases/download/latest-boot/bpi-r4-emmc-boot-2026.01-latest.tar.gz +[7]: https://docs.banana-pi.org/en/BPI-R4/BananaPi_BPI-R4 +[8]: https://forum.banana-pi.org/ +[9]: https://wiki.fw-web.de/doku.php?id=en:bpi-r4:start +[10]: https://github.com/kernelkit/infix/releases/tag/latest +[11]: https://github.com/kernelkit/infix/releases/tag/latest-boot +[12]: https://github.com/frank-w/u-boot/releases +[13]: https://github.com/frank-w/u-boot/releases/download/CI-BUILD-2026-01-bpi-2026.01-2026-01-15_2013/bpi-r4_spim-nand_bl2.img +[14]: https://github.com/frank-w/u-boot/releases/download/CI-BUILD-2026-01-bpi-2026.01-2026-01-15_2013/bpi-r4_spim-nand_fip.bin diff --git a/board/aarch64/bananapi-bpi-r4/banana_pi_bpi-r4_poe.jpg b/board/aarch64/bananapi-bpi-r4/banana_pi_bpi-r4_poe.jpg new file mode 100644 index 000000000..d035eb553 Binary files /dev/null and b/board/aarch64/bananapi-bpi-r4/banana_pi_bpi-r4_poe.jpg differ diff --git a/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.hash b/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.hash new file mode 100644 index 000000000..2b1e74432 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d48246c717b505cc11df95171f2fd548b389e1a463f1af4c68d0b69fe0d1009b LICENSE diff --git a/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.mk b/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.mk new file mode 100644 index 000000000..645a037a1 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/bananapi-bpi-r4.mk @@ -0,0 +1,49 @@ +define BANANAPI_BPI_R4_LINUX_CONFIG_FIXUPS + $(call KCONFIG_ENABLE_OPT,CONFIG_ARCH_MEDIATEK) + $(call KCONFIG_ENABLE_OPT,CONFIG_MACH_MT7988) + $(call KCONFIG_ENABLE_OPT,CONFIG_PINCTRL_MT7988) + $(call KCONFIG_ENABLE_OPT,CONFIG_SERIAL_8250_MT6577) + $(call KCONFIG_SET_OPT,CONFIG_I2C_GPIO,y) + $(call KCONFIG_SET_OPT,CONFIG_MTK_THERMAL,m) + $(call KCONFIG_SET_OPT,CONFIG_MTK_LVTS_THERMAL,m) + $(call KCONFIG_ENABLE_OPT,CONFIG_MTK_UART) + $(call KCONFIG_ENABLE_OPT,CONFIG_MEDIATEK_WATCHDOG) + $(call KCONFIG_ENABLE_OPT,CONFIG_MEDIATEK_GE_PHY) + $(call KCONFIG_ENABLE_OPT,CONFIG_MEDIATEK_GE_SOC_PHY) + $(call KCONFIG_ENABLE_OPT,CONFIG_NET_VENDOR_MEDIATEK) + $(call KCONFIG_ENABLE_OPT,CONFIG_NET_MEDIATEK_SOC) + $(call KCONFIG_SET_OPT,CONFIG_NET_DSA_MT7530,m) + $(call KCONFIG_SET_OPT,CONFIG_MT7996E,m) + $(call KCONFIG_SET_OPT,CONFIG_PCIE_MEDIATEK_GEN3,m) + $(call KCONFIG_ENABLE_OPT,CONFIG_MTK_SCPSYS) + $(call KCONFIG_ENABLE_OPT,CONFIG_MMC_MTK) + $(call KCONFIG_SET_OPT,CONFIG_I2C_MT65XX,m) + $(call KCONFIG_SET_OPT,CONFIG_USB_XHCI_MTK,m) + $(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_TPHY,m) + $(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_XSPHY,m) + $(call KCONFIG_SET_OPT,CONFIG_PHY_MTK_XFI_TPHY,m) + $(call KCONFIG_SET_OPT,CONFIG_PCS_STANDALONE,y) + $(call KCONFIG_SET_OPT,CONFIG_PCS_MTK_USXGMII,y) + $(call KCONFIG_SET_OPT,CONFIG_PWM_MEDIATEK,m) + $(call KCONFIG_SET_OPT,CONFIG_SENSORS_PWM_FAN,m) + $(call KCONFIG_SET_OPT,CONFIG_NVMEM_MTK_EFUSE,m) + $(call KCONFIG_SET_OPT,CONFIG_MEDIATEK_2P5GE_PHY,m) + $(call KCONFIG_SET_OPT,CONFIG_CRYPTO_DEV_SAFEXCEL,m) +endef + +LINUX_DTS_MT7988 = $(LINUX_DIR)/arch/arm64/boot/dts/mediatek + +define BANANAPI_BPI_R4_KERNEL_DTBS_INSTALL_TARGET + @$(call MESSAGE,"Installing kernel DTBs and DTBOs for BPI-R4") + $(foreach f, \ + mt7988a-bananapi-bpi-r4.dtb \ + mt7988a-bananapi-bpi-r4-2g5.dtb \ + mt7988a-bananapi-bpi-r4-sd.dtbo \ + mt7988a-bananapi-bpi-r4-emmc.dtbo, \ + $(INSTALL) -D $(LINUX_DTS_MT7988)/$(f) \ + $(TARGET_DIR)/boot/mediatek/$(f)$(sep)) +endef +BANANAPI_BPI_R4_POST_INSTALL_TARGET_HOOKS += BANANAPI_BPI_R4_KERNEL_DTBS_INSTALL_TARGET + +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/board/aarch64/bananapi-bpi-r4/bootstrap-sw3.png b/board/aarch64/bananapi-bpi-r4/bootstrap-sw3.png new file mode 100644 index 000000000..a76d17152 Binary files /dev/null and b/board/aarch64/bananapi-bpi-r4/bootstrap-sw3.png differ diff --git a/board/aarch64/bananapi-bpi-r4/bootstrap-switch.jpg b/board/aarch64/bananapi-bpi-r4/bootstrap-switch.jpg new file mode 100644 index 000000000..70c3a3d91 Binary files /dev/null and b/board/aarch64/bananapi-bpi-r4/bootstrap-switch.jpg differ diff --git a/board/aarch64/bananapi-bpi-r4/console-header.png b/board/aarch64/bananapi-bpi-r4/console-header.png new file mode 100644 index 000000000..2f2bb246e Binary files /dev/null and b/board/aarch64/bananapi-bpi-r4/console-header.png differ diff --git a/board/aarch64/bananapi-bpi-r4/dts/Makefile b/board/aarch64/bananapi-bpi-r4/dts/Makefile new file mode 100644 index 000000000..a3cd484c7 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/dts/Makefile @@ -0,0 +1,2 @@ +dtb-y += infix/bananapi,bpi-r4.dtbo +dtb-y += infix/bananapi,bpi-r4-2g5.dtbo diff --git a/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4-2g5.dtso b/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4-2g5.dtso new file mode 100644 index 000000000..286553f75 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4-2g5.dtso @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4-2g5"; +}; + +/* + * On the 2g5 variant, GMAC1 uses the internal 2.5G PHY (eth1 renamed to + * "wan" by udev). The switch's port0, which is labeled "wan" in the base + * DTS, would cause a name collision when the switch driver registers it. + * Rename it to "lan0" here so the kernel names it correctly from the start. + */ +&gsw_port0 { + label = "lan0"; +}; + +/* + * The upstream mt7988a.dtsi sets compatible = "ethernet-phy-ieee802.3-c45" + * on the internal 2.5G PHY node. That gives genphy_c45 (built-in) OF-match + * priority over the PHY-ID-based mtk-2p5ge driver, leaving the PHY powered + * down and unclaimed. Replace it with the standard ethernet-phy-idXXXX.XXXX + * form so of_get_phy_id() registers the PHY as C22 with explicit ID 0x00339c11. + * mtk-2p5ge then matches via PHY_ID_MATCH_VENDOR(0x00339c00) instead of + * genphy_c45 winning via OF-match. + * Note: /delete-property/ is not used because U-Boot fdt apply does not + * implement property deletion in overlays. + */ +&int_2p5g_phy { + compatible = "ethernet-phy-id0033.9c11"; +}; diff --git a/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4.dtso b/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4.dtso new file mode 100644 index 000000000..7ea10d03b --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/dts/infix/bananapi,bpi-r4.dtso @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/dts-v1/; +/plugin/; + +/ { + compatible = "bananapi,bpi-r4", "mediatek,mt7988a"; +}; + +/* + * The upstream mt7988a-bananapi-bpi-r4.dtsi sets stdout-path = "serial0:..." + * but the aliases node there only has ethernet entries. Linux resolves + * stdout-path by looking in /aliases, so we must add serial0 here. + * Path references in overlay aliases cannot use &label, so use the full path. + */ +&{/} { + aliases { + serial0 = "/soc/serial@11000000"; + }; + + chosen { + infix { + /* Default admin user password: 'admin' */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + usb-ports = <&ssusb1>; + usb-port-names = "USB"; + }; + }; +}; diff --git a/board/aarch64/bananapi-bpi-r4/genimage.cfg.in b/board/aarch64/bananapi-bpi-r4/genimage.cfg.in new file mode 100644 index 000000000..51bda51da --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/genimage.cfg.in @@ -0,0 +1,81 @@ +image cfg.ext4 { + empty = true + temporary = true + size = 128M + ext4 { + label = "cfg" + use-mke2fs = true + features = "uninit_bg" + extraargs = "-m 0 -i 4096" + } +} + +# The /var partition will be expanded automatically at first boot +# to use the full size of the SD-card or eMMC media. +image var.ext4 { + empty = true + temporary = true + size = 128M + ext4 { + label = "var" + use-mke2fs = true + features = "uninit_bg" + extraargs = "-m 0 -i 4096" + } +} + +image #INFIX_ID##VERSION#-bpi-r4-#TARGET#.img { + hdimage { + partition-table-type = "gpt" + gpt-no-backup = true + } + # BL2 bootloader partition (MediaTek official location) + partition bl2 { + image = "bl2.img" + offset = 1024s # 0x80000 = sector 1024 + size = 4M # 0x400000 + bootable = true + } + + # Factory/calibration data (sectors 9216-13311) + partition factory { + offset = 4608K # 0x480000 + size = 2M # 0x200000 + } + + # FIP partition - BL31 + U-Boot (sectors 13312-17407) + partition fip { + image = "fip.bin" + offset = 13312s + size = 4096s + } + + partition aux { + partition-uuid = D4EF35A0-0652-45A1-B3DE-D63339C82035 + image = "aux.ext4" + } + + partition primary { + partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 + bootable = true + size = 250M + image = "rootfs.squashfs" + } + + partition secondary { + partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 + bootable = true + size = 250M + image = "rootfs.squashfs" + } + + partition cfg { + partition-uuid = 7aa497f0-73b5-47e5-b2ab-8752d8a48105 + image = "cfg.ext4" + } + + partition var { + partition-uuid = 8046A06A-E45A-4A14-A6AD-6684704A393F + image = "var.ext4" + } +} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-emmc-syslinux.conf b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-emmc-syslinux.conf new file mode 100644 index 000000000..f74dc1094 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-emmc-syslinux.conf @@ -0,0 +1,5 @@ +label Infix (aarch64) + kernel /boot/Image + fdtdir /boot + fdtoverlays /boot/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtbo /boot/infix/bananapi,bpi-r4.dtbo /boot/infix/bananapi,bpi-r4-2g5.dtbo + append ${bootargs_root} ${bootargs_log} usbcore.authorized_default=2 -- ${bootargs_user} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-sdmmc-syslinux.conf b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-sdmmc-syslinux.conf new file mode 100644 index 000000000..4d198362d --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-2g5-sdmmc-syslinux.conf @@ -0,0 +1,5 @@ +label Infix (aarch64) + kernel /boot/Image + fdtdir /boot + fdtoverlays /boot/mediatek/mt7988a-bananapi-bpi-r4-sd.dtbo /boot/infix/bananapi,bpi-r4.dtbo /boot/infix/bananapi,bpi-r4-2g5.dtbo + append ${bootargs_root} ${bootargs_log} usbcore.authorized_default=2 -- ${bootargs_user} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-emmc-syslinux.conf b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-emmc-syslinux.conf new file mode 100644 index 000000000..079c9a262 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-emmc-syslinux.conf @@ -0,0 +1,5 @@ +label Infix (aarch64) + kernel /boot/Image + fdtdir /boot + fdtoverlays /boot/mediatek/mt7988a-bananapi-bpi-r4-emmc.dtbo /boot/infix/bananapi,bpi-r4.dtbo + append ${bootargs_root} ${bootargs_log} usbcore.authorized_default=2 -- ${bootargs_user} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-sdmmc-syslinux.conf b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-sdmmc-syslinux.conf new file mode 100644 index 000000000..b3734a23d --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/boot/syslinux/bananapi,bpi-r4-sdmmc-syslinux.conf @@ -0,0 +1,5 @@ +label Infix (aarch64) + kernel /boot/Image + fdtdir /boot + fdtoverlays /boot/mediatek/mt7988a-bananapi-bpi-r4-sd.dtbo /boot/infix/bananapi,bpi-r4.dtbo + append ${bootargs_root} ${bootargs_log} usbcore.authorized_default=2 -- ${bootargs_user} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/factory-config.cfg b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/factory-config.cfg new file mode 100644 index 000000000..5571d3200 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/factory-config.cfg @@ -0,0 +1,404 @@ +{ + "ieee802-dot1ab-lldp:lldp": { + "infix-lldp:enabled": true + }, + "ietf-hardware:hardware": { + "component": [ + { + "name": "USB", + "class": "infix-hardware:usb", + "state": { + "admin-state": "unlocked" + } + } + ] + }, + "ietf-interfaces:interfaces": { + "interface": [ + { + "name": "br0", + "type": "infix-if-type:bridge", + "ietf-ip:ipv4": { + "address": [ + { + "ip": "192.168.0.1", + "prefix-length": 24 + } + ] + } + }, + { + "name": "lan0", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lan1", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lan2", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lan3", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lo", + "type": "infix-if-type:loopback", + "ietf-ip:ipv4": { + "address": [ + { + "ip": "127.0.0.1", + "prefix-length": 8 + } + ] + }, + "ietf-ip:ipv6": { + "address": [ + { + "ip": "::1", + "prefix-length": 128 + } + ] + } + }, + { + "name": "wan", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + { + "id": "ntp-server" + }, + { + "id": "broadcast" + }, + { + "id": "domain" + }, + { + "id": "hostname", + "value": "auto" + }, + { + "id": "dns-server" + }, + { + "id": "router" + }, + { + "id": "netmask" + }, + { + "id": "vendor-class", + "value": "Banana Pi BPI-R4" + } + ] + } + }, + "ietf-ip:ipv6": { + "infix-dhcpv6-client:dhcp": { + "option": [ + { + "id": "ntp-server" + }, + { + "id": "client-fqdn" + }, + { + "id": "domain-search" + }, + { + "id": "dns-server" + } + ] + } + } + } + ] + }, + "ietf-keystore:keystore": { + "asymmetric-keys": { + "asymmetric-key": [ + { + "name": "genkey", + "public-key-format": "infix-crypto-types:ssh-public-key-format", + "public-key": "", + "private-key-format": "infix-crypto-types:rsa-private-key-format", + "cleartext-private-key": "", + "certificates": {} + } + ] + } + }, + "ietf-netconf-acm:nacm": { + "enable-nacm": true, + "read-default": "permit", + "write-default": "permit", + "exec-default": "permit", + "groups": { + "group": [ + { + "name": "admin", + "user-name": [ + "admin" + ] + }, + { + "name": "operator", + "user-name": [] + }, + { + "name": "guest", + "user-name": [] + } + ] + }, + "rule-list": [ + { + "name": "admin-acl", + "group": [ + "admin" + ], + "rule": [ + { + "name": "permit-all", + "module-name": "*", + "access-operations": "*", + "action": "permit", + "comment": "Allow 'admin' group complete access to all operations and data." + } + ] + }, + { + "name": "operator-acl", + "group": [ + "operator" + ], + "rule": [ + { + "name": "permit-system-rpcs", + "module-name": "ietf-system", + "rpc-name": "*", + "access-operations": "exec", + "action": "permit", + "comment": "Operators can reboot, shutdown, and set system time." + } + ] + }, + { + "name": "guest-acl", + "group": [ + "guest" + ], + "rule": [ + { + "name": "deny-all-write+exec", + "module-name": "*", + "access-operations": "create update delete exec", + "action": "deny", + "comment": "Guests cannot change anything or exec rpcs." + } + ] + }, + { + "name": "default-deny-all", + "group": [ + "*" + ], + "rule": [ + { + "name": "deny-password-access", + "path": "/ietf-system:system/authentication/user/password", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access password hashes." + }, + { + "name": "deny-keystore-access", + "module-name": "ietf-keystore", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access cryptographic keys." + }, + { + "name": "deny-truststore-access", + "module-name": "ietf-truststore", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access trust store." + } + ] + } + ] + }, + "ietf-netconf-server:netconf-server": { + "listen": { + "endpoints": { + "endpoint": [ + { + "name": "default-ssh", + "ssh": { + "tcp-server-parameters": { + "local-bind": [ + { + "local-address": "::" + } + ] + }, + "ssh-server-parameters": { + "server-identity": { + "host-key": [ + { + "name": "default-key", + "public-key": { + "central-keystore-reference": "genkey" + } + } + ] + } + } + } + } + ] + } + } + }, + "ietf-system:system": { + "hostname": "bpi-%m", + "ntp": { + "server": [ + { + "name": "default", + "udp": { + "address": "pool.ntp.org" + } + } + ] + }, + "authentication": { + "user": [ + { + "name": "admin", + "password": "$factory$", + "infix-system:shell": "bash" + } + ] + }, + "infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo=" + }, + "infix-dhcp-server:dhcp-server": { + "option": [ + { + "id": "ntp-server", + "address": "auto" + }, + { + "id": "dns-server", + "address": "auto" + }, + { + "id": "router", + "address": "auto" + } + ], + "subnet": [ + { + "subnet": "192.168.0.0/24", + "pool": { + "start-address": "192.168.0.100", + "end-address": "192.168.0.250" + } + } + ] + }, + "infix-firewall:firewall": { + "default": "wan", + "zone": [ + { + "name": "lan", + "action": "accept", + "interface": [ + "br0" + ] + }, + { + "name": "wan", + "action": "drop", + "interface": [ + "wan" + ], + "service": [ + "dhcpv6-client" + ] + } + ], + "policy": [ + { + "name": "lan-to-wan", + "action": "accept", + "ingress": [ + "lan" + ], + "egress": [ + "wan" + ], + "masquerade": true + } + ] + }, + "infix-meta:meta": { + "version": "1.7" + }, + "infix-services:mdns": { + "enabled": true + }, + "infix-services:ssh": { + "enabled": true, + "hostkey": [ + "genkey" + ], + "listen": [ + { + "name": "ipv4", + "address": "0.0.0.0", + "port": 22 + }, + { + "name": "ipv6", + "address": "::", + "port": 22 + } + ] + }, + "infix-services:web": { + "enabled": true, + "console": { + "enabled": true + }, + "netbrowse": { + "enabled": true + }, + "restconf": { + "enabled": true + } + } +} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/60-mtk-2p5ge-phy.rules b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/60-mtk-2p5ge-phy.rules new file mode 100644 index 000000000..e4ec55b32 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/60-mtk-2p5ge-phy.rules @@ -0,0 +1,5 @@ +# The mtk-2p5ge PHY driver uses MDIO PHY ID matching, not OF compatible +# matching. udev auto-loading is based on MODALIAS, which for DT-described +# devices is "of:N...C" — a format that never matches the driver's +# "mdio:..." module alias. Match on OF_COMPATIBLE_0 explicitly instead. +ACTION=="add", SUBSYSTEM=="mdio_bus", ENV{OF_COMPATIBLE_0}=="ethernet-phy-id0033.9c11", RUN+="/sbin/modprobe -b mtk-2p5ge" diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules new file mode 100644 index 000000000..20d58c4bd --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4-2g5/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules @@ -0,0 +1,2 @@ +ACTION=="add", SUBSYSTEM=="net", DEVPATH=="/devices/platform/soc/15100000.ethernet/net/eth1", NAME="wan" +ACTION=="add", SUBSYSTEM=="net", DEVPATH=="/devices/platform/soc/15100000.ethernet/net/eth2", NAME="sfp1" diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/factory-config.cfg b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/factory-config.cfg new file mode 100644 index 000000000..13a22c9ba --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/factory-config.cfg @@ -0,0 +1,396 @@ +{ + "ieee802-dot1ab-lldp:lldp": { + "infix-lldp:enabled": true + }, + "ietf-hardware:hardware": { + "component": [ + { + "name": "USB", + "class": "infix-hardware:usb", + "state": { + "admin-state": "unlocked" + } + } + ] + }, + "ietf-interfaces:interfaces": { + "interface": [ + { + "name": "br0", + "type": "infix-if-type:bridge", + "ietf-ip:ipv4": { + "address": [ + { + "ip": "192.168.0.1", + "prefix-length": 24 + } + ] + } + }, + { + "name": "lan1", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lan2", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lan3", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv6": {}, + "infix-interfaces:bridge-port": { + "bridge": "br0" + } + }, + { + "name": "lo", + "type": "infix-if-type:loopback", + "ietf-ip:ipv4": { + "address": [ + { + "ip": "127.0.0.1", + "prefix-length": 8 + } + ] + }, + "ietf-ip:ipv6": { + "address": [ + { + "ip": "::1", + "prefix-length": 128 + } + ] + } + }, + { + "name": "wan", + "type": "infix-if-type:ethernet", + "ietf-ip:ipv4": { + "infix-dhcp-client:dhcp": { + "option": [ + { + "id": "ntp-server" + }, + { + "id": "broadcast" + }, + { + "id": "domain" + }, + { + "id": "hostname", + "value": "auto" + }, + { + "id": "dns-server" + }, + { + "id": "router" + }, + { + "id": "netmask" + }, + { + "id": "vendor-class", + "value": "Banana Pi BPI-R4" + } + ] + } + }, + "ietf-ip:ipv6": { + "infix-dhcpv6-client:dhcp": { + "option": [ + { + "id": "ntp-server" + }, + { + "id": "client-fqdn" + }, + { + "id": "domain-search" + }, + { + "id": "dns-server" + } + ] + } + } + } + ] + }, + "ietf-keystore:keystore": { + "asymmetric-keys": { + "asymmetric-key": [ + { + "name": "genkey", + "public-key-format": "infix-crypto-types:ssh-public-key-format", + "public-key": "", + "private-key-format": "infix-crypto-types:rsa-private-key-format", + "cleartext-private-key": "", + "certificates": {} + } + ] + } + }, + "ietf-netconf-acm:nacm": { + "enable-nacm": true, + "read-default": "permit", + "write-default": "permit", + "exec-default": "permit", + "groups": { + "group": [ + { + "name": "admin", + "user-name": [ + "admin" + ] + }, + { + "name": "operator", + "user-name": [] + }, + { + "name": "guest", + "user-name": [] + } + ] + }, + "rule-list": [ + { + "name": "admin-acl", + "group": [ + "admin" + ], + "rule": [ + { + "name": "permit-all", + "module-name": "*", + "access-operations": "*", + "action": "permit", + "comment": "Allow 'admin' group complete access to all operations and data." + } + ] + }, + { + "name": "operator-acl", + "group": [ + "operator" + ], + "rule": [ + { + "name": "permit-system-rpcs", + "module-name": "ietf-system", + "rpc-name": "*", + "access-operations": "exec", + "action": "permit", + "comment": "Operators can reboot, shutdown, and set system time." + } + ] + }, + { + "name": "guest-acl", + "group": [ + "guest" + ], + "rule": [ + { + "name": "deny-all-write+exec", + "module-name": "*", + "access-operations": "create update delete exec", + "action": "deny", + "comment": "Guests cannot change anything or exec rpcs." + } + ] + }, + { + "name": "default-deny-all", + "group": [ + "*" + ], + "rule": [ + { + "name": "deny-password-access", + "path": "/ietf-system:system/authentication/user/password", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access password hashes." + }, + { + "name": "deny-keystore-access", + "module-name": "ietf-keystore", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access cryptographic keys." + }, + { + "name": "deny-truststore-access", + "module-name": "ietf-truststore", + "access-operations": "*", + "action": "deny", + "comment": "No user except admins can access trust store." + } + ] + } + ] + }, + "ietf-netconf-server:netconf-server": { + "listen": { + "endpoints": { + "endpoint": [ + { + "name": "default-ssh", + "ssh": { + "tcp-server-parameters": { + "local-bind": [ + { + "local-address": "::" + } + ] + }, + "ssh-server-parameters": { + "server-identity": { + "host-key": [ + { + "name": "default-key", + "public-key": { + "central-keystore-reference": "genkey" + } + } + ] + } + } + } + } + ] + } + } + }, + "ietf-system:system": { + "hostname": "bpi-%m", + "ntp": { + "server": [ + { + "name": "default", + "udp": { + "address": "pool.ntp.org" + } + } + ] + }, + "authentication": { + "user": [ + { + "name": "admin", + "password": "$factory$", + "infix-system:shell": "bash" + } + ] + }, + "infix-system:motd-banner": "Li0tLS0tLS0uCnwgIC4gLiAgfCBJbmZpeCBPUyDigJQgSW1tdXRhYmxlLkZyaWVuZGx5LlNlY3VyZQp8LS4gdiAuLXwgaHR0cHM6Ly9rZXJuZWxraXQub3JnCictJy0tLSctJwo=" + }, + "infix-dhcp-server:dhcp-server": { + "option": [ + { + "id": "ntp-server", + "address": "auto" + }, + { + "id": "dns-server", + "address": "auto" + }, + { + "id": "router", + "address": "auto" + } + ], + "subnet": [ + { + "subnet": "192.168.0.0/24", + "pool": { + "start-address": "192.168.0.100", + "end-address": "192.168.0.250" + } + } + ] + }, + "infix-firewall:firewall": { + "default": "wan", + "zone": [ + { + "name": "lan", + "action": "accept", + "interface": [ + "br0" + ] + }, + { + "name": "wan", + "action": "drop", + "interface": [ + "wan" + ], + "service": [ + "dhcpv6-client" + ] + } + ], + "policy": [ + { + "name": "lan-to-wan", + "action": "accept", + "ingress": [ + "lan" + ], + "egress": [ + "wan" + ], + "masquerade": true + } + ] + }, + "infix-meta:meta": { + "version": "1.7" + }, + "infix-services:mdns": { + "enabled": true + }, + "infix-services:ssh": { + "enabled": true, + "hostkey": [ + "genkey" + ], + "listen": [ + { + "name": "ipv4", + "address": "0.0.0.0", + "port": 22 + }, + { + "name": "ipv6", + "address": "::", + "port": 22 + } + ] + }, + "infix-services:web": { + "enabled": true, + "console": { + "enabled": true + }, + "netbrowse": { + "enabled": true + }, + "restconf": { + "enabled": true + } + } +} diff --git a/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules new file mode 100644 index 000000000..33a17bea8 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/rootfs/usr/share/product/bananapi,bpi-r4/etc/udev/rules.d/90-bpi-r4-rename-ifaces.rules @@ -0,0 +1,2 @@ +ACTION=="add", SUBSYSTEM=="net", DEVPATH=="/devices/platform/soc/15100000.ethernet/net/eth1", NAME="sfp2" +ACTION=="add", SUBSYSTEM=="net", DEVPATH=="/devices/platform/soc/15100000.ethernet/net/eth2", NAME="sfp1" diff --git a/board/aarch64/bananapi-bpi-r4/uboot/emmc-extras.config b/board/aarch64/bananapi-bpi-r4/uboot/emmc-extras.config new file mode 100644 index 000000000..89aa7e09f --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/emmc-extras.config @@ -0,0 +1 @@ +CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi mt7988-emmc-env.dtsi" diff --git a/board/aarch64/bananapi-bpi-r4/uboot/extras.config b/board/aarch64/bananapi-bpi-r4/uboot/extras.config new file mode 100644 index 000000000..bf7d6676c --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/extras.config @@ -0,0 +1,40 @@ +CONFIG_AUTOBOOT=y +CONFIG_BOOTDELAY=2 +# CONFIG_MMC_PCI is not set +CONFIG_ENV_IS_NOWHERE=y +# CONFIG_ENV_IS_IN_MMC is not set +CONFIG_MULTI_DTB_FIT=y +CONFIG_OF_LIST="mt7988a-bananapi-bpi-r4 mt7988a-bananapi-bpi-r4-2g5" + +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_MTU3=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y + +CONFIG_MTK_SPIM=y +CONFIG_SPI=y +CONFIG_DM_SPI=y +CONFIG_SPI_FLASH=y +CONFIG_DM_SPI_FLASH=y +CONFIG_SPI_FLASH_MTD=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_MTD=y +CONFIG_DM_MTD=y +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_SPI_NAND=y +CONFIG_MTK_SPIM=y +CONFIG_MTK_SNOR=y + +CONFIG_BUTTON=y +CONFIG_BUTTON_CMD=y +CONFIG_BUTTON_GPIO=y + +CONFIG_CMD_SF=y +CONFIG_CMD_USB=y +CONFIG_CMD_MTD=y +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_DM=y diff --git a/board/aarch64/bananapi-bpi-r4/uboot/mt7988-emmc-env.dtsi b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-emmc-env.dtsi new file mode 100644 index 000000000..4b2946a22 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-emmc-env.dtsi @@ -0,0 +1,7 @@ +#include + +&env { + fdtfile = "mediatek/mt7988a-bananapi-bpi-r4.dtb"; + board = "bananapi,bpi-r4-emmc"; + ixvariant = "if test \"${BOARD_VARIANT}\" = \"2g5\"; then setenv fdtfile mediatek/mt7988a-bananapi-bpi-r4-2g5.dtb; setenv board bananapi,bpi-r4-2g5-emmc; fi"; +}; diff --git a/board/aarch64/bananapi-bpi-r4/uboot/mt7988-env.dtsi b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-env.dtsi new file mode 100644 index 000000000..b3ffc7c44 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-env.dtsi @@ -0,0 +1,27 @@ +/ { + config { + env: environment { + bootcmd = "run ixboot"; + boot_targets = "mmc0"; + ethprime = "eth0"; + fdt_addr_r = "0x43f00000"; + kernel_addr_r = "0x44000000"; + fdtoverlay_addr_r = "0x47f00000"; + scriptaddr = "0x48000000"; + ramdisk_addr_r = "0x4A000000"; + + /* + * Apply BOARD_VARIANT from aux uboot.env. + * Infix writes BOARD_VARIANT=2g5 via fw_setenv on + * BPI-R4-2g5 / BPI-R4P boards to select the correct + * device tree. Unset = standard R4 (2x SFP+). + */ + ixvariant = "if test \"${BOARD_VARIANT}\" = \"2g5\"; then setenv fdtfile mediatek/mt7988a-bananapi-bpi-r4-2g5.dtb; fi"; + + /* This is a development platform, keep + * developer mode statically enabled. + */ + ixbtn-devmode = "setenv dev_mode yes; echo Enabled"; + }; + }; +}; diff --git a/board/aarch64/bananapi-bpi-r4/uboot/mt7988-sd-env.dtsi b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-sd-env.dtsi new file mode 100644 index 000000000..214e67b0e --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/mt7988-sd-env.dtsi @@ -0,0 +1,7 @@ +#include + +&env { + fdtfile = "mediatek/mt7988a-bananapi-bpi-r4.dtb"; + board = "bananapi,bpi-r4-sdmmc"; + ixvariant = "if test \"${BOARD_VARIANT}\" = \"2g5\"; then setenv fdtfile mediatek/mt7988a-bananapi-bpi-r4-2g5.dtb; setenv board bananapi,bpi-r4-2g5-sdmmc; fi"; +}; diff --git a/board/aarch64/bananapi-bpi-r4/uboot/sd-extras.config b/board/aarch64/bananapi-bpi-r4/uboot/sd-extras.config new file mode 100644 index 000000000..58e915f13 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r4/uboot/sd-extras.config @@ -0,0 +1,2 @@ +CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi mt7988-sd-env.dtsi" +CONFIG_OF_LIST="mt7988a-bananapi-bpi-r4-sd" diff --git a/board/aarch64/bananapi-bpi-r64/README.md b/board/aarch64/bananapi-bpi-r64/README.md index 9db6728b1..e4b1ee42d 100644 --- a/board/aarch64/bananapi-bpi-r64/README.md +++ b/board/aarch64/bananapi-bpi-r64/README.md @@ -30,20 +30,15 @@ Infix comes preconfigured with: SW1 Boot Switch -The BPI-R64 uses a 2-position DIP switch (SW1) to select the boot device -order. The MT7622 Boot ROM tries devices in the order listed and falls -back to the next if no valid BL2 is found at the expected location. +The BPI-R64 has a 2-position DIP switch (SW1) for selecting the boot device. +The MT7622 Boot ROM always tries SD first if a card is present, so you can +leave SW1 in the OFF (eMMC) position and simply insert or remove an SD card +to control boot device selection. -| SW1 | Boot device | Use case | -|-----|-------------|----------------------------| -| OFF | eMMC | Production eMMC boot | -| ON | SD card | SD card boot / development | - -> [!NOTE] -> SinoVoip has exposed only one bit of the MT7622's two-bit `BOOT_SEL[1:0]` -> strapping field via SW1, with `BOOT_SEL[1]` hardwired high. This limits the -> board to eMMC (`10b`) and SD (`11b`) boot; the SPI-NOR and SPI-NAND modes -> available on the MT7622 reference board (`00b`, `01b`) are not selectable. +| SW1 | Boot device | +|-----|-------------| +| OFF | eMMC | +| ON | SD card | ## Getting Started @@ -58,11 +53,10 @@ back to the next if no valid BL2 is found at the expected location. dd if=infix-*-bpi-r64-sdcard.img of=/dev/sdX bs=4M status=progress ``` -2. **Set boot switch:** SW1 ON (SD card boot) -3. **Insert SD card and power on** -4. **Connect console:** 115200 8N1 — use the dedicated Debug UART header +2. **Insert SD card and power on** +3. **Connect console:** 115200 8N1 — use the dedicated Debug UART header just below the 40-pin GPIO header; pins are labeled GND, RX, TX on the board -5. **Default login:** `admin` / `admin` +4. **Default login:** `admin` / `admin` ## Installing to eMMC @@ -84,9 +78,8 @@ drive. #### Step 1: Boot from SD card -1. Set SW1 to ON (SD boot) -2. Insert SD card with Infix -3. Power on and break into U-Boot (press Ctrl-C during boot) +1. Insert SD card with Infix +2. Power on and break into U-Boot (press Ctrl-C during boot) #### Step 2: Write the eMMC image from U-Boot @@ -115,9 +108,8 @@ mmc partconf 0 1 1 0 #### Step 4: Boot from eMMC 1. Power off the board -2. Set SW1 to OFF (eMMC boot) -3. Remove SD card and USB drive -4. Power on +2. Remove SD card and USB drive +3. Power on ## Platform Notes diff --git a/board/aarch64/bananapi-bpi-r64/bananapi-bpi-r64.hash b/board/aarch64/bananapi-bpi-r64/bananapi-bpi-r64.hash new file mode 100644 index 000000000..2b1e74432 --- /dev/null +++ b/board/aarch64/bananapi-bpi-r64/bananapi-bpi-r64.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d48246c717b505cc11df95171f2fd548b389e1a463f1af4c68d0b69fe0d1009b LICENSE diff --git a/board/aarch64/bananapi-bpi-r64/uboot/emmc-extras.config b/board/aarch64/bananapi-bpi-r64/uboot/emmc-extras.config index 9dff8112a..896f66474 100644 --- a/board/aarch64/bananapi-bpi-r64/uboot/emmc-extras.config +++ b/board/aarch64/bananapi-bpi-r64/uboot/emmc-extras.config @@ -1,2 +1,3 @@ CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi mt7622-emmc-env.dtsi" CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_CMD_MMC_PARTCONF=y diff --git a/board/aarch64/bananapi-bpi-r64/uboot/sd-extras.config b/board/aarch64/bananapi-bpi-r64/uboot/sd-extras.config index 9502bd1d1..dc1466de0 100644 --- a/board/aarch64/bananapi-bpi-r64/uboot/sd-extras.config +++ b/board/aarch64/bananapi-bpi-r64/uboot/sd-extras.config @@ -1 +1,3 @@ CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi mt7622-sd-env.dtsi" +CONFIG_SUPPORT_EMMC_BOOT=y +CONFIG_CMD_MMC_PARTCONF=y diff --git a/board/aarch64/freescale-imx8mp-evk/freescale-imx8mp-evk.hash b/board/aarch64/freescale-imx8mp-evk/freescale-imx8mp-evk.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/freescale-imx8mp-evk/freescale-imx8mp-evk.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/aarch64/friendlyarm-nanopi-r2s/friendlyarm-nanopi-r2s.hash b/board/aarch64/friendlyarm-nanopi-r2s/friendlyarm-nanopi-r2s.hash new file mode 100644 index 000000000..d1a69bc36 --- /dev/null +++ b/board/aarch64/friendlyarm-nanopi-r2s/friendlyarm-nanopi-r2s.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 dbe4eae8debbba8135297e15f24aeefef0b4c03781f3f9328db4398d58a728b3 LICENSE diff --git a/board/aarch64/marvell-cn9130-crb/marvell-cn9130-crb.hash b/board/aarch64/marvell-cn9130-crb/marvell-cn9130-crb.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/marvell-cn9130-crb/marvell-cn9130-crb.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/aarch64/marvell-espressobin/marvell-espressobin.hash b/board/aarch64/marvell-espressobin/marvell-espressobin.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/marvell-espressobin/marvell-espressobin.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/aarch64/microchip-sparx5-pcb135/microchip-sparx5-pcb135.hash b/board/aarch64/microchip-sparx5-pcb135/microchip-sparx5-pcb135.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/microchip-sparx5-pcb135/microchip-sparx5-pcb135.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/aarch64/raspberrypi-rpi64/raspberrypi-rpi64.hash b/board/aarch64/raspberrypi-rpi64/raspberrypi-rpi64.hash new file mode 100644 index 000000000..d1a69bc36 --- /dev/null +++ b/board/aarch64/raspberrypi-rpi64/raspberrypi-rpi64.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 dbe4eae8debbba8135297e15f24aeefef0b4c03781f3f9328db4398d58a728b3 LICENSE diff --git a/board/aarch64/styx-dcp-sc-28p/styx-dcp-sc-28p.hash b/board/aarch64/styx-dcp-sc-28p/styx-dcp-sc-28p.hash new file mode 100644 index 000000000..2809a5eed --- /dev/null +++ b/board/aarch64/styx-dcp-sc-28p/styx-dcp-sc-28p.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE diff --git a/board/arm/microchip-sama7g54-ek/microchip-sama7g54-ek.hash b/board/arm/microchip-sama7g54-ek/microchip-sama7g54-ek.hash new file mode 100644 index 000000000..2b1e74432 --- /dev/null +++ b/board/arm/microchip-sama7g54-ek/microchip-sama7g54-ek.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d48246c717b505cc11df95171f2fd548b389e1a463f1af4c68d0b69fe0d1009b LICENSE diff --git a/board/arm/raspberrypi-rpi2/raspberrypi-rpi2.hash b/board/arm/raspberrypi-rpi2/raspberrypi-rpi2.hash new file mode 100644 index 000000000..d1a69bc36 --- /dev/null +++ b/board/arm/raspberrypi-rpi2/raspberrypi-rpi2.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 dbe4eae8debbba8135297e15f24aeefef0b4c03781f3f9328db4398d58a728b3 LICENSE diff --git a/board/common/uboot/env.dtsi b/board/common/uboot/env.dtsi index 750e83114..f484b5174 100644 --- a/board/common/uboot/env.dtsi +++ b/board/common/uboot/env.dtsi @@ -14,6 +14,7 @@ boot_targets = "virtio mmc"; bootcmd = "run ixboot"; + ixvariant = ""; ixpreboot = /incbin/("scripts/ixpreboot.sh"); ixbtn-devmode = /incbin/("scripts/ixbtn-devmode.sh"); ixbtn-factory = /incbin/("scripts/ixbtn-factory.sh"); diff --git a/board/common/uboot/scripts/ixpreboot.sh b/board/common/uboot/scripts/ixpreboot.sh index 71eb9f935..bfe61a899 100644 --- a/board/common/uboot/scripts/ixpreboot.sh +++ b/board/common/uboot/scripts/ixpreboot.sh @@ -33,7 +33,8 @@ for tgt in "${boot_targets}"; do setexpr ixmenu_n ${ixmenu_n} + 1 if load ${devtype} ${devnum}:${auxpart} ${loadaddr} /uboot.env; then - env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG ethact + env import -b ${loadaddr} ${filesize} BOOT_ORDER DEBUG ethact BOARD_VARIANT + run ixvariant fi if test -n "${DEBUG}"; then diff --git a/board/dtb-inst.makefile b/board/dtb-inst.makefile index 62b0f0595..60590e066 100644 --- a/board/dtb-inst.makefile +++ b/board/dtb-inst.makefile @@ -6,4 +6,8 @@ $(DESTDIR)/boot/%.dtb: %.dtb @echo " DTB-INSTALL $<" @install -D $< $@ +$(DESTDIR)/boot/%.dtbo: %.dtbo + @echo " DTBO-INSTALL $<" + @install -D $< $@ + .PHONY: install diff --git a/buildroot b/buildroot index 79bfb2231..362f1511b 160000 --- a/buildroot +++ b/buildroot @@ -1 +1 @@ -Subproject commit 79bfb2231d12d7528288a24839c4e9793ac3f733 +Subproject commit 362f1511ba061bd710b159f21993db96e49dbdff diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig index ccf13f122..f19df0578 100644 --- a/configs/aarch64_defconfig +++ b/configs/aarch64_defconfig @@ -134,6 +134,7 @@ BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y BR2_PACKAGE_ALDER_ALDER=y BR2_PACKAGE_BANANAPI_BPI_R3=y +BR2_PACKAGE_BANANAPI_BPI_R4=y BR2_PACKAGE_BANANAPI_BPI_R64=y BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y BR2_PACKAGE_MARVELL_CN9130_CRB=y diff --git a/configs/aarch64_minimal_defconfig b/configs/aarch64_minimal_defconfig index 83e8eb226..2961d48ea 100644 --- a/configs/aarch64_minimal_defconfig +++ b/configs/aarch64_minimal_defconfig @@ -113,6 +113,7 @@ BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y BR2_PACKAGE_ALDER_ALDER=y BR2_PACKAGE_BANANAPI_BPI_R3=y +BR2_PACKAGE_BANANAPI_BPI_R4=y BR2_PACKAGE_BANANAPI_BPI_R64=y BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y BR2_PACKAGE_MARVELL_CN9130_CRB=y diff --git a/configs/bpi_r4_emmc_boot_defconfig b/configs/bpi_r4_emmc_boot_defconfig new file mode 100644 index 000000000..2ae3342aa --- /dev/null +++ b/configs/bpi_r4_emmc_boot_defconfig @@ -0,0 +1,42 @@ +BR2_aarch64=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y +BR2_DL_DIR="$(BR2_EXTERNAL_INFIX_PATH)/dl" +BR2_CCACHE=y +BR2_CCACHE_DIR="$(BR2_EXTERNAL_INFIX_PATH)/.ccache" +BR2_ENABLE_DEBUG=y +BR2_PACKAGE_OVERRIDE_FILE="$(BR2_EXTERNAL_INFIX_PATH)/local.mk" +BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_INFIX_PATH)/patches" +BR2_SSP_NONE=y +BR2_INIT_NONE=y +BR2_SYSTEM_BIN_SH_NONE=y +# BR2_PACKAGE_BUSYBOX is not set +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +# BR2_TARGET_ROOTFS_TAR is not set +BR2_TARGET_ARM_TRUSTED_FIRMWARE=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_GIT=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_URL="https://github.com/mtk-openwrt/arm-trusted-firmware-mtk.git" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_VERSION="e06f258664198a901ff1c7c0c87802a115179451" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_PLATFORM="mt7988" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_FIP=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_UBOOT_AS_BL33=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_ADDITIONAL_VARIABLES="BOOT_DEVICE=emmc DRAM_USE_COMB=1 DDR4_4BG_MODE=1 BOARD_BGA=1 HAVE_DRAM_OBJ_FILE=yes USE_MKIMAGE=1 MKIMAGE=$(HOST_DIR)/bin/mkimage" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_IMAGES="*.img *.bin" +BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y +BR2_TARGET_UBOOT_CUSTOM_VERSION=y +BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2026.01" +BR2_TARGET_UBOOT_BOARD_DEFCONFIG="mt7988a_bpir4" +BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/emmc-extras.config" +BR2_TARGET_UBOOT_NEEDS_DTC=y +BR2_TARGET_UBOOT_FORMAT_DTB=y +BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/*.dtsi" +BR2_PACKAGE_HOST_BMAP_TOOLS=y +BR2_PACKAGE_HOST_GENIMAGE=y +BR2_PACKAGE_HOST_RAUC=y +BR2_PACKAGE_HOST_UBOOT_TOOLS=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y +TRUSTED_KEYS=y +TRUSTED_KEYS_DEVELOPMENT=y diff --git a/configs/bpi_r4_sd_boot_defconfig b/configs/bpi_r4_sd_boot_defconfig new file mode 100644 index 000000000..9f2a63e96 --- /dev/null +++ b/configs/bpi_r4_sd_boot_defconfig @@ -0,0 +1,42 @@ +BR2_aarch64=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y +BR2_DL_DIR="$(BR2_EXTERNAL_INFIX_PATH)/dl" +BR2_CCACHE=y +BR2_CCACHE_DIR="$(BR2_EXTERNAL_INFIX_PATH)/.ccache" +BR2_ENABLE_DEBUG=y +BR2_PACKAGE_OVERRIDE_FILE="$(BR2_EXTERNAL_INFIX_PATH)/local.mk" +BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_INFIX_PATH)/patches" +BR2_SSP_NONE=y +BR2_INIT_NONE=y +BR2_SYSTEM_BIN_SH_NONE=y +# BR2_PACKAGE_BUSYBOX is not set +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +# BR2_TARGET_ROOTFS_TAR is not set +BR2_TARGET_ARM_TRUSTED_FIRMWARE=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_GIT=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_URL="https://github.com/mtk-openwrt/arm-trusted-firmware-mtk.git" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_VERSION="e06f258664198a901ff1c7c0c87802a115179451" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_PLATFORM="mt7988" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_FIP=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_UBOOT_AS_BL33=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_ADDITIONAL_VARIABLES="BOOT_DEVICE=sdmmc DRAM_USE_COMB=1 DDR4_4BG_MODE=1 BOARD_BGA=1 HAVE_DRAM_OBJ_FILE=yes USE_MKIMAGE=1 MKIMAGE=$(HOST_DIR)/bin/mkimage" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_IMAGES="*.img *.bin" +BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y +BR2_TARGET_UBOOT_CUSTOM_VERSION=y +BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2026.01" +BR2_TARGET_UBOOT_BOARD_DEFCONFIG="mt7988a_bpir4_sd" +BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/sd-extras.config" +BR2_TARGET_UBOOT_NEEDS_DTC=y +BR2_TARGET_UBOOT_FORMAT_DTB=y +BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/bananapi-bpi-r4/uboot/*.dtsi" +BR2_PACKAGE_HOST_BMAP_TOOLS=y +BR2_PACKAGE_HOST_GENIMAGE=y +BR2_PACKAGE_HOST_RAUC=y +BR2_PACKAGE_HOST_UBOOT_TOOLS=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y +TRUSTED_KEYS=y +TRUSTED_KEYS_DEVELOPMENT=y diff --git a/configs/sama7g54_ek_emmc_boot_defconfig b/configs/sama7g54_ek_emmc_boot_defconfig index 8fefffd1b..5c76540cc 100644 --- a/configs/sama7g54_ek_emmc_boot_defconfig +++ b/configs/sama7g54_ek_emmc_boot_defconfig @@ -20,6 +20,7 @@ BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_TARBALL=y BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_TARBALL_LOCATION="$(call github,linux4sam,at91bootstrap,v4.0.9)/at91bootstrap-v4.0.9.tar.gz" BR2_TARGET_AT91BOOTSTRAP3_DEFCONFIG="sama7g5ekemmc_uboot" BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y BR2_TARGET_UBOOT_CUSTOM_VERSION=y BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2025.01" BR2_TARGET_UBOOT_BOARD_DEFCONFIG="sama7g5ek_mmc" diff --git a/configs/sama7g54_ek_sd_boot_defconfig b/configs/sama7g54_ek_sd_boot_defconfig index ddb575781..dc2f94560 100644 --- a/configs/sama7g54_ek_sd_boot_defconfig +++ b/configs/sama7g54_ek_sd_boot_defconfig @@ -20,6 +20,7 @@ BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_TARBALL=y BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_TARBALL_LOCATION="$(call github,linux4sam,at91bootstrap,v4.0.9)/at91bootstrap-v4.0.9.tar.gz" BR2_TARGET_AT91BOOTSTRAP3_DEFCONFIG="sama7g5eksd_uboot" BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y BR2_TARGET_UBOOT_CUSTOM_VERSION=y BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2025.01" BR2_TARGET_UBOOT_BOARD_DEFCONFIG="sama7g5ek_mmc1" diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index b5f7af78a..f7b69aef3 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -9,9 +9,15 @@ All notable changes to the project are documented in this file. ### Changes - Upgrade Linux kernel to 6.18.21 (LTS) +- Add support for [Banana Pi BPI-R4][BPI-R4], quad-core Cortex-A73 router with + 4x 2.5 GbE switching, dual 10 GbE SFP+. Variants BPI-R4-2g5 and BPI-R4P have + one SFP+ replaced by a 2.5 GbE RJ45, with optional PoE on the R4P ### Fixes +- N/A + +[BPI-R4]: https://docs.banana-pi.org/en/BPI-R4/BananaPi_BPI-R4 [v26.03.0][] - 2026-03-31 ------------------------- diff --git a/package/confd-test-mode/confd-test-mode.hash b/package/confd-test-mode/confd-test-mode.hash new file mode 100644 index 000000000..0b2c589c7 --- /dev/null +++ b/package/confd-test-mode/confd-test-mode.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 360336cbf0f228b12b7ca0996b33e442d97f496edcf2ec31b655e63631e7f96f LICENSE diff --git a/package/date-cpp/date.hash b/package/date-cpp/date-cpp.hash similarity index 100% rename from package/date-cpp/date.hash rename to package/date-cpp/date-cpp.hash diff --git a/package/date-cpp/date.mk b/package/date-cpp/date-cpp.mk similarity index 86% rename from package/date-cpp/date.mk rename to package/date-cpp/date-cpp.mk index c181fe33a..c6c9a104f 100644 --- a/package/date-cpp/date.mk +++ b/package/date-cpp/date-cpp.mk @@ -1,4 +1,5 @@ DATE_CPP_VERSION = 3.0.1 +DATE_CPP_SOURCE = date-$(DATE_CPP_VERSION).tar.gz DATE_CPP_SITE = $(call github,HowardHinnant,date,v$(DATE_CPP_VERSION)) DATE_CPP_INSTALL_STAGING = YES DATE_CPP_LICENSE = MIT diff --git a/package/netd/netd.hash b/package/netd/netd.hash new file mode 100644 index 000000000..9c49868ea --- /dev/null +++ b/package/netd/netd.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 2f44058572d6e56953b0928a24dc7f816f35d33fb16097e97dfcd5b000bcc140 LICENSE diff --git a/package/onieprom/onieprom.hash b/package/onieprom/onieprom.hash new file mode 100644 index 000000000..704aa616d --- /dev/null +++ b/package/onieprom/onieprom.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 ab15fd526bd8dd18a9e77ebc139656bf4d33e97fc7238cd11bf60e2b9b8666c6 COPYING diff --git a/patches/linux/6.18.21/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch b/patches/linux/6.18.21/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch new file mode 100644 index 000000000..d80ae0ae5 --- /dev/null +++ b/patches/linux/6.18.21/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch @@ -0,0 +1,189 @@ +From 8d2aec5525d60e643f85d68d62186cae530f17fc Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Sun, 5 Apr 2026 11:33:00 +0200 +Subject: [PATCH 42/47] net/pcs: add standalone PCS registration infrastructure +Organization: Wires + +Add a simple registration mechanism that allows platform PCS drivers to +register their phylink_pcs instances, and consumers (e.g. Ethernet MAC +drivers) to look them up via a DT phandle using devm_of_pcs_get(). + +When the pcs-handle property is present but the PCS device is not yet +registered, devm_of_pcs_get() returns -ENODEV to trigger deferred probe +in the consumer driver. + +Based on work by Daniel Golle . + +Signed-off-by: Joachim Wiberg +--- + drivers/net/pcs/Kconfig | 4 ++ + drivers/net/pcs/Makefile | 1 + + drivers/net/pcs/pcs-standalone.c | 95 ++++++++++++++++++++++++++++++ + include/linux/pcs/pcs-standalone.h | 26 ++++++++ + 4 files changed, 126 insertions(+) + create mode 100644 drivers/net/pcs/pcs-standalone.c + create mode 100644 include/linux/pcs/pcs-standalone.h + +diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig +index ecbc3530e780..f6b4de7f972c 100644 +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -5,6 +5,10 @@ + + menu "PCS device drivers" + ++config PCS_STANDALONE ++ tristate ++ select PHYLINK ++ + config PCS_XPCS + tristate "Synopsys DesignWare Ethernet XPCS" + select PHYLINK +diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile +index 4f7920618b90..0cb0057f2b8e 100644 +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -4,6 +4,7 @@ + pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-plat.o \ + pcs-xpcs-nxp.o pcs-xpcs-wx.o + ++obj-$(CONFIG_PCS_STANDALONE) += pcs-standalone.o + obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o + obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o +diff --git a/drivers/net/pcs/pcs-standalone.c b/drivers/net/pcs/pcs-standalone.c +new file mode 100644 +index 000000000000..f7b46de59636 +--- /dev/null ++++ b/drivers/net/pcs/pcs-standalone.c +@@ -0,0 +1,95 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Helpers for standalone PCS drivers ++ * ++ * Copyright (C) 2024 Daniel Golle ++ */ ++ ++#include ++#include ++ ++static LIST_HEAD(pcs_list); ++static DEFINE_MUTEX(pcs_mutex); ++ ++struct pcs_standalone { ++ struct device *dev; ++ struct phylink_pcs *pcs; ++ struct list_head list; ++}; ++ ++static void devm_pcs_provider_release(struct device *dev, void *res) ++{ ++ struct pcs_standalone *pcssa = (struct pcs_standalone *)res; ++ ++ mutex_lock(&pcs_mutex); ++ list_del(&pcssa->list); ++ mutex_unlock(&pcs_mutex); ++} ++ ++int devm_pcs_register(struct device *dev, struct phylink_pcs *pcs) ++{ ++ struct pcs_standalone *pcssa; ++ ++ pcssa = devres_alloc(devm_pcs_provider_release, sizeof(*pcssa), ++ GFP_KERNEL); ++ if (!pcssa) ++ return -ENOMEM; ++ ++ devres_add(dev, pcssa); ++ pcssa->pcs = pcs; ++ pcssa->dev = dev; ++ ++ mutex_lock(&pcs_mutex); ++ list_add_tail(&pcssa->list, &pcs_list); ++ mutex_unlock(&pcs_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(devm_pcs_register); ++ ++static struct pcs_standalone *of_pcs_locate(const struct device_node *_np, u32 index) ++{ ++ struct device_node *np; ++ struct pcs_standalone *iter, *pcssa = NULL; ++ ++ if (!_np) ++ return NULL; ++ ++ np = of_parse_phandle(_np, "pcs-handle", index); ++ if (!np) ++ return NULL; ++ ++ mutex_lock(&pcs_mutex); ++ list_for_each_entry(iter, &pcs_list, list) { ++ if (iter->dev->of_node != np) ++ continue; ++ ++ pcssa = iter; ++ break; ++ } ++ mutex_unlock(&pcs_mutex); ++ ++ of_node_put(np); ++ ++ return pcssa ?: ERR_PTR(-ENODEV); ++} ++ ++struct phylink_pcs *devm_of_pcs_get(struct device *dev, ++ const struct device_node *np, ++ unsigned int index) ++{ ++ struct pcs_standalone *pcssa; ++ ++ pcssa = of_pcs_locate(np ?: dev->of_node, index); ++ if (IS_ERR_OR_NULL(pcssa)) ++ return ERR_PTR(PTR_ERR(pcssa)); ++ ++ device_link_add(dev, pcssa->dev, DL_FLAG_AUTOREMOVE_CONSUMER); ++ ++ return pcssa->pcs; ++} ++EXPORT_SYMBOL_GPL(devm_of_pcs_get); ++ ++MODULE_DESCRIPTION("Helper for standalone PCS drivers"); ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/pcs/pcs-standalone.h b/include/linux/pcs/pcs-standalone.h +new file mode 100644 +index 000000000000..520835cdeee8 +--- /dev/null ++++ b/include/linux/pcs/pcs-standalone.h +@@ -0,0 +1,26 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __LINUX_PCS_STANDALONE_H ++#define __LINUX_PCS_STANDALONE_H ++ ++#include ++#include ++#include ++#include ++ ++#if IS_ENABLED(CONFIG_PCS_STANDALONE) ++int devm_pcs_register(struct device *dev, struct phylink_pcs *pcs); ++struct phylink_pcs *devm_of_pcs_get(struct device *dev, ++ const struct device_node *np, unsigned int index); ++#else ++static inline int devm_pcs_register(struct device *dev, struct phylink_pcs *pcs) ++{ ++ return -ENOTSUPP; ++} ++static inline struct phylink_pcs *devm_of_pcs_get(struct device *dev, ++ const struct device_node *np, ++ unsigned int index) ++{ ++ return ERR_PTR(-ENOTSUPP); ++} ++#endif /* CONFIG_PCS_STANDALONE */ ++#endif /* __LINUX_PCS_STANDALONE_H */ +-- +2.43.0 + diff --git a/patches/linux/6.18.21/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch b/patches/linux/6.18.21/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch new file mode 100644 index 000000000..b81370597 --- /dev/null +++ b/patches/linux/6.18.21/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch @@ -0,0 +1,465 @@ +From a11a254420cf8777497b7c027208b382c49964e7 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 6 Apr 2026 14:14:23 +0200 +Subject: [PATCH 43/47] net/pcs: add MediaTek MT7988 USXGMII PCS driver +Organization: Wires + +Add a PCS driver for the USXGMII subsystem found in the MediaTek MT7988 +SoC (usxgmiisys0 at 0x10080000, usxgmiisys1 at 0x10081000). The hardware +supports USXGMII (10G with in-band AN), 10GBase-R and 5GBase-R interface +modes. + +The driver: + - Registers via devm_pcs_register() so the Ethernet MAC driver can find + it through a DT pcs-handle phandle + - Delegates SerDes initialisation to the xfi_tphy PHY driver + - Sets up PCS speed/AN control registers and handles link state polling + - Reports link state from pcs_get_state without re-running pcs_config; + the 10G SerDes needs several seconds to complete CDR lock after a reset + and must not be restarted on every poll cycle before it can lock + +Based on work by Henry Yen and +Daniel Golle . + +Signed-off-by: Joachim Wiberg +--- + drivers/net/pcs/Kconfig | 10 + + drivers/net/pcs/Makefile | 1 + + drivers/net/pcs/pcs-mtk-usxgmii.c | 394 ++++++++++++++++++++++++++++++ + 3 files changed, 405 insertions(+) + create mode 100644 drivers/net/pcs/pcs-mtk-usxgmii.c + +diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig +index f6b4de7f972c..563c12d6aa9c 100644 +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -29,6 +29,16 @@ config PCS_MTK_LYNXI + This module provides helpers to phylink for managing the LynxI PCS + which is part of MediaTek's SoC and Ethernet switch ICs. + ++config PCS_MTK_USXGMII ++ tristate "MediaTek USXGMII PCS" ++ select PCS_STANDALONE ++ select PHY_MTK_XFI_TPHY ++ select PHYLINK ++ help ++ This module provides a driver for MediaTek's USXGMII PCS found in ++ the MT7988 SoC, supporting USXGMII, 10GBase-R and 5GBase-R interface ++ modes. ++ + config PCS_RZN1_MIIC + tristate "Renesas RZ/N1, RZ/N2H, RZ/T2H MII converter" + depends on OF +diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile +index 0cb0057f2b8e..b876cb2157b1 100644 +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -8,4 +8,5 @@ obj-$(CONFIG_PCS_STANDALONE) += pcs-standalone.o + obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o + obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o ++obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o + obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o +diff --git a/drivers/net/pcs/pcs-mtk-usxgmii.c b/drivers/net/pcs/pcs-mtk-usxgmii.c +new file mode 100644 +index 000000000000..f0e7d418db38 +--- /dev/null ++++ b/drivers/net/pcs/pcs-mtk-usxgmii.c +@@ -0,0 +1,394 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2023 MediaTek Inc. ++ * Author: Henry Yen ++ * Daniel Golle ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USXGMII subsystem config registers */ ++/* Register to control speed */ ++#define RG_PHY_TOP_SPEED_CTRL1 0x80c ++#define USXGMII_RATE_UPDATE_MODE BIT(31) ++#define USXGMII_MAC_CK_GATED BIT(29) ++#define USXGMII_IF_FORCE_EN BIT(28) ++#define USXGMII_RATE_ADAPT_MODE GENMASK(10, 8) ++#define USXGMII_RATE_ADAPT_MODE_X1 0 ++#define USXGMII_RATE_ADAPT_MODE_X2 1 ++#define USXGMII_RATE_ADAPT_MODE_X4 2 ++#define USXGMII_RATE_ADAPT_MODE_X10 3 ++#define USXGMII_RATE_ADAPT_MODE_X100 4 ++#define USXGMII_RATE_ADAPT_MODE_X5 5 ++#define USXGMII_RATE_ADAPT_MODE_X50 6 ++#define USXGMII_XFI_RX_MODE GENMASK(6, 4) ++#define USXGMII_XFI_TX_MODE GENMASK(2, 0) ++#define USXGMII_XFI_MODE_10G 0 ++#define USXGMII_XFI_MODE_5G 1 ++#define USXGMII_XFI_MODE_2P5G 3 ++ ++/* Register to control PCS AN */ ++#define RG_PCS_AN_CTRL0 0x810 ++#define USXGMII_AN_RESTART BIT(31) ++#define USXGMII_AN_SYNC_CNT GENMASK(30, 11) ++#define USXGMII_AN_ENABLE BIT(0) ++ ++#define RG_PCS_AN_CTRL2 0x818 ++#define USXGMII_LINK_TIMER_IDLE_DETECT GENMASK(29, 20) ++#define USXGMII_LINK_TIMER_COMP_ACK_DETECT GENMASK(19, 10) ++#define USXGMII_LINK_TIMER_AN_RESTART GENMASK(9, 0) ++ ++/* Register to read PCS AN status */ ++#define RG_PCS_AN_STS0 0x81c ++#define USXGMII_LPA GENMASK(15, 0) ++#define USXGMII_LPA_LATCH BIT(31) ++ ++/* Register to read PCS link status */ ++#define RG_PCS_RX_STATUS0 0x904 ++#define RG_PCS_RX_STATUS_UPDATE BIT(16) ++#define RG_PCS_RX_LINK_STATUS BIT(2) ++ ++/* struct mtk_usxgmii_pcs - This structure holds each usxgmii PCS ++ * @pcs: Phylink PCS structure ++ * @dev: Pointer to device structure ++ * @base: IO memory to access PCS hardware ++ * @clk: Pointer to USXGMII clk ++ * @reset: Pointer to USXGMII reset control ++ * @xfi_tphy: Pointer to XFI transceiver PHY ++ * @interface: Currently selected interface mode ++ * @node: List node ++ */ ++struct mtk_usxgmii_pcs { ++ struct phylink_pcs pcs; ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct reset_control *reset; ++ struct phy *xfi_tphy; ++ phy_interface_t interface; ++ struct list_head node; ++}; ++ ++static u32 mtk_r32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg) ++{ ++ return ioread32(mpcs->base + reg); ++} ++ ++static void mtk_m32(struct mtk_usxgmii_pcs *mpcs, unsigned int reg, u32 mask, u32 set) ++{ ++ u32 val; ++ ++ val = ioread32(mpcs->base + reg); ++ val &= ~mask; ++ val |= set; ++ iowrite32(val, mpcs->base + reg); ++} ++ ++static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mtk_usxgmii_pcs, pcs); ++} ++ ++static void mtk_usxgmii_reset(struct mtk_usxgmii_pcs *mpcs) ++{ ++ reset_control_assert(mpcs->reset); ++ udelay(100); ++ reset_control_deassert(mpcs->reset); ++ ++ mdelay(10); ++} ++ ++static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0; ++ bool mode_changed = false; ++ ++ if (interface == PHY_INTERFACE_MODE_USXGMII) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) | USXGMII_AN_ENABLE; ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); ++ } else if (interface == PHY_INTERFACE_MODE_10GBASER) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF); ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x7B) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x7B); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_10G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_10G); ++ adapt_mode = USXGMII_RATE_UPDATE_MODE; ++ } else if (interface == PHY_INTERFACE_MODE_5GBASER) { ++ an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0xFF); ++ link_timer = FIELD_PREP(USXGMII_LINK_TIMER_IDLE_DETECT, 0x3D) | ++ FIELD_PREP(USXGMII_LINK_TIMER_COMP_ACK_DETECT, 0x3D) | ++ FIELD_PREP(USXGMII_LINK_TIMER_AN_RESTART, 0x3D); ++ xfi_mode = FIELD_PREP(USXGMII_XFI_RX_MODE, USXGMII_XFI_MODE_5G) | ++ FIELD_PREP(USXGMII_XFI_TX_MODE, USXGMII_XFI_MODE_5G); ++ adapt_mode = USXGMII_RATE_UPDATE_MODE; ++ } else { ++ return -EINVAL; ++ } ++ ++ adapt_mode |= FIELD_PREP(USXGMII_RATE_ADAPT_MODE, USXGMII_RATE_ADAPT_MODE_X1); ++ ++ if (mpcs->interface != interface) { ++ mpcs->interface = interface; ++ mode_changed = true; ++ } ++ ++ phy_reset(mpcs->xfi_tphy); ++ mtk_usxgmii_reset(mpcs); ++ ++ /* Setup USXGMII AN ctrl */ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL0, ++ USXGMII_AN_SYNC_CNT | USXGMII_AN_ENABLE, ++ an_ctrl); ++ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL2, ++ USXGMII_LINK_TIMER_IDLE_DETECT | ++ USXGMII_LINK_TIMER_COMP_ACK_DETECT | ++ USXGMII_LINK_TIMER_AN_RESTART, ++ link_timer); ++ ++ /* Gated MAC CK */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_MAC_CK_GATED, USXGMII_MAC_CK_GATED); ++ ++ /* Enable interface force mode */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_IF_FORCE_EN, USXGMII_IF_FORCE_EN); ++ ++ /* Setup USXGMII adapt mode */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_RATE_UPDATE_MODE | USXGMII_RATE_ADAPT_MODE, ++ adapt_mode); ++ ++ /* Setup USXGMII speed */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, ++ USXGMII_XFI_RX_MODE | USXGMII_XFI_TX_MODE, ++ xfi_mode); ++ ++ usleep_range(1, 10); ++ ++ /* Un-gated MAC CK */ ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_MAC_CK_GATED, 0); ++ ++ usleep_range(1, 10); ++ ++ /* Disable interface force mode for the AN mode */ ++ if (an_ctrl & USXGMII_AN_ENABLE) ++ mtk_m32(mpcs, RG_PHY_TOP_SPEED_CTRL1, USXGMII_IF_FORCE_EN, 0); ++ ++ /* Setup PMA/PMD */ ++ phy_set_mode_ext(mpcs->xfi_tphy, PHY_MODE_ETHERNET, interface); ++ ++ return mode_changed; ++} ++ ++static void mtk_usxgmii_pcs_get_fixed_speed(struct mtk_usxgmii_pcs *mpcs, ++ struct phylink_link_state *state) ++{ ++ u32 val = mtk_r32(mpcs, RG_PHY_TOP_SPEED_CTRL1); ++ int speed; ++ ++ /* Calculate speed from interface speed and rate adapt mode */ ++ switch (FIELD_GET(USXGMII_XFI_RX_MODE, val)) { ++ case USXGMII_XFI_MODE_10G: ++ speed = 10000; ++ break; ++ case USXGMII_XFI_MODE_5G: ++ speed = 5000; ++ break; ++ case USXGMII_XFI_MODE_2P5G: ++ speed = 2500; ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ return; ++ } ++ ++ switch (FIELD_GET(USXGMII_RATE_ADAPT_MODE, val)) { ++ case USXGMII_RATE_ADAPT_MODE_X100: ++ speed /= 100; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X50: ++ speed /= 50; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X10: ++ speed /= 10; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X5: ++ speed /= 5; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X4: ++ speed /= 4; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X2: ++ speed /= 2; ++ break; ++ case USXGMII_RATE_ADAPT_MODE_X1: ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ return; ++ } ++ ++ state->speed = speed; ++ state->duplex = DUPLEX_FULL; ++} ++ ++static void mtk_usxgmii_pcs_get_an_state(struct mtk_usxgmii_pcs *mpcs, ++ struct phylink_link_state *state) ++{ ++ u16 lpa; ++ ++ /* Refresh LPA by toggling LPA_LATCH */ ++ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, USXGMII_LPA_LATCH); ++ ndelay(1020); ++ mtk_m32(mpcs, RG_PCS_AN_STS0, USXGMII_LPA_LATCH, 0); ++ ndelay(1020); ++ lpa = FIELD_GET(USXGMII_LPA, mtk_r32(mpcs, RG_PCS_AN_STS0)); ++ ++ phylink_decode_usxgmii_word(state, lpa); ++} ++ ++static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs, ++ unsigned int neg_mode, ++ struct phylink_link_state *state) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ /* Refresh USXGMII link status by toggling RG_PCS_AN_STATUS_UPDATE */ ++ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, ++ RG_PCS_RX_STATUS_UPDATE); ++ ndelay(1020); ++ mtk_m32(mpcs, RG_PCS_RX_STATUS0, RG_PCS_RX_STATUS_UPDATE, 0); ++ ndelay(1020); ++ ++ /* Read USXGMII link status */ ++ state->link = FIELD_GET(RG_PCS_RX_LINK_STATUS, ++ mtk_r32(mpcs, RG_PCS_RX_STATUS0)); ++ ++ if (!state->link) ++ return; ++ ++ if (FIELD_GET(USXGMII_AN_ENABLE, mtk_r32(mpcs, RG_PCS_AN_CTRL0))) ++ mtk_usxgmii_pcs_get_an_state(mpcs, state); ++ else ++ mtk_usxgmii_pcs_get_fixed_speed(mpcs, state); ++} ++ ++static void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ mtk_m32(mpcs, RG_PCS_AN_CTRL0, USXGMII_AN_RESTART, USXGMII_AN_RESTART); ++} ++ ++static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, ++ phy_interface_t interface, ++ int speed, int duplex) ++{ ++ /* Reconfiguring USXGMII to ensure the quality of the RX signal ++ * after the line side link up. ++ */ ++ mtk_usxgmii_pcs_config(pcs, neg_mode, interface, NULL, false); ++} ++ ++static int mtk_usxgmii_pcs_enable(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ phy_power_on(mpcs->xfi_tphy); ++ ++ return 0; ++} ++ ++static void mtk_usxgmii_pcs_disable(struct phylink_pcs *pcs) ++{ ++ struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs); ++ ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ ++ phy_power_off(mpcs->xfi_tphy); ++} ++ ++static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = { ++ .pcs_config = mtk_usxgmii_pcs_config, ++ .pcs_get_state = mtk_usxgmii_pcs_get_state, ++ .pcs_an_restart = mtk_usxgmii_pcs_restart_an, ++ .pcs_link_up = mtk_usxgmii_pcs_link_up, ++ .pcs_enable = mtk_usxgmii_pcs_enable, ++ .pcs_disable = mtk_usxgmii_pcs_disable, ++}; ++ ++static int mtk_usxgmii_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct mtk_usxgmii_pcs *mpcs; ++ ++ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return -ENOMEM; ++ ++ mpcs->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(mpcs->base)) ++ return PTR_ERR(mpcs->base); ++ ++ mpcs->dev = dev; ++ mpcs->pcs.ops = &mtk_usxgmii_pcs_ops; ++ mpcs->pcs.poll = true; ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ ++ mpcs->clk = devm_clk_get_enabled(mpcs->dev, NULL); ++ if (IS_ERR(mpcs->clk)) ++ return PTR_ERR(mpcs->clk); ++ ++ mpcs->xfi_tphy = devm_of_phy_get(mpcs->dev, dev->of_node, NULL); ++ if (IS_ERR(mpcs->xfi_tphy)) ++ return PTR_ERR(mpcs->xfi_tphy); ++ ++ mpcs->reset = devm_reset_control_get_shared(dev, NULL); ++ if (IS_ERR(mpcs->reset)) ++ return PTR_ERR(mpcs->reset); ++ ++ reset_control_deassert(mpcs->reset); ++ ++ platform_set_drvdata(pdev, mpcs); ++ ++ return devm_pcs_register(dev, &mpcs->pcs); ++} ++ ++static const struct of_device_id mtk_usxgmii_of_mtable[] = { ++ { .compatible = "mediatek,mt7988-usxgmiisys" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, mtk_usxgmii_of_mtable); ++ ++static struct platform_driver mtk_usxgmii_driver = { ++ .driver = { ++ .name = "mtk_usxgmii", ++ .suppress_bind_attrs = true, ++ .of_match_table = mtk_usxgmii_of_mtable, ++ }, ++ .probe = mtk_usxgmii_probe, ++}; ++module_platform_driver(mtk_usxgmii_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("MediaTek USXGMII PCS driver"); ++MODULE_AUTHOR("Daniel Golle "); +-- +2.43.0 + diff --git a/patches/linux/6.18.21/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch b/patches/linux/6.18.21/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch new file mode 100644 index 000000000..3627d6a1d --- /dev/null +++ b/patches/linux/6.18.21/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch @@ -0,0 +1,296 @@ +From 8917bfe8fac3e16e2c5958cdbf0b8258a7797539 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 6 Apr 2026 14:15:43 +0200 +Subject: [PATCH 44/47] net: ethernet: mediatek: add USXGMII support for MT7988 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +Organization: Wires + +Add support for the USXGMII path used by gmac1 and gmac2 on the MT7988 +SoC (BananaPi BPI-R4). Changes: + + - mtk_eth_soc.h: add MTK_USXGMII capability bit, path bits for all + three GMACs, SYSCFG0_SGMII_GMAC3_V2 mask, usxgmii_pcs pointer in + struct mtk_mac, and update MT7988_CAPS to include the USXGMII paths + and mux + + - mtk_eth_path.c: add set_mux_gmac123_to_usxgmii() which clears the + SGMII SYSCFG0 bits and for GMAC2 sets MUX_G2_USXGMII_SEL in + TOP_MISC_NETSYS_PCS_MUX; add mtk_gmac_usxgmii_path_setup() + + - mtk_eth_soc.c: wire up the USXGMII PCS — look up the pcs-handle DT + property via devm_of_pcs_get() during MAC probe and store in + mac->usxgmii_pcs; return it from mtk_mac_select_pcs() for USXGMII, + 10GBase-R and 5GBase-R modes; call mtk_gmac_usxgmii_path_setup() in + mtk_mac_config(); allow in-band autoneg for XGMII interfaces + +Based on work by Henry Yen and +Daniel Golle . + +Signed-off-by: Joachim Wiberg +--- + drivers/net/ethernet/mediatek/mtk_eth_path.c | 64 ++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 46 +++++++++++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 32 +++++++++- + 3 files changed, 139 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c +index b4c01e2878f6..57380776032a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -37,6 +37,12 @@ static const char *mtk_eth_path_name(u64 path) + return "gmac2_gephy"; + case MTK_ETH_PATH_GDM1_ESW: + return "gdm1_esw"; ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ return "gmac1_usxgmii"; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ return "gmac2_usxgmii"; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ return "gmac3_usxgmii"; + default: + return "unknown path"; + } +@@ -221,6 +227,48 @@ static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) + return 0; + } + ++static int set_mux_gmac123_to_usxgmii(struct mtk_eth *eth, u64 path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ int mac_id = 0; ++ ++ /* Disable SYSCFG1 SGMII */ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC1_V2; ++ mac_id = MTK_GMAC1_ID; ++ break; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; ++ mac_id = MTK_GMAC2_ID; ++ break; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC3_V2; ++ mac_id = MTK_GMAC3_ID; ++ break; ++ default: ++ updated = false; ++ break; ++ } ++ ++ if (updated) { ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ if (mac_id == MTK_GMAC2_ID) ++ regmap_set_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX, ++ MUX_G2_USXGMII_SEL); ++ } ++ ++ dev_dbg(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name(path), __func__, updated); ++ ++ return 0; ++} ++ + static const struct mtk_eth_muxc mtk_eth_muxc[] = { + { + .name = "mux_gdm1_to_gmac1_esw", +@@ -246,6 +294,10 @@ static const struct mtk_eth_muxc mtk_eth_muxc[] = { + .name = "mux_gmac12_to_gephy_sgmii", + .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, + .set_path = set_mux_gmac12_to_gephy_sgmii, ++ }, { ++ .name = "mux_gmac123_to_usxgmii", ++ .cap_bit = MTK_ETH_MUX_GMAC123_TO_USXGMII, ++ .set_path = set_mux_gmac123_to_usxgmii, + }, + }; + +@@ -328,3 +380,15 @@ int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) + return mtk_eth_mux_setup(eth, path); + } + ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ u64 path; ++ ++ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_USXGMII : ++ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_USXGMII : ++ MTK_ETH_PATH_GMAC3_USXGMII; ++ ++ /* Setup proper MUXes along the path */ ++ return mtk_eth_mux_setup(eth, path); ++} ++ +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 8d3e15bc867d..e6347b08648a 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -522,6 +523,17 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, + struct mtk_eth *eth = mac->hw; + unsigned int sid; + ++ if (mtk_is_netsys_v3_or_greater(eth)) { ++ switch (interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_5GBASER: ++ return mac->usxgmii_pcs; ++ default: ++ return NULL; ++ } ++ } ++ + if (interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_8023z(interface)) { + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? +@@ -601,6 +613,15 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + goto init_err; + } + break; ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_5GBASER: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) { ++ err = mtk_gmac_usxgmii_path_setup(eth, mac->id); ++ if (err) ++ goto init_err; ++ } ++ break; + default: + goto err_phy; + } +@@ -664,7 +685,8 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + + /* Save the syscfg0 value for mac_finish */ + mac->syscfg0 = val; +- } else if (phylink_autoneg_inband(mode)) { ++ } else if (phylink_autoneg_inband(mode) && ++ !mtk_interface_mode_is_xgmii(eth, state->interface)) { + dev_err(eth->dev, + "In-band mode not supported in non SGMII mode!\n"); + return; +@@ -4912,6 +4934,28 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_USXGMII)) { ++ struct phylink_pcs *pcs; ++ ++ pcs = devm_of_pcs_get(eth->dev, np, 0); ++ if (IS_ERR(pcs)) { ++ if (PTR_ERR(pcs) == -ENODEV) ++ return dev_err_probe(eth->dev, -EPROBE_DEFER, ++ "waiting for USXGMII PCS\n"); ++ /* No pcs-handle property — USXGMII not wired for this MAC */ ++ } else if (pcs) { ++ mac->usxgmii_pcs = pcs; ++ mac->phylink_config.mac_capabilities |= MAC_5000FD | ++ MAC_10000FD; ++ __set_bit(PHY_INTERFACE_MODE_USXGMII, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_10GBASER, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_5GBASER, ++ mac->phylink_config.supported_interfaces); ++ } ++ } ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), + phy_mode, &mtk_phylink_ops); +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 0168e2fbc619..2b27ef392b76 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -567,6 +567,7 @@ + #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) + #define SYSCFG0_SGMII_GMAC1_V2 BIT(9) + #define SYSCFG0_SGMII_GMAC2_V2 BIT(8) ++#define SYSCFG0_SGMII_GMAC3_V2 BIT(7) + + + /* ethernet subsystem clock register */ +@@ -1012,6 +1013,13 @@ enum mkt_eth_capabilities { + MTK_ETH_PATH_GMAC2_2P5GPHY_BIT, + MTK_ETH_PATH_GMAC2_GEPHY_BIT, + MTK_ETH_PATH_GDM1_ESW_BIT, ++ ++ /* USXGMII capability and path bits */ ++ MTK_USXGMII_BIT, ++ MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC1_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC2_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC3_USXGMII_BIT, + }; + + /* Supported hardware group on SoCs */ +@@ -1092,6 +1100,23 @@ enum mkt_eth_capabilities { + #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) + ++/* USXGMII support */ ++#define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT) ++ ++#define MTK_ETH_MUX_GMAC123_TO_USXGMII \ ++ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT) ++ ++#define MTK_ETH_PATH_GMAC1_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC3_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT) ++ ++#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) ++#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII) ++#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII) ++ ++#define MTK_MUX_GMAC123_TO_USXGMII \ ++ (MTK_ETH_MUX_GMAC123_TO_USXGMII | MTK_MUX | MTK_INFRA) ++ + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) + + #define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ +@@ -1124,8 +1149,9 @@ enum mkt_eth_capabilities { + MTK_RSTCTRL_PPE1 | MTK_SRAM) + + #define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC2_2P5GPHY | \ +- MTK_MUX_GMAC2_TO_2P5GPHY | MTK_QDMA | MTK_RSTCTRL_PPE1 | \ +- MTK_RSTCTRL_PPE2 | MTK_SRAM) ++ MTK_GMAC2_USXGMII | MTK_GMAC3_USXGMII | \ ++ MTK_MUX_GMAC2_TO_2P5GPHY | MTK_MUX_GMAC123_TO_USXGMII | \ ++ MTK_QDMA | MTK_RSTCTRL_PPE1 | MTK_RSTCTRL_PPE2 | MTK_SRAM) + + struct mtk_tx_dma_desc_info { + dma_addr_t addr; +@@ -1372,6 +1398,7 @@ struct mtk_mac { + struct device_node *of_node; + struct phylink *phylink; + struct phylink_config phylink_config; ++ struct phylink_pcs *usxgmii_pcs; + struct mtk_eth *hw; + struct mtk_hw_stats *hw_stats; + __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; +@@ -1506,6 +1533,7 @@ int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id); + + int mtk_eth_offload_init(struct mtk_eth *eth, u8 id); + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, +-- +2.43.0 + diff --git a/patches/linux/6.18.21/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch b/patches/linux/6.18.21/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch new file mode 100644 index 000000000..febdc5cd6 --- /dev/null +++ b/patches/linux/6.18.21/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch @@ -0,0 +1,65 @@ +From c62809d597945068569a95b7ccc0398d99db098f Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 6 Apr 2026 14:15:56 +0200 +Subject: [PATCH 45/47] arm64: dts: mediatek: mt7988a: add USXGMII PCS nodes +Organization: Wires + +Add device nodes for the two USXGMII subsystem blocks (usxgmiisys0 at +0x10080000 and usxgmiisys1 at 0x10081000), each referencing its clock, +reset, and xfi_tphy SerDes PHY. + +Wire gmac1 to usxgmiisys1 and gmac2 to usxgmiisys0 via the pcs-handle +property, so the Ethernet driver can discover the PCS at probe time. + +Signed-off-by: Joachim Wiberg +--- + arch/arm64/boot/dts/mediatek/mt7988a.dtsi | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +index 366203a72d6d..5ae43390f6c2 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +@@ -708,6 +708,24 @@ xfi_pll: clock-controller@11f40000 { + #clock-cells = <1>; + }; + ++ usxgmiisys0: pcs@10080000 { ++ compatible = "mediatek,mt7988-usxgmiisys"; ++ reg = <0 0x10080000 0 0x1000>; ++ resets = <&watchdog 12>; ++ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>; ++ phys = <&xfi_tphy0>; ++ #pcs-cells = <0>; ++ }; ++ ++ usxgmiisys1: pcs@10081000 { ++ compatible = "mediatek,mt7988-usxgmiisys"; ++ reg = <0 0x10081000 0 0x1000>; ++ resets = <&watchdog 13>; ++ clocks = <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>; ++ phys = <&xfi_tphy1>; ++ #pcs-cells = <0>; ++ }; ++ + efuse@11f50000 { + compatible = "mediatek,mt7988-efuse", "mediatek,efuse"; + reg = <0 0x11f50000 0 0x1000>; +@@ -979,12 +997,14 @@ gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + status = "disabled"; ++ pcs-handle = <&usxgmiisys1>; + }; + + gmac2: mac@2 { + compatible = "mediatek,eth-mac"; + reg = <2>; + status = "disabled"; ++ pcs-handle = <&usxgmiisys0>; + }; + + mdio_bus: mdio-bus { +-- +2.43.0 + diff --git a/patches/linux/6.18.21/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports.patch b/patches/linux/6.18.21/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports.patch new file mode 100644 index 000000000..be8eae29b --- /dev/null +++ b/patches/linux/6.18.21/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports.patch @@ -0,0 +1,82 @@ +From 12d076e64f65326cf9e453899b6ac5adb31374c3 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 6 Apr 2026 14:16:11 +0200 +Subject: [PATCH] arm64: dts: mediatek: bananapi-bpi-r4: enable SFP+ ports and + WPS button +Organization: Wires + +Enable the SFP+ cages wired to gmac1 and gmac2. The USXGMII PCS nodes +and xfi_tphy SerDes are wired up in mt7988a.dtsi; only status = "okay" +was missing. + +gmac2 (sfp1, WAN cage) is common to all R4 variants and is enabled in +mt7988a-bananapi-bpi-r4.dtsi. gmac1 (sfp2, LAN cage) is present only +on the standard R4 (2x SFP+) and is enabled here in the variant .dts. +The 2g5 variant uses gmac1 for the internal 2.5G PHY instead. + +Also add a gpio-keys node for the WPS/factory button on GPIO14 (active-low) +reporting KEY_WPS_BUTTON. This is the physical button labeled WPS/Factory +on the board silkscreen; GPIO14 is connected to it in the final hardware +revision of the BPI-R4. + +Signed-off-by: Joachim Wiberg +--- + .../boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts | 1 + + .../boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi | 13 ++++++++++++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +index 4b3796ba82e3..499f0c91c213 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dts +@@ -27,6 +27,7 @@ &gmac1 { + managed = "in-band-status"; + phy-mode = "usxgmii"; + sfp = <&sfp2>; ++ status = "okay"; + }; + + &pca9545 { +diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +index 0ff69dae45d3..2a904a76f3fe 100644 +--- a/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7988a-bananapi-bpi-r4.dtsi +@@ -3,9 +3,9 @@ + /dts-v1/; + + #include ++#include + #include + #include +-#include + + #include "mt7988a.dtsi" + +@@ -29,6 +29,16 @@ fan: pwm-fan { + status = "okay"; + }; + ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ wps { ++ label = "wps"; ++ gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ + gpio-leds { + compatible = "gpio-leds"; + +@@ -152,6 +162,7 @@ &gmac2 { + managed = "in-band-status"; + phy-mode = "usxgmii"; + sfp = <&sfp1>; ++ status = "okay"; + }; + + &gsw_phy0 { +-- +2.43.0 + diff --git a/patches/linux/6.18.21/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch b/patches/linux/6.18.21/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch new file mode 100644 index 000000000..d1a209d7d --- /dev/null +++ b/patches/linux/6.18.21/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch @@ -0,0 +1,60 @@ +From 4b267c1be4141e0213b49d6d511051b8e6673f7c Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Mon, 6 Apr 2026 14:16:16 +0200 +Subject: [PATCH 47/47] net: phy: sfp: add OEM SFP-10G-T-I quirk +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +Organization: Wires + +The industrial-temperature variant of the OEM SFP-10G-T copper module +reports vendor PN "SFP-10G-T-I". Unlike the base "SFP-10G-T" which is a +genuine RollBall module, the -I variant uses a plain XFI (10GBASER) host +interface and does not implement the RollBall MDIO protocol. + +Both variants zero the extended_cc field in EEPROM, which causes +sfp_module_parse_support() to hit SFF8024_ECC_UNSPEC and set no interface +modes, making phylink reject the module with "no common interface modes". + +For the -I variant, add sfp_fixup_xfi_cc which only corrects the extended +compliance code to SFF8024_ECC_10GBASE_T_SFI so the driver picks 10GBASER. +Skipping the RollBall PHY probe avoids a ~7-minute boot-time delay +(sfp_poll_timeout * retries ≈ 440 s) when no RollBall PHY is found. + +Signed-off-by: Joachim Wiberg +--- + drivers/net/phy/sfp.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index ca0992533572..53aafabeefd4 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -451,6 +451,16 @@ static void sfp_fixup_rollball_cc(struct sfp *sfp) + sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI; + } + ++static void sfp_fixup_xfi_cc(struct sfp *sfp) ++{ ++ /* Module has zeroed extended compliance code but uses a plain XFI ++ * (10GBASER) host interface and does not support the Rollball MDIO ++ * protocol. Only fix the compliance code so the driver picks 10GBASER; ++ * skipping Rollball avoids a ~7 minute PHY probe retry delay on boot. ++ */ ++ sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI; ++} ++ + static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, + struct sfp_module_caps *caps) + { +@@ -559,6 +569,7 @@ static const struct sfp_quirk sfp_quirks[] = { + SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), + + SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), ++ SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_xfi_cc), + SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), + SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex), + SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-U", sfp_quirk_2500basex), +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0001-hush-Remove-Ctrl-C-detection-in-loops.patch b/patches/uboot/2026.01/0001-hush-Remove-Ctrl-C-detection-in-loops.patch new file mode 100644 index 000000000..4371a4c57 --- /dev/null +++ b/patches/uboot/2026.01/0001-hush-Remove-Ctrl-C-detection-in-loops.patch @@ -0,0 +1,42 @@ +From cde9fed496833b88094ed6e9fea11969a1be8e25 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Mon, 10 Jun 2024 13:25:31 +0200 +Subject: [PATCH 01/10] hush: Remove Ctrl-C detection in loops +Organization: Wires + +Assume that the original intent was to emulate SIGINT to a shell. This +only works as expected if the loop in question is the ouermost, and +last, statement. In all other cases, it completely breaks the expected +execution flow. It more or less resurrects Visual Basic's "On Error +Resume Next". + +Disable this behavior and delegate the problem of loop termination to +the writer of the script instead. + +Signed-off-by: Tobias Waldekranz +Signed-off-by: Joachim Wiberg +--- + common/cli_hush.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/common/cli_hush.c b/common/cli_hush.c +index 7bd6943d3ed..a58a2d24572 100644 +--- a/common/cli_hush.c ++++ b/common/cli_hush.c +@@ -1794,13 +1794,6 @@ static int run_list_real(struct pipe *pi) + for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { + if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || + pi->r_mode == RES_FOR) { +-#ifdef __U_BOOT__ +- /* check Ctrl-C */ +- ctrlc(); +- if ((had_ctrlc())) { +- return 1; +- } +-#endif + flag_restore = 0; + if (!rpipe) { + flag_rep = 0; +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0002-cmd-new-command-rpidisplay.patch b/patches/uboot/2026.01/0002-cmd-new-command-rpidisplay.patch new file mode 100644 index 000000000..28af02cb3 --- /dev/null +++ b/patches/uboot/2026.01/0002-cmd-new-command-rpidisplay.patch @@ -0,0 +1,153 @@ +From 020c9a036f2916afdce9d18aacc9e8c09a5dfca7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= +Date: Sat, 6 Sep 2025 22:18:27 +0200 +Subject: [PATCH 02/10] cmd: new command rpidisplay +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +Organization: Wires + +Signed-off-by: Mattias Walström +Signed-off-by: Joachim Wiberg +--- + cmd/Kconfig | 14 ++++++++ + cmd/Makefile | 2 +- + cmd/rpi_display.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 96 insertions(+), 1 deletion(-) + create mode 100644 cmd/rpi_display.c + +diff --git a/cmd/Kconfig b/cmd/Kconfig +index 5c611fb3016..5b69cd3a439 100644 +--- a/cmd/Kconfig ++++ b/cmd/Kconfig +@@ -183,6 +183,20 @@ config CMD_UFETCH + Fetch utility for U-Boot (akin to neofetch). Prints information + about U-Boot and the board it is running on in a pleasing format. + ++config CMD_RPI_DISPLAY ++ bool "rpidisplay" ++ depends on ARCH_BCM283X ++ help ++ Enable commands to detect Raspberry Pi 7" DSI display connection. ++ ++ This provides two commands: ++ - rpidisplay: Shows detailed detection information ++ - testrpidisplay: Silent test for use in boot scripts ++ ++ Detection is performed by querying the VideoCore GPU for the ++ active display resolution. The official Raspberry Pi 7" DSI ++ display uses 800x480 resolution. ++ + config CMD_FWU_METADATA + bool "fwu metadata read" + depends on FWU_MULTI_BANK_UPDATE +diff --git a/cmd/Makefile b/cmd/Makefile +index 25479907797..94b6890df0e 100644 +--- a/cmd/Makefile ++++ b/cmd/Makefile +@@ -50,6 +50,7 @@ obj-$(CONFIG_CMD_CLK) += clk.o + obj-$(CONFIG_CMD_CLS) += cls.o + obj-$(CONFIG_CMD_CONFIG) += config.o + obj-$(CONFIG_CMD_CONITRACE) += conitrace.o ++obj-$(CONFIG_CMD_RPI_DISPLAY) += rpi_display.o + obj-$(CONFIG_CMD_CONSOLE) += console.o + obj-$(CONFIG_CMD_CPU) += cpu.o + obj-$(CONFIG_CMD_DATE) += date.o +@@ -204,7 +205,6 @@ obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o + obj-$(CONFIG_CMD_UFS) += ufs.o + obj-$(CONFIG_CMD_USB) += usb.o disk.o + obj-$(CONFIG_CMD_VIDCONSOLE) += video.o +- + obj-$(CONFIG_CMD_FASTBOOT) += fastboot.o + obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o + +diff --git a/cmd/rpi_display.c b/cmd/rpi_display.c +new file mode 100644 +index 00000000000..07abdc08552 +--- /dev/null ++++ b/cmd/rpi_display.c +@@ -0,0 +1,81 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Raspberry Pi 7" DSI Display Detection Command ++ * Detects if the official Raspberry Pi 7" DSI display is connected ++ */ ++ ++#include ++#include ++ ++static int do_rpi_display(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int width, height; ++ int ret; ++ ++ printf("=== Raspberry Pi 7\" DSI Display Detection ===\n"); ++ ++ /* Use official VideoCore mailbox interface to get display resolution */ ++ ret = bcm2835_get_video_size(&width, &height); ++ if (ret) { ++ printf("Failed to query VideoCore display size (ret=%d)\n", ret); ++ printf("Display Status: NOT DETECTED\n"); ++ return 2; ++ } ++ ++ printf("VideoCore reports display: %dx%d", width, height); ++ ++ /* Official Raspberry Pi 7" DSI display is 800x480 */ ++ if (width == 800 && height == 480) { ++ printf(" - RASPBERRY PI 7\" DSI DISPLAY DETECTED!\n"); ++ printf("Display Status: CONNECTED\n"); ++ return 0; ++ } ++ /* No resolution could indicate no display */ ++ else if (width == 0 || height == 0) { ++ printf(" - No active display\n"); ++ printf("Display Status: NOT DETECTED\n"); ++ return 1; ++ } ++ else { ++ printf(" - Not Raspberry Pi DSI display (resolution %dx%d)\n", width, height); ++ printf("Display Status: NOT DETECTED\n"); ++ return 1; ++ } ++} ++ ++static int do_test_rpi_display(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ int width, height; ++ int ret; ++ ++ /* Silent test using VideoCore mailbox interface */ ++ ret = bcm2835_get_video_size(&width, &height); ++ if (ret) { ++ return 2; /* Failed to query VideoCore */ ++ } ++ ++ /* Check for Raspberry Pi DSI display resolutions */ ++ if ((width == 800 && height == 480)) { ++ return 0; /* DSI display found */ ++ } ++ ++ return 1; /* DSI display not found */ ++} ++ ++U_BOOT_CMD( ++ rpidisplay, 1, 1, do_rpi_display, ++ "detect Raspberry Pi DSI display", ++ "\n" ++ "Detects Raspberry Pi 7\" DSI display by checking resolution:\n" ++ " - 800x480 = Official Raspberry Pi 7\" DSI display\n" ++ "Returns: 0=connected, 1=not detected, 2=no video" ++); ++ ++U_BOOT_CMD( ++ testrpidisplay, 1, 1, do_test_rpi_display, ++ "silent test for Raspberry Pi DSI display", ++ "\n" ++ "Silent test for Raspberry Pi DSI display (for use in scripts):\n" ++ "Returns: 0=connected, 1=not detected, 2=no video\n" ++ "Usage: if testrpidisplay; then echo DSI found; fi" ++); +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0003-arm-dts-at91-sama7g5ek-supports-high-speed-on-mmc0-e.patch b/patches/uboot/2026.01/0003-arm-dts-at91-sama7g5ek-supports-high-speed-on-mmc0-e.patch new file mode 100644 index 000000000..8c679922f --- /dev/null +++ b/patches/uboot/2026.01/0003-arm-dts-at91-sama7g5ek-supports-high-speed-on-mmc0-e.patch @@ -0,0 +1,35 @@ +From 1a861c65011f636e464ca557804dfb6853a3871c Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Thu, 12 Feb 2026 10:00:02 +0100 +Subject: [PATCH 03/10] arm: dts: at91: sama7g5ek supports high-speed on mmc0 + (eMMC) +Organization: Wires + +- eMMC high-speed timing is supported +- eMMC hardware reset is supported + +Tested on sama7g5ek rev 5. + +Signed-off-by: Joachim Wiberg +--- + arch/arm/dts/at91-sama7g5ek.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/dts/at91-sama7g5ek.dts b/arch/arm/dts/at91-sama7g5ek.dts +index 9b247fcaf66..45fe6a7f6cd 100644 +--- a/arch/arm/dts/at91-sama7g5ek.dts ++++ b/arch/arm/dts/at91-sama7g5ek.dts +@@ -776,8 +776,8 @@ + &sdmmc0 { + bus-width = <8>; + non-removable; +- no-1-8-v; +- sdhci-caps-mask = <0x0 0x00200000>; ++ cap-mmc-highspeed; ++ cap-mmc-hw-reset; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + status = "okay"; +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0004-arm-dts-at91-sama7g5ek-increase-clock-for-sdmmc-from.patch b/patches/uboot/2026.01/0004-arm-dts-at91-sama7g5ek-increase-clock-for-sdmmc-from.patch new file mode 100644 index 000000000..b564eb7dd --- /dev/null +++ b/patches/uboot/2026.01/0004-arm-dts-at91-sama7g5ek-increase-clock-for-sdmmc-from.patch @@ -0,0 +1,36 @@ +From 3fadc90e8c1017aa3d8c165e54a13d8f75536b99 Mon Sep 17 00:00:00 2001 +From: Mihai Sain +Date: Fri, 5 May 2023 13:28:31 +0300 +Subject: [PATCH 04/10] arm: dts: at91: sama7g5ek: increase clock for sdmmc + from 25 MHz to 50 MHz +Organization: Wires + +Current clock for sdmmc0 and sdmmc1 is 25 MHz because of the caps forced +by the mainline kernel. + +Remove the caps in order to increase the clock to 50 MHz. This will +improve the boot time when reading the kernel binary. Tested on +sama7g5ek rev 5 using mmcinfo command. + +Signed-off-by: Mihai Sain +Signed-off-by: Joachim Wiberg +--- + arch/arm/dts/at91-sama7g5ek.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm/dts/at91-sama7g5ek.dts b/arch/arm/dts/at91-sama7g5ek.dts +index 45fe6a7f6cd..d2d16bd5f1f 100644 +--- a/arch/arm/dts/at91-sama7g5ek.dts ++++ b/arch/arm/dts/at91-sama7g5ek.dts +@@ -785,8 +785,6 @@ + + &sdmmc1 { + bus-width = <4>; +- no-1-8-v; +- sdhci-caps-mask = <0x0 0x00200000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc1_default>; + status = "okay"; +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0005-net-phy-Add-the-Airoha-EN8811H-PHY-driver.patch b/patches/uboot/2026.01/0005-net-phy-Add-the-Airoha-EN8811H-PHY-driver.patch new file mode 100644 index 000000000..874dfdcf9 --- /dev/null +++ b/patches/uboot/2026.01/0005-net-phy-Add-the-Airoha-EN8811H-PHY-driver.patch @@ -0,0 +1,977 @@ +From b8b781fd58eb8f0934edde8db45744d0a417cda8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= +Date: Wed, 18 Feb 2026 17:00:09 +0100 +Subject: [PATCH 05/10] net: phy: Add the Airoha EN8811H PHY driver +Organization: Wires + +Add the driver for the Airoha EN8811H 2.5 Gigabit PHY. The PHY supports +100/1000/2500 Mbps with auto negotiation only. + +The driver uses two firmware files, for which updated versions are added to +linux-firmware already. + +Locating the AIROHA FW within the filesystem at the designated partition +and path will trigger its automatic loading and writing to the PHY via MDIO. +If need board specific loading override, +please override the en8811h_read_fw function on board or architecture level. + +Linux upstream AIROHA EN8811H driver commit: +71e79430117d56c409c5ea485a263bc0d8083390 + +Based on the Linux upstream AIROHA EN8811H driver code(air_en8811h.c), +I have modified the relevant process to align with the U-Boot boot sequence. +and have validated this on Banana Pi BPI-R3 Mini. + +Signed-off-by: Lucien.Jheng +Signed-off-by: Joachim Wiberg +--- + drivers/net/phy/Kconfig | 25 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/air_en8811h.c | 887 ++++++++++++++++++++++++++++++++++ + 3 files changed, 913 insertions(+) + create mode 100644 drivers/net/phy/air_en8811h.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 018be98705a..bc5b9d8a8c4 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -83,6 +83,31 @@ config PHY_ADIN + help + Add support for configuring RGMII on Analog Devices ADIN PHYs. + ++menuconfig PHY_AIROHA ++ bool "Airoha Ethernet PHYs support" ++ ++config PHY_AIROHA_EN8811H ++ bool "Airoha Ethernet EN8811H support" ++ depends on PHY_AIROHA ++ help ++ AIROHA EN8811H supported. ++ ++choice ++ prompt "Location of the Airoha PHY firmware" ++ default PHY_AIROHA_FW_IN_MMC ++ depends on PHY_AIROHA_EN8811H ++ ++config PHY_AIROHA_FW_IN_MMC ++ bool "Airoha firmware in MMC partition" ++ help ++ Airoha PHYs use firmware which can be loaded automatically ++ from storage directly attached to the PHY, and then loaded ++ via MDIO commands by the boot loader. The firmware is loaded ++ from a file specified by the U-Boot environment variables ++ en8811h_fw_part, en8811h_fw_dm_dir, and en8811h_fw_dsp_dir. ++ ++endchoice ++ + menuconfig PHY_AQUANTIA + bool "Aquantia Ethernet PHYs support" + select PHY_GIGE +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index a339b8ac29d..431d1eef083 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o + obj-$(CONFIG_PHYLIB) += phy.o + obj-$(CONFIG_PHYLIB_10G) += generic_10g.o + obj-$(CONFIG_PHY_ADIN) += adin.o ++obj-$(CONFIG_PHY_AIROHA_EN8811H) += air_en8811h.o + obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o + obj-$(CONFIG_PHY_ATHEROS) += atheros.o + obj-$(CONFIG_PHY_BROADCOM) += broadcom.o +diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c +new file mode 100644 +index 00000000000..d856d48b4a5 +--- /dev/null ++++ b/drivers/net/phy/air_en8811h.c +@@ -0,0 +1,887 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Driver for the Airoha EN8811H 2.5 Gigabit PHY. ++ * ++ * Limitations of the EN8811H: ++ * - Only full duplex supported ++ * - Forced speed (AN off) is not supported by hardware (100Mbps) ++ * ++ * Source originated from linux air_en8811h.c ++ * ++ * Copyright (C) 2025 Airoha Technology Corp. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define EN8811H_PHY_ID 0x03a2a411 ++ ++#define AIR_FW_ADDR_DM 0x00000000 ++#define AIR_FW_ADDR_DSP 0x00100000 ++ ++#define EN8811H_MD32_DM_SIZE 0x4000 ++#define EN8811H_MD32_DSP_SIZE 0x20000 ++ ++ #define EN8811H_FW_CTRL_1 0x0f0018 ++ #define EN8811H_FW_CTRL_1_START 0x0 ++ #define EN8811H_FW_CTRL_1_FINISH 0x1 ++ #define EN8811H_FW_CTRL_2 0x800000 ++ #define EN8811H_FW_CTRL_2_LOADING BIT(11) ++ ++ /* MII Registers */ ++ #define AIR_AUX_CTRL_STATUS 0x1d ++ #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2) ++ #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4 ++ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 ++ #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc ++ ++#define AIR_EXT_PAGE_ACCESS 0x1f ++#define AIR_PHY_PAGE_STANDARD 0x0000 ++#define AIR_PHY_PAGE_EXTENDED_4 0x0004 ++ ++/* MII Registers Page 4*/ ++#define AIR_BPBUS_MODE 0x10 ++#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 ++#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) ++#define AIR_BPBUS_WR_ADDR_HIGH 0x11 ++#define AIR_BPBUS_WR_ADDR_LOW 0x12 ++#define AIR_BPBUS_WR_DATA_HIGH 0x13 ++#define AIR_BPBUS_WR_DATA_LOW 0x14 ++#define AIR_BPBUS_RD_ADDR_HIGH 0x15 ++#define AIR_BPBUS_RD_ADDR_LOW 0x16 ++#define AIR_BPBUS_RD_DATA_HIGH 0x17 ++#define AIR_BPBUS_RD_DATA_LOW 0x18 ++ ++/* Registers on MDIO_MMD_VEND1 */ ++#define EN8811H_PHY_FW_STATUS 0x8009 ++#define EN8811H_PHY_READY 0x02 ++ ++/* Registers on MDIO_MMD_VEND2 */ ++#define AIR_PHY_LED_BCR 0x021 ++#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0) ++#define AIR_PHY_LED_BCR_TIME_TEST BIT(2) ++#define AIR_PHY_LED_BCR_CLK_EN BIT(3) ++#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15) ++ ++#define AIR_PHY_LED_DUR_ON 0x022 ++ ++#define AIR_PHY_LED_DUR_BLINK 0x023 ++ ++#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2)) ++#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8)) ++#define AIR_PHY_LED_ON_LINK1000 BIT(0) ++#define AIR_PHY_LED_ON_LINK100 BIT(1) ++#define AIR_PHY_LED_ON_LINK10 BIT(2) ++#define AIR_PHY_LED_ON_LINKDOWN BIT(3) ++#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */ ++#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */ ++#define AIR_PHY_LED_ON_FORCE_ON BIT(6) ++#define AIR_PHY_LED_ON_LINK2500 BIT(8) ++#define AIR_PHY_LED_ON_POLARITY BIT(14) ++#define AIR_PHY_LED_ON_ENABLE BIT(15) ++ ++#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2)) ++#define AIR_PHY_LED_BLINK_1000TX BIT(0) ++#define AIR_PHY_LED_BLINK_1000RX BIT(1) ++#define AIR_PHY_LED_BLINK_100TX BIT(2) ++#define AIR_PHY_LED_BLINK_100RX BIT(3) ++#define AIR_PHY_LED_BLINK_10TX BIT(4) ++#define AIR_PHY_LED_BLINK_10RX BIT(5) ++#define AIR_PHY_LED_BLINK_COLLISION BIT(6) ++#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7) ++#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) ++#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9) ++#define AIR_PHY_LED_BLINK_2500TX BIT(10) ++#define AIR_PHY_LED_BLINK_2500RX BIT(11) ++ ++#define EN8811H_FW_VERSION 0x3b3c ++ ++#define EN8811H_POLARITY 0xca0f8 ++#define EN8811H_POLARITY_TX_NORMAL BIT(0) ++#define EN8811H_POLARITY_RX_REVERSE BIT(1) ++ ++#define EN8811H_CLK_CGM 0xcf958 ++#define EN8811H_CLK_CGM_CKO BIT(26) ++#define EN8811H_HWTRAP1 0xcf914 ++#define EN8811H_HWTRAP1_CKO BIT(12) ++ ++#define air_upper_16_bits(n) ((u16)((n) >> 16)) ++#define air_lower_16_bits(n) ((u16)((n) & 0xffff)) ++#define clear_bit(bit, bitmap) __clear_bit(bit, bitmap) ++ ++/* Led definitions */ ++#define EN8811H_LED_COUNT 3 ++ ++struct led { ++ unsigned long rules; ++ unsigned long state; ++}; ++ ++enum { ++ AIR_PHY_LED_STATE_FORCE_ON, ++ AIR_PHY_LED_STATE_FORCE_BLINK, ++}; ++ ++enum { ++ AIR_PHY_LED_DUR_BLINK_32MS, ++ AIR_PHY_LED_DUR_BLINK_64MS, ++ AIR_PHY_LED_DUR_BLINK_128MS, ++ AIR_PHY_LED_DUR_BLINK_256MS, ++ AIR_PHY_LED_DUR_BLINK_512MS, ++ AIR_PHY_LED_DUR_BLINK_1024MS, ++}; ++ ++enum { ++ AIR_LED_DISABLE, ++ AIR_LED_ENABLE, ++}; ++ ++enum { ++ AIR_ACTIVE_LOW, ++ AIR_ACTIVE_HIGH, ++}; ++ ++enum { ++ AIR_LED_MODE_DISABLE, ++ AIR_LED_MODE_USER_DEFINE, ++}; ++ ++/* Trigger specific enum */ ++enum air_led_trigger_netdev_modes { ++ AIR_TRIGGER_NETDEV_LINK = 0, ++ AIR_TRIGGER_NETDEV_LINK_10, ++ AIR_TRIGGER_NETDEV_LINK_100, ++ AIR_TRIGGER_NETDEV_LINK_1000, ++ AIR_TRIGGER_NETDEV_LINK_2500, ++ AIR_TRIGGER_NETDEV_LINK_5000, ++ AIR_TRIGGER_NETDEV_LINK_10000, ++ AIR_TRIGGER_NETDEV_HALF_DUPLEX, ++ AIR_TRIGGER_NETDEV_FULL_DUPLEX, ++ AIR_TRIGGER_NETDEV_TX, ++ AIR_TRIGGER_NETDEV_RX, ++ AIR_TRIGGER_NETDEV_TX_ERR, ++ AIR_TRIGGER_NETDEV_RX_ERR, ++ ++ /* Keep last */ ++ __AIR_TRIGGER_NETDEV_MAX, ++}; ++ ++/* Default LED setup: ++ * GPIO5 <-> LED0 On: Link detected, blink Rx/Tx ++ * GPIO4 <-> LED1 On: Link detected at 2500 and 1000 Mbps ++ * GPIO3 <-> LED2 On: Link detected at 2500 and 100 Mbps ++ */ ++#define AIR_DEFAULT_TRIGGER_LED0 (BIT(AIR_TRIGGER_NETDEV_LINK) | \ ++ BIT(AIR_TRIGGER_NETDEV_RX) | \ ++ BIT(AIR_TRIGGER_NETDEV_TX)) ++#define AIR_DEFAULT_TRIGGER_LED1 (BIT(AIR_TRIGGER_NETDEV_LINK_2500) | \ ++ BIT(AIR_TRIGGER_NETDEV_LINK_1000)) ++#define AIR_DEFAULT_TRIGGER_LED2 (BIT(AIR_TRIGGER_NETDEV_LINK_2500) | \ ++ BIT(AIR_TRIGGER_NETDEV_LINK_100)) ++ ++#define AIR_PHY_LED_DUR_UNIT 781 ++#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS) ++ ++struct en8811h_priv { ++ int firmware_version; ++ bool mcu_needs_restart; ++ struct led led[EN8811H_LED_COUNT]; ++}; ++ ++static int air_phy_read_page(struct phy_device *phydev) ++{ ++ return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS); ++} ++ ++static int air_phy_write_page(struct phy_device *phydev, int page) ++{ ++ return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page); ++} ++ ++int air_phy_select_page(struct phy_device *phydev, int page) ++{ ++ int ret, oldpage; ++ ++ oldpage = air_phy_read_page(phydev); ++ if (oldpage < 0) ++ return oldpage; ++ ++ if (oldpage != page) { ++ ret = air_phy_write_page(phydev, page); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return oldpage; ++} ++ ++int air_phy_restore_page(struct phy_device *phydev, int oldpage, int ret) ++{ ++ int r; ++ ++ if (oldpage < 0) ++ return oldpage; ++ ++ r = air_phy_write_page(phydev, oldpage); ++ if (ret >= 0 && r < 0) ++ ret = r; ++ ++ return ret; ++} ++ ++static int air_buckpbus_reg_write(struct phy_device *phydev, ++ u32 pbus_address, u32 pbus_data) ++{ ++ int ret, saved_page; ++ ++ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ if (saved_page < 0) ++ return saved_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, ++ AIR_BPBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, ++ air_upper_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, ++ air_lower_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, ++ air_upper_16_bits(pbus_data)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, ++ air_lower_16_bits(pbus_data)); ++ if (ret < 0) ++ goto restore_page; ++ ++restore_page: ++ if (ret < 0) ++ printf("%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ ++ return air_phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int air_buckpbus_reg_read(struct phy_device *phydev, ++ u32 pbus_address, u32 *pbus_data) ++{ ++ int pbus_data_low, pbus_data_high; ++ int ret = 0, saved_page; ++ ++ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ if (saved_page < 0) ++ return saved_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, ++ AIR_BPBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, ++ air_upper_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, ++ air_lower_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); ++ if (pbus_data_high < 0) { ++ ret = pbus_data_high; ++ goto restore_page; ++ } ++ ++ pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); ++ if (pbus_data_low < 0) { ++ ret = pbus_data_low; ++ goto restore_page; ++ } ++ ++ *pbus_data = pbus_data_low | (pbus_data_high << 16); ++ ++restore_page: ++ if (ret < 0) ++ printf("%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ ++ return air_phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int air_buckpbus_reg_modify(struct phy_device *phydev, ++ u32 pbus_address, u32 mask, u32 set) ++{ ++ int pbus_data_low, pbus_data_high; ++ u32 pbus_data_old, pbus_data_new; ++ int ret = 0, saved_page; ++ ++ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ if (saved_page < 0) ++ return saved_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, ++ AIR_BPBUS_MODE_ADDR_FIXED); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, ++ air_upper_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, ++ air_lower_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); ++ if (pbus_data_high < 0) ++ return pbus_data_high; ++ ++ pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); ++ if (pbus_data_low < 0) ++ return pbus_data_low; ++ ++ pbus_data_old = pbus_data_low | (pbus_data_high << 16); ++ pbus_data_new = (pbus_data_old & ~mask) | set; ++ if (pbus_data_new == pbus_data_old) ++ return 0; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, ++ air_upper_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, ++ air_lower_16_bits(pbus_address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, ++ air_upper_16_bits(pbus_data_new)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, ++ air_lower_16_bits(pbus_data_new)); ++ if (ret < 0) ++ goto restore_page; ++ ++restore_page: ++ if (ret < 0) ++ printf("%s 0x%08x failed: %d\n", __func__, ++ pbus_address, ret); ++ ++ return air_phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int air_write_buf(struct phy_device *phydev, unsigned long address, ++ unsigned long array_size, const unsigned char *buffer) ++{ ++ unsigned int offset; ++ int ret, saved_page; ++ u16 val; ++ ++ saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); ++ if (saved_page < 0) ++ return saved_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, ++ AIR_BPBUS_MODE_ADDR_INCR); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, ++ air_upper_16_bits(address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, ++ air_lower_16_bits(address)); ++ if (ret < 0) ++ goto restore_page; ++ ++ for (offset = 0; offset < array_size; offset += 4) { ++ val = get_unaligned_le16(&buffer[offset + 2]); ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, val); ++ if (ret < 0) ++ goto restore_page; ++ ++ val = get_unaligned_le16(&buffer[offset]); ++ ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, val); ++ if (ret < 0) ++ goto restore_page; ++ } ++ ++restore_page: ++ if (ret < 0) ++ printf("%s 0x%08lx failed: %d\n", __func__, ++ address, ret); ++ ++ return air_phy_restore_page(phydev, saved_page, ret); ++} ++ ++static int en8811h_wait_mcu_ready(struct phy_device *phydev) ++{ ++ int ret, reg_value; ++ ++ /* Because of mdio-lock, may have to wait for multiple loads */ ++ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ++ EN8811H_PHY_FW_STATUS, reg_value, ++ reg_value == EN8811H_PHY_READY, ++ 20000, 7500000, true); ++ if (ret) { ++ printf("MCU not ready: 0x%x\n", reg_value); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++__weak int en8811h_read_fw(void **addr) ++{ ++ const char *fw_dm, *fw_dsp, *fw_part; ++ u32 ca_crc32; ++ void *buffer; ++ loff_t read; ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_PHY_AIROHA_FW_IN_MMC)) ++ return -EOPNOTSUPP; ++ ++ /* Allocate memory to store both DM and DSP firmware */ ++ buffer = malloc(EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE); ++ if (!buffer) { ++ printf("Failed to allocate memory for firmware\n"); ++ return -ENOMEM; ++ } ++ ++ /* Get the partition name where the firmware is stored */ ++ fw_part = env_get("en8811h_fw_part"); ++ if (!fw_part) { ++ printf("Error: env var en8811h_fw_part not set.\n"); ++ ret = -EINVAL; ++ goto err_free; ++ } ++ ++ /* Get the DM firmware file path */ ++ fw_dm = env_get("en8811h_fw_dm_dir"); ++ if (!fw_dm) { ++ printf("Error: env var en8811h_fw_dm_dir not set.\n"); ++ ret = -EINVAL; ++ goto err_free; ++ } ++ ++ /* Get the DSP firmware file path */ ++ fw_dsp = env_get("en8811h_fw_dsp_dir"); ++ if (!fw_dsp) { ++ printf("Error: env var en8811h_fw_dsp_dir not set.\n"); ++ ret = -EINVAL; ++ goto err_free; ++ } ++ ++ /* Load DM firmware */ ++ ret = fs_set_blk_dev("mmc", fw_part, FS_TYPE_ANY); ++ if (ret < 0) ++ goto err_free; ++ ++ /* Read DM firmware file into the start of buffer */ ++ ret = fs_read(fw_dm, (ulong)buffer, 0, EN8811H_MD32_DM_SIZE, &read); ++ if (ret < 0) { ++ printf("Failed to read DM firmware: %s\n", fw_dm); ++ goto err_free; ++ } ++ ++ /* Calculate CRC32 of DM firmware for verification */ ++ ca_crc32 = crc32(0, (unsigned char *)buffer, EN8811H_MD32_DM_SIZE); ++ debug("DM crc32: 0x%x\n", ca_crc32); ++ ++ /* Load DSP firmware */ ++ ret = fs_set_blk_dev("mmc", fw_part, FS_TYPE_ANY); ++ if (ret < 0) ++ goto err_free; ++ ++ /* Read DSP firmware file into buffer after DM section */ ++ ret = fs_read(fw_dsp, (ulong)buffer + EN8811H_MD32_DM_SIZE, 0, ++ EN8811H_MD32_DSP_SIZE, &read); ++ if (ret < 0) { ++ printf("Failed to read DSP firmware: %s\n", fw_dsp); ++ goto err_free; ++ } ++ ++ /* Calculate CRC32 of DSP firmware for verification */ ++ ca_crc32 = crc32(0, (unsigned char *)buffer + EN8811H_MD32_DM_SIZE, ++ EN8811H_MD32_DSP_SIZE); ++ debug("DSP crc32: 0x%x\n", ca_crc32); ++ ++ *addr = buffer; ++ debug("Found Airoha Firmware.\n"); ++ ++ return 0; ++ ++err_free: ++ free(buffer); ++ return ret; ++} ++ ++static int en8811h_load_firmware(struct phy_device *phydev) ++{ ++ struct en8811h_priv *priv = phydev->priv; ++ void *buffer = NULL; ++ int ret; ++ ++ if (!IS_ENABLED(CONFIG_PHY_AIROHA_FW_IN_MMC)) { ++ printf("Airoha EN8811H firmware loading not implemented\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ ret = en8811h_read_fw(&buffer); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ EN8811H_FW_CTRL_1_START); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, ++ EN8811H_FW_CTRL_2_LOADING); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_write_buf(phydev, AIR_FW_ADDR_DM, EN8811H_MD32_DM_SIZE, ++ (unsigned char *)buffer); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, EN8811H_MD32_DSP_SIZE, ++ (unsigned char *)buffer + EN8811H_MD32_DM_SIZE); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, ++ EN8811H_FW_CTRL_2_LOADING, 0); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ EN8811H_FW_CTRL_1_FINISH); ++ if (ret < 0) ++ goto en8811h_load_firmware_out; ++ ++ ret = en8811h_wait_mcu_ready(phydev); ++ ++ air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, ++ &priv->firmware_version); ++ printf("MD32 firmware version: %08x\n", ++ priv->firmware_version); ++ ++en8811h_load_firmware_out: ++ free(buffer); ++ if (ret < 0) ++ printf("Firmware loading failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int en8811h_restart_mcu(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_write_mmd(phydev, 0x1e, 0x8009, 0x0); ++ if (ret < 0) ++ return ret; ++ ++ ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ EN8811H_FW_CTRL_1_START); ++ if (ret < 0) ++ return ret; ++ ++ return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, ++ EN8811H_FW_CTRL_1_FINISH); ++} ++ ++static int air_led_hw_control_set(struct phy_device *phydev, u8 index, ++ unsigned long rules) ++{ ++ struct en8811h_priv *priv = phydev->priv; ++ u16 on = 0, blink = 0; ++ int ret; ++ ++ if (index >= EN8811H_LED_COUNT) ++ return -EINVAL; ++ ++ priv->led[index].rules = rules; ++ ++ if (rules & BIT(AIR_TRIGGER_NETDEV_FULL_DUPLEX)) ++ on |= AIR_PHY_LED_ON_FDX; ++ ++ if (rules & (BIT(AIR_TRIGGER_NETDEV_LINK_10) | BIT(AIR_TRIGGER_NETDEV_LINK))) ++ on |= AIR_PHY_LED_ON_LINK10; ++ ++ if (rules & (BIT(AIR_TRIGGER_NETDEV_LINK_100) | BIT(AIR_TRIGGER_NETDEV_LINK))) ++ on |= AIR_PHY_LED_ON_LINK100; ++ ++ if (rules & (BIT(AIR_TRIGGER_NETDEV_LINK_1000) | BIT(AIR_TRIGGER_NETDEV_LINK))) ++ on |= AIR_PHY_LED_ON_LINK1000; ++ ++ if (rules & (BIT(AIR_TRIGGER_NETDEV_LINK_2500) | BIT(AIR_TRIGGER_NETDEV_LINK))) ++ on |= AIR_PHY_LED_ON_LINK2500; ++ ++ if (rules & BIT(AIR_TRIGGER_NETDEV_RX)) { ++ blink |= AIR_PHY_LED_BLINK_10RX | ++ AIR_PHY_LED_BLINK_100RX | ++ AIR_PHY_LED_BLINK_1000RX | ++ AIR_PHY_LED_BLINK_2500RX; ++ } ++ ++ if (rules & BIT(AIR_TRIGGER_NETDEV_TX)) { ++ blink |= AIR_PHY_LED_BLINK_10TX | ++ AIR_PHY_LED_BLINK_100TX | ++ AIR_PHY_LED_BLINK_1000TX | ++ AIR_PHY_LED_BLINK_2500TX; ++ } ++ ++ if (blink || on) { ++ /* switch hw-control on, so led-on and led-blink are off */ ++ clear_bit(AIR_PHY_LED_STATE_FORCE_ON, ++ &priv->led[index].state); ++ clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK, ++ &priv->led[index].state); ++ } else { ++ priv->led[index].rules = 0; ++ } ++ ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index), ++ AIR_PHY_LED_ON_MASK, on); ++ ++ if (ret < 0) ++ return ret; ++ ++ return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index), ++ blink); ++}; ++ ++static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol) ++{ ++ int val = 0; ++ int err; ++ ++ if (index >= EN8811H_LED_COUNT) ++ return -EINVAL; ++ ++ if (state == AIR_LED_ENABLE) ++ val |= AIR_PHY_LED_ON_ENABLE; ++ else ++ val &= ~AIR_PHY_LED_ON_ENABLE; ++ ++ if (pol == AIR_ACTIVE_HIGH) ++ val |= AIR_PHY_LED_ON_POLARITY; ++ else ++ val &= ~AIR_PHY_LED_ON_POLARITY; ++ ++ err = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_ON(index), val); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int air_leds_init(struct phy_device *phydev, int num, u16 dur, int mode) ++{ ++ struct en8811h_priv *priv = phydev->priv; ++ int ret, i; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK, ++ dur); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_ON, ++ dur >> 1); ++ if (ret < 0) ++ return ret; ++ ++ switch (mode) { ++ case AIR_LED_MODE_DISABLE: ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_MODE_MASK, 0); ++ break; ++ case AIR_LED_MODE_USER_DEFINE: ++ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN, ++ AIR_PHY_LED_BCR_EXT_CTRL | ++ AIR_PHY_LED_BCR_CLK_EN); ++ if (ret < 0) ++ return ret; ++ break; ++ default: ++ printf("LED mode %d is not supported\n", mode); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < num; ++i) { ++ ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH); ++ if (ret < 0) { ++ printf("LED%d init failed: %d\n", i, ret); ++ return ret; ++ } ++ air_led_hw_control_set(phydev, i, priv->led[i].rules); ++ } ++ ++ return 0; ++} ++ ++static int en8811h_config(struct phy_device *phydev) ++{ ++ struct en8811h_priv *priv = phydev->priv; ++ ofnode node = phy_get_ofnode(phydev); ++ u32 pbus_value = 0; ++ int ret = 0; ++ ++ /* If restart happened in .probe(), no need to restart now */ ++ if (priv->mcu_needs_restart) { ++ ret = en8811h_restart_mcu(phydev); ++ if (ret < 0) ++ return ret; ++ } else { ++ ret = en8811h_load_firmware(phydev); ++ if (ret) { ++ printf("Load firmware fail.\n"); ++ return ret; ++ } ++ /* Next calls to .config() mcu needs to restart */ ++ priv->mcu_needs_restart = true; ++ } ++ ++ ret = phy_write_mmd(phydev, 0x1e, 0x800c, 0x0); ++ if (ret < 0) ++ return ret; ++ ret = phy_write_mmd(phydev, 0x1e, 0x800d, 0x0); ++ if (ret < 0) ++ return ret; ++ ret = phy_write_mmd(phydev, 0x1e, 0x800e, 0x1101); ++ if (ret < 0) ++ return ret; ++ ret = phy_write_mmd(phydev, 0x1e, 0x800f, 0x0002); ++ if (ret < 0) ++ return ret; ++ ++ /* Serdes polarity */ ++ pbus_value = 0; ++ if (ofnode_read_bool(node, "airoha,pnswap-rx")) ++ pbus_value |= EN8811H_POLARITY_RX_REVERSE; ++ else ++ pbus_value &= ~EN8811H_POLARITY_RX_REVERSE; ++ if (ofnode_read_bool(node, "airoha,pnswap-tx")) ++ pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; ++ else ++ pbus_value |= EN8811H_POLARITY_TX_NORMAL; ++ ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, ++ EN8811H_POLARITY_RX_REVERSE | ++ EN8811H_POLARITY_TX_NORMAL, pbus_value); ++ if (ret < 0) ++ return ret; ++ ++ ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR, ++ AIR_LED_MODE_USER_DEFINE); ++ if (ret < 0) { ++ printf("Failed to disable leds: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int en8811h_parse_status(struct phy_device *phydev) ++{ ++ int ret = 0, reg_value; ++ ++ phydev->duplex = DUPLEX_FULL; ++ ++ reg_value = phy_read(phydev, MDIO_DEVAD_NONE, AIR_AUX_CTRL_STATUS); ++ if (reg_value < 0) ++ return reg_value; ++ ++ switch (reg_value & AIR_AUX_CTRL_STATUS_SPEED_MASK) { ++ case AIR_AUX_CTRL_STATUS_SPEED_2500: ++ phydev->speed = SPEED_2500; ++ break; ++ case AIR_AUX_CTRL_STATUS_SPEED_1000: ++ phydev->speed = SPEED_1000; ++ break; ++ case AIR_AUX_CTRL_STATUS_SPEED_100: ++ phydev->speed = SPEED_100; ++ break; ++ default: ++ printf("Auto-neg error, defaulting to 100M/FD\n"); ++ phydev->speed = SPEED_100; ++ break; ++ } ++ ++ return ret; ++} ++ ++static int en8811h_startup(struct phy_device *phydev) ++{ ++ int ret = 0; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ return en8811h_parse_status(phydev); ++} ++ ++static int en8811h_probe(struct phy_device *phydev) ++{ ++ struct en8811h_priv *priv; ++ ++ priv = malloc(sizeof(*priv)); ++ if (!priv) ++ return -ENOMEM; ++ memset(priv, 0, sizeof(*priv)); ++ ++ priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0; ++ priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1; ++ priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2; ++ ++ /* mcu has just restarted after firmware load */ ++ priv->mcu_needs_restart = false; ++ ++ phydev->priv = priv; ++ ++ return 0; ++} ++ ++U_BOOT_PHY_DRIVER(en8811h) = { ++ .name = "Airoha EN8811H", ++ .uid = EN8811H_PHY_ID, ++ .mask = 0x0ffffff0, ++ .config = &en8811h_config, ++ .probe = &en8811h_probe, ++ .startup = &en8811h_startup, ++ .shutdown = &genphy_shutdown, ++}; +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0006-Add-bpi-r3-mini-device-tree.patch b/patches/uboot/2026.01/0006-Add-bpi-r3-mini-device-tree.patch new file mode 100644 index 000000000..4dfeedbad --- /dev/null +++ b/patches/uboot/2026.01/0006-Add-bpi-r3-mini-device-tree.patch @@ -0,0 +1,272 @@ +From 3ba908cf4b16d729f611f64c20568baa47cf0a31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= +Date: Wed, 18 Feb 2026 17:00:42 +0100 +Subject: [PATCH 06/10] Add bpi-r3-mini device tree +Organization: Wires + +Signed-off-by: Joachim Wiberg +--- + arch/arm/dts/Makefile | 1 + + arch/arm/dts/mt7986a-bpi-r3-mini.dts | 238 +++++++++++++++++++++++++++ + 2 files changed, 239 insertions(+) + create mode 100644 arch/arm/dts/mt7986a-bpi-r3-mini.dts + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +index fcad6fb2fc7..d4255f95702 100644 +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -1125,6 +1125,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt7981-sd-rfb.dtb \ + mt7986a-bpi-r3-sd.dtb \ + mt7986a-bpi-r3-emmc.dtb \ ++ mt7986a-bpi-r3-mini.dtb \ + mt7986a-rfb.dtb \ + mt7986b-rfb.dtb \ + mt7986a-sd-rfb.dtb \ +diff --git a/arch/arm/dts/mt7986a-bpi-r3-mini.dts b/arch/arm/dts/mt7986a-bpi-r3-mini.dts +new file mode 100644 +index 00000000000..469b087fb0c +--- /dev/null ++++ b/arch/arm/dts/mt7986a-bpi-r3-mini.dts +@@ -0,0 +1,238 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/dts-v1/; ++#include "mt7986.dtsi" ++#include ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ model = "Bananapi BPi-R3 Mini"; ++ compatible = "mediatek,mt7986", "mediatek,mt7986-rfb"; ++ ++ chosen { ++ stdout-path = &uart0; ++ tick-timer = &timer0; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0x40000000 0x80000000>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ button-reset { ++ label = "reset"; ++ linux,code = ; ++ gpios = <&pio 7 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ status_led: led-0 { ++ label = "green:status"; ++ gpios = <&pio 19 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-1 { ++ label = "blue:wlan2g"; ++ gpios = <&pio 1 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-2 { ++ label = "blue:wlan5g"; ++ gpios = <&pio 2 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++ð { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mdio_pins>; ++ ++ mediatek,gmac-id = <0>; ++ phy-mode = "2500base-x"; ++ phy-handle = <&phy14>; ++ ++ phy14: eth-phy@e { ++ compatible = "ethernet-phy-id03a2.a411"; ++ reg = <14>; ++ ++ airoha,pnswap-rx; ++ ++ reset-gpios = <&pio 49 GPIO_ACTIVE_LOW>; ++ reset-assert-us = <10000>; ++ reset-deassert-us = <20000>; ++ }; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ bus-width = <8>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ cap-mmc-hw-reset; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_1p8v>; ++ non-removable; ++ status = "okay"; ++}; ++ ++&pio { ++ mdio_pins: mdio-pins { ++ mux { ++ function = "eth"; ++ groups = "mdc_mdio"; ++ }; ++ ++ conf-en8811-pwr-a { ++ pins = "GPIO_11"; ++ drive-strength = ; ++ bias-pull-down = ; ++ output-low; ++ }; ++ ++ conf-en8811-pwr-b { ++ pins = "GPIO_12"; ++ drive-strength = ; ++ bias-pull-down = ; ++ output-low; ++ }; ++ }; ++ ++ mmc0_pins_default: mmc0default { ++ mux { ++ function = "flash"; ++ groups = "emmc_51"; ++ }; ++ ++ conf-cmd-dat { ++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", ++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", ++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; ++ input-enable; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-clk { ++ pins = "EMMC_CK"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ ++ conf-dsl { ++ pins = "EMMC_DSL"; ++ bias-pull-down = ; ++ }; ++ ++ conf-rst { ++ pins = "EMMC_RSTB"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ }; ++ ++ spi_flash_pins: spi0-pins-func-1 { ++ mux { ++ function = "flash"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ ++ conf-pu { ++ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; ++ drive-strength = ; ++ bias-pull-up = ; ++ }; ++ ++ conf-pd { ++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; ++ drive-strength = ; ++ bias-pull-down = ; ++ }; ++ }; ++ ++ pwm_pins: pwm0-pins-func-1 { ++ mux { ++ function = "pwm"; ++ groups = "pwm0"; ++ }; ++ }; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ ++&spi0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi_flash_pins>; ++ status = "okay"; ++ must_tx; ++ enhance_timing; ++ dma_ext; ++ ipm_design; ++ support_quad; ++ tick_dly = <1>; ++ sample_sel = <0>; ++ ++ spi_nand@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <20000000>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x200000>; ++ }; ++ ++ partition@200000 { ++ label = "ubi"; ++ reg = <0x200000 0x7e00000>; ++ }; ++ }; ++ }; ++ ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&watchdog { ++ status = "disabled"; ++}; +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0007-bpi-r3-r4-Add-probe-for-specific-model.patch b/patches/uboot/2026.01/0007-bpi-r3-r4-Add-probe-for-specific-model.patch new file mode 100644 index 000000000..fe1eb8306 --- /dev/null +++ b/patches/uboot/2026.01/0007-bpi-r3-r4-Add-probe-for-specific-model.patch @@ -0,0 +1,559 @@ +From a1ac4c9c4e35782afcf66ab031b4d426d81120a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= +Date: Wed, 18 Feb 2026 17:02:23 +0100 +Subject: [PATCH 07/10] bpi-r3/r4: Add probe for specific model +Organization: Wires + +Probe for bpi-r3 and bpi-r3-mini and select correct device tree, +prepare for bpi-r4 (not supported yet, but soon), for bpi-r3, +look if there are phys connected, if so it is a mini, else it is +regular bpi-r3. + +Signed-off-by: Joachim Wiberg +--- + arch/arm/mach-mediatek/Kconfig | 3 + + board/mediatek/mt7986/Kconfig | 10 ++ + board/mediatek/mt7986/Makefile | 1 + + board/mediatek/mt7986/bpir3.c | 229 +++++++++++++++++++++++++++ + board/mediatek/mt7988/Kconfig | 9 ++ + board/mediatek/mt7988/Makefile | 1 + + board/mediatek/mt7988/bpir4.c | 33 ++++ + configs/mt7986a_bpir3_emmc_defconfig | 2 + + configs/mt7986a_bpir3_mini_defconfig | 66 ++++++++ + configs/mt7986a_bpir3_sd_defconfig | 2 + + configs/mt7988a_bpir4_defconfig | 85 ++++++++++ + 11 files changed, 441 insertions(+) + create mode 100644 board/mediatek/mt7986/Kconfig + create mode 100644 board/mediatek/mt7986/bpir3.c + create mode 100644 board/mediatek/mt7988/Kconfig + create mode 100644 board/mediatek/mt7988/bpir4.c + create mode 100644 configs/mt7986a_bpir3_mini_defconfig + create mode 100644 configs/mt7988a_bpir4_defconfig + +diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig +index e54c456aec0..ca593cceb43 100644 +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -165,4 +165,7 @@ config MTK_TZ_MOVABLE + select OF_SYSTEM_SETUP + bool + ++source "board/mediatek/mt7986/Kconfig" ++source "board/mediatek/mt7988/Kconfig" ++ + endif +diff --git a/board/mediatek/mt7986/Kconfig b/board/mediatek/mt7986/Kconfig +new file mode 100644 +index 00000000000..cea150b52d8 +--- /dev/null ++++ b/board/mediatek/mt7986/Kconfig +@@ -0,0 +1,10 @@ ++if TARGET_MT7986 ++ ++config BOARD_BPI_R3 ++ bool "BananaPi BPI-R3 / BPI-R3-mini board support" ++ select BOARD_LATE_INIT ++ help ++ Enable runtime variant detection for BananaPi BPI-R3 and BPI-R3-mini, ++ selecting the correct device tree from a FIT image. ++ ++endif +diff --git a/board/mediatek/mt7986/Makefile b/board/mediatek/mt7986/Makefile +index 7bb84fa2f4e..b006ee150bd 100644 +--- a/board/mediatek/mt7986/Makefile ++++ b/board/mediatek/mt7986/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-y += mt7986_rfb.o ++obj-$(CONFIG_BOARD_BPI_R3) += bpir3.o +diff --git a/board/mediatek/mt7986/bpir3.c b/board/mediatek/mt7986/bpir3.c +new file mode 100644 +index 00000000000..01eef55bb74 +--- /dev/null ++++ b/board/mediatek/mt7986/bpir3.c +@@ -0,0 +1,229 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * BPI-R3 / BPI-R3-mini board variant detection ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++enum bpir3_variant { ++ BPIR3, ++ BPIR3_MINI, ++}; ++ ++/* ++ * Detect BPI-R3 vs BPI-R3-mini by probing for the Airoha EN8811H PHY. ++ * ++ * BPI-R3-mini: EN8811H is directly on the MDIO bus at addr 14. ++ * GPIO49 (active-low) is its reset; PHYSID1 = 0x03a2. ++ * BPI-R3: MT7531AE switch via SGMII; nothing at MDIO addr 14 → 0xffff. ++ * ++ * NOTE: I2C 0x50 is NOT usable — BPI-R3 SFP cage EEPROMs occupy 0x50–0x5b. ++ */ ++ ++/* ++ * MT7986 GPIO — gpio_base = 0x1001f000 ++ * ++ * DIR register: base + 0x000 + (pin/32)*0x10, 1 bit/pin (1=output) ++ * DOUT register: base + 0x100 + (pin/32)*0x10, 1 bit/pin ++ * MODE register: base + 0x300 + (pin*4/32)*0x10, 4 bits/pin (0=GPIO, 1=eth…) ++ */ ++#define MT7986_GPIO_BASE 0x1001f000UL ++#define GPIO_DIR_REG(p) (MT7986_GPIO_BASE + 0x000 + ((p) / 32) * 0x10) ++#define GPIO_DOUT_REG(p) (MT7986_GPIO_BASE + 0x100 + ((p) / 32) * 0x10) ++#define GPIO_MODE_REG(p) (MT7986_GPIO_BASE + 0x300 + (((p) * 4) / 32) * 0x10) ++#define GPIO_MODE_SHIFT(p) (((p) * 4) % 32) ++ ++/* EN8811H PHY reset: GPIO49, active-low */ ++#define EN8811H_RST_GPIO 49 ++/* EN8811H power control lines: active-low enables on some BPI-R3-mini dts */ ++#define EN8811H_PWR_A_GPIO 11 ++#define EN8811H_PWR_B_GPIO 12 ++/* Alternative EN8811H power control lines used by other mini trees */ ++#define EN8811H_PWR2_A_GPIO 16 ++#define EN8811H_PWR2_B_GPIO 17 ++ ++/* MDC/MDIO pins: GPIO67 = MDC, GPIO68 = MDIO, both on function 1 ("eth") */ ++#define MDC_GPIO 67 ++#define MDIO_GPIO 68 ++ ++/* ++ * MT7986 Frame Engine: ethernet@15100000, GMAC at +0x10000 ++ * ++ * PPSC (+0x0000): MDC clock config — bits[29:24] = divider, bit[4] = turbo ++ * PIAC (+0x0004): PHY indirect access — write then poll PHY_ACS_ST clear ++ */ ++#define GMAC_BASE 0x15110000UL ++#define GMAC_PPSC (GMAC_BASE + 0x0000) ++#define GMAC_PIAC (GMAC_BASE + 0x0004) ++ ++#define PPSC_MDC_CFG_MASK GENMASK(29, 24) ++#define PPSC_MDC_CFG(d) (((d) & 0x3f) << 24) ++#define PPSC_MDC_TURBO BIT(4) ++/* divider = 10 → MDC ≈ 2.5 MHz from 25 MHz reference */ ++#define MDC_DIVIDER 10 ++ ++#define PIAC_ACS_ST BIT(31) ++#define PIAC_REG_S 25 ++#define PIAC_PHY_S 20 ++#define PIAC_CMD_S 18 ++#define PIAC_ST_S 16 ++#define PIAC_DATA_MASK 0xffffU ++#define PIAC_CMD_READ 2 ++#define PIAC_ST_C22 1 ++ ++/* EN8811H PHY ID register values */ ++#define EN8811H_PHYSID1 0x03a2 ++#define EN8811H_PHYSID2_MASK 0xfff0 ++#define EN8811H_PHYSID2 0xa410 ++#define MII_PHYSID1 0x02 /* IEEE MII register 2 */ ++#define MII_PHYSID2 0x03 /* IEEE MII register 3 */ ++ ++/* Set a GPIO pin's mode field (0 = GPIO, 1 = eth function, …) */ ++static void gpio_set_mode(unsigned int pin, unsigned int func) ++{ ++ clrsetbits_le32(GPIO_MODE_REG(pin), ++ 0xf << GPIO_MODE_SHIFT(pin), ++ (func & 0xf) << GPIO_MODE_SHIFT(pin)); ++} ++ ++/* Configure a GPIO pin as output and drive it high or low */ ++static void gpio_out(unsigned int pin, int val) ++{ ++ setbits_le32(GPIO_DIR_REG(pin), BIT(pin % 32)); ++ if (val) ++ setbits_le32(GPIO_DOUT_REG(pin), BIT(pin % 32)); ++ else ++ clrbits_le32(GPIO_DOUT_REG(pin), BIT(pin % 32)); ++} ++ ++/* ++ * Clause-22 MDIO read via the MT7986 GMAC PHY indirect access register. ++ * Returns the 16-bit register value, or -1 on timeout. ++ */ ++static int mdio_read_c22(unsigned int phy, unsigned int reg) ++{ ++ u32 val; ++ int i; ++ ++ val = (PIAC_ST_C22 << PIAC_ST_S) | ++ (PIAC_CMD_READ << PIAC_CMD_S) | ++ (phy << PIAC_PHY_S) | ++ (reg << PIAC_REG_S); ++ writel(val | PIAC_ACS_ST, GMAC_PIAC); ++ ++ for (i = 0; i < 5000; i++) { ++ val = readl(GMAC_PIAC); ++ if (!(val & PIAC_ACS_ST)) ++ return (int)(val & PIAC_DATA_MASK); ++ udelay(1); ++ } ++ ++ return -1; /* timeout */ ++} ++ ++static void enable_mini_power_lines(unsigned int gpio_a, unsigned int gpio_b) ++{ ++ gpio_set_mode(gpio_a, 0); /* mode 0 = GPIO */ ++ gpio_set_mode(gpio_b, 0); /* mode 0 = GPIO */ ++ gpio_out(gpio_a, 0); /* active-low enable */ ++ gpio_out(gpio_b, 0); /* active-low enable */ ++} ++ ++static void pulse_mini_phy_reset(void) ++{ ++ gpio_set_mode(EN8811H_RST_GPIO, 0); /* mode 0 = GPIO */ ++ gpio_out(EN8811H_RST_GPIO, 0); /* assert reset */ ++ mdelay(10); ++ gpio_out(EN8811H_RST_GPIO, 1); /* deassert reset */ ++ mdelay(20); ++} ++ ++static bool is_en8811_id(int id1, int id2) ++{ ++ return id1 == EN8811H_PHYSID1 && ++ (id2 & EN8811H_PHYSID2_MASK) == EN8811H_PHYSID2; ++} ++ ++static int probe_en8811_addr(unsigned int phy_addr) ++{ ++ int id1, id2; ++ ++ id1 = mdio_read_c22(phy_addr, MII_PHYSID1); ++ id2 = mdio_read_c22(phy_addr, MII_PHYSID2); ++ ++ if (id1 < 0 || id2 < 0) ++ return 0; ++ ++ return is_en8811_id(id1, id2); ++} ++ ++static enum bpir3_variant detect_bpir3_variant(void) ++{ ++ unsigned int pwr_a[] = { EN8811H_PWR_A_GPIO, EN8811H_PWR2_A_GPIO }; ++ unsigned int pwr_b[] = { EN8811H_PWR_B_GPIO, EN8811H_PWR2_B_GPIO }; ++ unsigned int i; ++ ++ /* Switch GPIO67 (MDC) and GPIO68 (MDIO) to eth function */ ++ gpio_set_mode(MDC_GPIO, 1); ++ gpio_set_mode(MDIO_GPIO, 1); ++ ++ /* Configure MDC clock: enable turbo + set safe divider (~2.5 MHz) */ ++ setbits_le32(GMAC_PPSC, PPSC_MDC_TURBO); ++ clrsetbits_le32(GMAC_PPSC, PPSC_MDC_CFG_MASK, PPSC_MDC_CFG(MDC_DIVIDER)); ++ ++ /* ++ * Enable EN8811H power rails and probe; some mini boards use ++ * GPIO11/12, others GPIO16/17. ++ */ ++ for (i = 0; i < ARRAY_SIZE(pwr_a); i++) { ++ enable_mini_power_lines(pwr_a[i], pwr_b[i]); ++ pulse_mini_phy_reset(); ++ ++ if (probe_en8811_addr(14) || probe_en8811_addr(15)) { ++ /* Assert reset; DM eth-phy will deassert with proper delays */ ++ gpio_out(EN8811H_RST_GPIO, 0); ++ return BPIR3_MINI; ++ } ++ } ++ ++ return BPIR3; ++} ++ ++int board_fit_config_name_match(const char *name) ++{ ++ static int variant = -1; ++ ++ if (variant < 0) ++ variant = detect_bpir3_variant(); ++ ++ switch (variant) { ++ case BPIR3_MINI: ++ return strcmp(name, "mt7986a-bpi-r3-mini") ? -1 : 0; ++ case BPIR3: ++ default: ++ /* ++ * Accept both sd and emmc variants of BPI-R3; ++ * storage type is determined by spl_boot_device(), not here. ++ */ ++ return (strcmp(name, "mt7986a-bpi-r3-sd") == 0 || ++ strcmp(name, "mt7986a-bpi-r3-emmc") == 0) ? 0 : -1; ++ } ++} ++ ++int board_late_init(void) ++{ ++ const char *model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); ++ ++ if (model && strstr(model, "Mini")) ++ env_set("fdtfile", "mediatek/mt7986a-bananapi-bpi-r3-mini.dtb"); ++ ++ return 0; ++} +diff --git a/board/mediatek/mt7988/Kconfig b/board/mediatek/mt7988/Kconfig +new file mode 100644 +index 00000000000..24c70417ec5 +--- /dev/null ++++ b/board/mediatek/mt7988/Kconfig +@@ -0,0 +1,9 @@ ++if TARGET_MT7988 ++ ++config BOARD_BPI_R4 ++ bool "BananaPi BPI-R4 / BPI-R4-2g5 board support" ++ help ++ Enable runtime variant detection for BananaPi BPI-R4 and BPI-R4-2g5, ++ selecting the correct device tree from a FIT image. ++ ++endif +diff --git a/board/mediatek/mt7988/Makefile b/board/mediatek/mt7988/Makefile +index f1249ab3715..157ee371eae 100644 +--- a/board/mediatek/mt7988/Makefile ++++ b/board/mediatek/mt7988/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0 + + obj-y += mt7988_rfb.o ++obj-$(CONFIG_BOARD_BPI_R4) += bpir4.o +diff --git a/board/mediatek/mt7988/bpir4.c b/board/mediatek/mt7988/bpir4.c +new file mode 100644 +index 00000000000..46e22d38135 +--- /dev/null ++++ b/board/mediatek/mt7988/bpir4.c +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * BPI-R4 / BPI-R4-2g5 board variant detection ++ */ ++ ++#include ++#include ++ ++enum bpir4_variant { ++ BPIR4, ++ BPIR4_2G5, ++}; ++ ++/* ++ * Detect which BPI-R4 variant this board is. ++ * TODO: implement real hardware detection ++ */ ++static enum bpir4_variant detect_bpir4_variant(void) ++{ ++ /* Stub: always report BPI-R4 */ ++ return BPIR4; ++} ++ ++int board_fit_config_name_match(const char *name) ++{ ++ switch (detect_bpir4_variant()) { ++ case BPIR4_2G5: ++ return strcmp(name, "mt7988a-bananapi-bpi-r4-2g5") ? -1 : 0; ++ case BPIR4: ++ default: ++ return strcmp(name, "mt7988a-bananapi-bpi-r4") ? -1 : 0; ++ } ++} +diff --git a/configs/mt7986a_bpir3_emmc_defconfig b/configs/mt7986a_bpir3_emmc_defconfig +index 153c1934bd0..2f9baa723ff 100644 +--- a/configs/mt7986a_bpir3_emmc_defconfig ++++ b/configs/mt7986a_bpir3_emmc_defconfig +@@ -9,6 +9,8 @@ CONFIG_ENV_SIZE=0x80000 + CONFIG_ENV_OFFSET=0x300000 + CONFIG_DEFAULT_DEVICE_TREE="mt7986a-bpi-r3-emmc" + CONFIG_TARGET_MT7986=y ++CONFIG_BOARD_BPI_R3=y ++CONFIG_SPL_LOAD_FIT=y + CONFIG_SYS_LOAD_ADDR=0x46000000 + CONFIG_DEBUG_UART_BASE=0x11002000 + CONFIG_DEBUG_UART_CLOCK=40000000 +diff --git a/configs/mt7986a_bpir3_mini_defconfig b/configs/mt7986a_bpir3_mini_defconfig +new file mode 100644 +index 00000000000..39e44555c55 +--- /dev/null ++++ b/configs/mt7986a_bpir3_mini_defconfig +@@ -0,0 +1,66 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_ENV_SIZE=0x80000 ++CONFIG_ENV_OFFSET=0x300000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7986a-bpi-r3-mini" ++CONFIG_TARGET_MT7986=y ++CONFIG_BOARD_BPI_R3=y ++CONFIG_SPL_LOAD_FIT=y ++CONFIG_SYS_LOAD_ADDR=0x46000000 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=40000000 ++CONFIG_DEBUG_UART=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7986a-bpi-r3-mini" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R3> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_UNLZ4 is not set ++# CONFIG_CMD_UNZIP is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_GPT_RENAME=y ++CONFIG_CMD_LSBLK=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_PHY_FIXED=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7986=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_FAT_WRITE=y ++CONFIG_HEXDUMP=y +diff --git a/configs/mt7986a_bpir3_sd_defconfig b/configs/mt7986a_bpir3_sd_defconfig +index ad9711da614..fc4d5d91fbc 100644 +--- a/configs/mt7986a_bpir3_sd_defconfig ++++ b/configs/mt7986a_bpir3_sd_defconfig +@@ -9,6 +9,8 @@ CONFIG_ENV_SIZE=0x80000 + CONFIG_ENV_OFFSET=0x300000 + CONFIG_DEFAULT_DEVICE_TREE="mt7986a-bpi-r3-sd" + CONFIG_TARGET_MT7986=y ++CONFIG_BOARD_BPI_R3=y ++CONFIG_SPL_LOAD_FIT=y + CONFIG_SYS_LOAD_ADDR=0x46000000 + CONFIG_DEBUG_UART_BASE=0x11002000 + CONFIG_DEBUG_UART_CLOCK=40000000 +diff --git a/configs/mt7988a_bpir4_defconfig b/configs/mt7988a_bpir4_defconfig +new file mode 100644 +index 00000000000..e2e128ec29d +--- /dev/null ++++ b/configs/mt7988a_bpir4_defconfig +@@ -0,0 +1,85 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEFAULT_DEVICE_TREE="mt7988a-bananapi-bpi-r4" ++CONFIG_TARGET_MT7988=y ++CONFIG_BOARD_BPI_R4=y ++CONFIG_SPL_LOAD_FIT=y ++CONFIG_SYS_LOAD_ADDR=0x46000000 ++CONFIG_DEBUG_UART_BASE=0x11000000 ++CONFIG_DEBUG_UART_CLOCK=40000000 ++CONFIG_DEBUG_UART=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7988a-bananapi-bpi-r4" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R4> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++CONFIG_CMD_CLK=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_SMC=y ++CONFIG_DOS_PARTITION=y ++CONFIG_EFI_PARTITION=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_USE_IPADDR=y ++CONFIG_IPADDR="192.168.1.1" ++CONFIG_USE_NETMASK=y ++CONFIG_NETMASK="255.255.255.0" ++CONFIG_USE_SERVERIP=y ++CONFIG_SERVERIP="192.168.1.2" ++CONFIG_PROT_TCP=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_MTD=y ++CONFIG_DM_MTD=y ++CONFIG_MTD_SPI_NAND=y ++CONFIG_DM_SPI_FLASH=y ++CONFIG_SPI_FLASH_SFDP_SUPPORT=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_XMC=y ++CONFIG_SPI_FLASH_XTX=y ++CONFIG_SPI_FLASH_MTD=y ++CONFIG_PHY_FIXED=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7988=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_PWM=y ++CONFIG_PWM_MTK=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SPIM=y ++CONFIG_LZO=y ++CONFIG_HEXDUMP=y +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0008-arm-mediatek-fix-MT7622-BROM-image-header-type.patch b/patches/uboot/2026.01/0008-arm-mediatek-fix-MT7622-BROM-image-header-type.patch new file mode 100644 index 000000000..7847b04b1 --- /dev/null +++ b/patches/uboot/2026.01/0008-arm-mediatek-fix-MT7622-BROM-image-header-type.patch @@ -0,0 +1,34 @@ +From e09f64e56b1f10dd4ad6f066b6c05a604daf80e5 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Thu, 26 Feb 2026 11:22:28 +0100 +Subject: [PATCH 08/10] arm: mediatek: fix MT7622 BROM image header type +Organization: Wires + +The LK image header for MT7622 was inadvertently changed to "media=nor" +when board Kconfigs were merged into mach-mediatek/Kconfig. MT7622 uses +the same ATF/LK-based boot flow as MT7623 and requires "lk=1" so that +mkimage generates the correct header for the BROM to accept. + +Reported-by: Shiji Yang +Signed-off-by: Joachim Wiberg +--- + arch/arm/mach-mediatek/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig +index ca593cceb43..59d678b7a08 100644 +--- a/arch/arm/mach-mediatek/Kconfig ++++ b/arch/arm/mach-mediatek/Kconfig +@@ -158,7 +158,8 @@ config MTK_BROM_HEADER_INFO + string + default "media=nor" if TARGET_MT8518 || TARGET_MT8512 || TARGET_MT7629 + default "media=emmc" if TARGET_MT8516 || TARGET_MT8365 || TARGET_MT8183 +- default "lk=1" if TARGET_MT7623 ++ default "media=snand;nandinfo=2k+64" if TARGET_MT7981 || TARGET_MT7986 || TARGET_MT7988 ++ default "lk=1" if TARGET_MT7622 || TARGET_MT7623 + + config MTK_TZ_MOVABLE + select ARCH_MISC_INIT +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0009-arm-mediatek-add-BananaPi-BPI-R64-MT7622-defconfigs.patch b/patches/uboot/2026.01/0009-arm-mediatek-add-BananaPi-BPI-R64-MT7622-defconfigs.patch new file mode 100644 index 000000000..d7158a2f7 --- /dev/null +++ b/patches/uboot/2026.01/0009-arm-mediatek-add-BananaPi-BPI-R64-MT7622-defconfigs.patch @@ -0,0 +1,710 @@ +From 92ed8c8fbbacab3c2e98c65008b3c314f609fd00 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Thu, 26 Feb 2026 11:23:28 +0100 +Subject: [PATCH 09/10] arm: mediatek: add BananaPi BPI-R64 (MT7622) defconfigs +Organization: Wires + +Add U-Boot support for the BananaPi BPI-R64 router board, based on the +MediaTek MT7622 SoC (dual-core ARM Cortex-A53, 64-bit). Three defconfigs +are provided, following the BPI-R3 pattern: + + mt7622_bpir64_emmc_defconfig - eMMC (mmc0), env at 4 MiB + mt7622_bpir64_sd_defconfig - SD card (mmc1), env at 4 MiB + mt7622_bpir64_snand_defconfig - SPI NAND via SNFI, env in UBI + +All variants include PCIe, USB3 (xHCI + T-PHY), Ethernet (MT7531 switch +via SGMII/2500base-x), GPIO-LEDs, and push-button support. + +The SNAND variant uses the upstream CONFIG_MTK_SNFI_SPI + MTD_SPI_NAND +path with a spi-nand child under &snfi, adapting OpenWRT patch 403 to +the upstream driver model (which has no separate &snand node or +CONFIG_MTK_SPI_NAND). NAND layout: bl2 at 0x0 (512 KiB), ubi for the +remainder of the flash. + +Also, add hardware description missing from the original device tree: + - ethernet0 alias for the MT7531 switch + - gpio-keys nodes for the reset (GPIO0) and WPS (GPIO102) buttons + - gpio-leds nodes for the green (GPIO89) and blue (GPIO85) LEDs + - Fix cap-sd-highspeed -> cap-mmc-highspeed on mmc0 (eMMC requires + the MMC-specific capability flag, not the SD one) + - Reduce mmc1 (SD card) max-frequency to 25 MHz for stability + +Sources: + OpenWRT patches 402-404/408 for package/boot/uboot-mediatek + https://git.infobricfleet.com/gtu/openwrt/-/tree/master/package/boot/uboot-mediatek/patches + Frank Wunderlich's initial MT7622/BPI-R64 U-Boot port (2019) + https://github.com/frank-w/u-boot/commit/c451ad3950e63d54b074f71e930459281dd3f594 + +Signed-off-by: Joachim Wiberg +--- + arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts | 290 ++++++++++++++++++ + arch/arm/dts/mt7622-bananapi-bpi-r64.dts | 38 ++- + board/mediatek/mt7622/MAINTAINERS | 5 + + configs/mt7622_bpir64_emmc_defconfig | 82 +++++ + configs/mt7622_bpir64_sd_defconfig | 82 +++++ + configs/mt7622_bpir64_snand_defconfig | 88 ++++++ + 6 files changed, 583 insertions(+), 2 deletions(-) + create mode 100644 arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts + create mode 100644 configs/mt7622_bpir64_emmc_defconfig + create mode 100644 configs/mt7622_bpir64_sd_defconfig + create mode 100644 configs/mt7622_bpir64_snand_defconfig + +diff --git a/arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts b/arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts +new file mode 100644 +index 00000000000..afdcb646f69 +--- /dev/null ++++ b/arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts +@@ -0,0 +1,290 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2019 MediaTek Inc. ++ * Author: Sam Shih ++ * ++ * BananaPi BPI-R64 - SPI NAND flash variant ++ */ ++ ++/dts-v1/; ++#include ++#include "mt7622.dtsi" ++#include "mt7622-u-boot.dtsi" ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ model = "mt7622-bpi-r64"; ++ compatible = "mediatek,mt7622", "mediatek,mt7622-rfb"; ++ chosen { ++ stdout-path = &uart0; ++ tick-timer = &timer0; ++ }; ++ ++ aliases { ++ spi0 = &snfi; ++ ethernet0 = ð ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0x40000000 0x40000000>; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ factory-reset { ++ label = "factory-reset"; ++ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ wps { ++ label = "wps"; ++ gpios = <&gpio 102 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ green { ++ label = "bpi-r64:pio:green"; ++ gpios = <&gpio 89 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ blue { ++ label = "bpi-r64:pio:blue"; ++ gpios = <&gpio 85 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>; ++ status = "okay"; ++ ++ pcie@0,0 { ++ status = "okay"; ++ }; ++ ++ pcie@1,0 { ++ status = "okay"; ++ }; ++}; ++ ++&pinctrl { ++ pcie0_pins: pcie0-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie0_pad_perst", ++ "pcie0_1_waken", ++ "pcie0_1_clkreq"; ++ }; ++ }; ++ ++ pcie1_pins: pcie1-pins { ++ mux { ++ function = "pcie"; ++ groups = "pcie1_pad_perst", ++ "pcie1_0_waken", ++ "pcie1_0_clkreq"; ++ }; ++ }; ++ ++ snfi_pins: snfi-pins { ++ mux { ++ function = "flash"; ++ groups = "snfi"; ++ }; ++ }; ++ ++ uart0_pins: uart0 { ++ mux { ++ function = "uart"; ++ groups = "uart0_0_tx_rx" ; ++ }; ++ }; ++ ++ pwm_pins: pwm1 { ++ mux { ++ function = "pwm"; ++ groups = "pwm_ch1_0" ; ++ }; ++ }; ++ ++ watchdog_pins: watchdog-default { ++ mux { ++ function = "watchdog"; ++ groups = "watchdog"; ++ }; ++ }; ++ ++ mmc0_pins_default: mmc0default { ++ mux { ++ function = "emmc"; ++ groups = "emmc"; ++ }; ++ ++ conf-cmd-dat { ++ pins = "NDL0", "NDL1", "NDL2", ++ "NDL3", "NDL4", "NDL5", ++ "NDL6", "NDL7", "NRB"; ++ input-enable; ++ bias-pull-up; ++ }; ++ ++ conf-clk { ++ pins = "NCLE"; ++ bias-pull-down; ++ }; ++ }; ++ ++ mmc1_pins_default: mmc1default { ++ mux { ++ function = "sd"; ++ groups = "sd_0"; ++ }; ++ ++ conf-cmd-data { ++ pins = "I2S2_OUT", "I2S4_IN", "I2S3_IN", ++ "I2S2_IN","I2S4_OUT"; ++ input-enable; ++ drive-strength = <8>; ++ bias-pull-up; ++ }; ++ ++ conf-clk { ++ pins = "I2S3_OUT"; ++ drive-strength = <12>; ++ bias-pull-down; ++ }; ++ ++ conf-cd { ++ pins = "TXD3"; ++ bias-pull-up; ++ }; ++ }; ++}; ++ ++&snfi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&snfi_pins>; ++ status = "okay"; ++ ++ spi-nand@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ partition@0 { ++ label = "bl2"; ++ reg = <0x0 0x80000>; ++ }; ++ ++ partition@80000 { ++ label = "ubi"; ++ reg = <0x80000 0x7f80000>; ++ }; ++ }; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++&pwm { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm_pins>; ++ status = "okay"; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_default>; ++ status = "okay"; ++ bus-width = <8>; ++ max-frequency = <50000000>; ++ cap-mmc-highspeed; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_3p3v>; ++ non-removable; ++}; ++ ++&mmc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc1_pins_default>; ++ status = "okay"; ++ bus-width = <4>; ++ max-frequency = <25000000>; ++ cap-sd-highspeed; ++ r_smpl = <1>; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_3p3v>; ++}; ++ ++&watchdog { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&watchdog_pins>; ++ status = "okay"; ++}; ++ ++ð { ++ status = "okay"; ++ mediatek,gmac-id = <0>; ++ phy-mode = "2500base-x"; ++ mediatek,switch = "mt7531"; ++ reset-gpios = <&gpio 54 GPIO_ACTIVE_HIGH>; ++ ++ fixed-link { ++ speed = <2500>; ++ full-duplex; ++ }; ++}; ++ ++&gpio { ++ /*gpio 90 for setting mode to sata*/ ++ asm_sel { ++ gpio-hog; ++ gpios = <90 GPIO_ACTIVE_HIGH>; ++ output-low; ++ }; ++}; ++ ++&ssusb { ++ status = "okay"; ++}; ++ ++&u3phy { ++ status = "okay"; ++}; +diff --git a/arch/arm/dts/mt7622-bananapi-bpi-r64.dts b/arch/arm/dts/mt7622-bananapi-bpi-r64.dts +index 717baf26d3f..f25257be63d 100644 +--- a/arch/arm/dts/mt7622-bananapi-bpi-r64.dts ++++ b/arch/arm/dts/mt7622-bananapi-bpi-r64.dts +@@ -5,6 +5,7 @@ + */ + + /dts-v1/; ++#include + #include "mt7622.dtsi" + #include "mt7622-u-boot.dtsi" + +@@ -20,6 +21,7 @@ + + aliases { + spi0 = &snfi; ++ ethernet0 = ð + }; + + memory@40000000 { +@@ -27,6 +29,38 @@ + reg = <0x40000000 0x40000000>; + }; + ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ factory-reset { ++ label = "factory-reset"; ++ gpios = <&gpio 0 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ wps { ++ label = "wps"; ++ gpios = <&gpio 102 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ green { ++ label = "bpi-r64:pio:green"; ++ gpios = <&gpio 89 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ blue { ++ label = "bpi-r64:pio:blue"; ++ gpios = <&gpio 85 GPIO_ACTIVE_LOW>; ++ default-state = "off"; ++ }; ++ }; ++ + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; +@@ -197,7 +231,7 @@ + status = "okay"; + bus-width = <8>; + max-frequency = <50000000>; +- cap-sd-highspeed; ++ cap-mmc-highspeed; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_3p3v>; + non-removable; +@@ -208,7 +242,7 @@ + pinctrl-0 = <&mmc1_pins_default>; + status = "okay"; + bus-width = <4>; +- max-frequency = <50000000>; ++ max-frequency = <25000000>; + cap-sd-highspeed; + r_smpl = <1>; + vmmc-supply = <®_3p3v>; +diff --git a/board/mediatek/mt7622/MAINTAINERS b/board/mediatek/mt7622/MAINTAINERS +index a3e0e75ca07..a7da7948a65 100644 +--- a/board/mediatek/mt7622/MAINTAINERS ++++ b/board/mediatek/mt7622/MAINTAINERS +@@ -4,3 +4,8 @@ S: Maintained + F: board/mediatek/mt7622 + F: include/configs/mt7622.h + F: configs/mt7622_rfb_defconfig ++F: configs/mt7622_bpir64_emmc_defconfig ++F: configs/mt7622_bpir64_sd_defconfig ++F: configs/mt7622_bpir64_snand_defconfig ++F: arch/arm/dts/mt7622-bananapi-bpi-r64.dts ++F: arch/arm/dts/mt7622-bananapi-bpi-r64-nand.dts +diff --git a/configs/mt7622_bpir64_emmc_defconfig b/configs/mt7622_bpir64_emmc_defconfig +new file mode 100644 +index 00000000000..9af7b280c93 +--- /dev/null ++++ b/configs/mt7622_bpir64_emmc_defconfig +@@ -0,0 +1,82 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_ENV_SIZE=0x80000 ++CONFIG_ENV_OFFSET=0x400000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64" ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_PCI=y ++CONFIG_DEBUG_UART=y ++CONFIG_FIT=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7622-bananapi-bpi-r64" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R64> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_UNLZ4 is not set ++# CONFIG_CMD_UNZIP is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_GPT_RENAME=y ++CONFIG_CMD_LSBLK=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_CLK=y ++CONFIG_GPIO_HOG=y ++CONFIG_LED=y ++CONFIG_LED_GPIO=y ++CONFIG_SUPPORT_EMMC_BOOT=y ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_PHY_FIXED=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_FAT_WRITE=y ++CONFIG_HEXDUMP=y +diff --git a/configs/mt7622_bpir64_sd_defconfig b/configs/mt7622_bpir64_sd_defconfig +new file mode 100644 +index 00000000000..5e9340a09a6 +--- /dev/null ++++ b/configs/mt7622_bpir64_sd_defconfig +@@ -0,0 +1,82 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_ENV_SIZE=0x80000 ++CONFIG_ENV_OFFSET=0x400000 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64" ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_PCI=y ++CONFIG_DEBUG_UART=y ++CONFIG_FIT=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7622-bananapi-bpi-r64" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R64> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_UNLZ4 is not set ++# CONFIG_CMD_UNZIP is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_GPT=y ++CONFIG_CMD_GPT_RENAME=y ++CONFIG_CMD_LSBLK=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MMC=y ++CONFIG_SYS_MMC_ENV_DEV=1 ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_CLK=y ++CONFIG_GPIO_HOG=y ++CONFIG_LED=y ++CONFIG_LED_GPIO=y ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_PHY_FIXED=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_FAT_WRITE=y ++CONFIG_HEXDUMP=y +diff --git a/configs/mt7622_bpir64_snand_defconfig b/configs/mt7622_bpir64_snand_defconfig +new file mode 100644 +index 00000000000..9be13d26fd9 +--- /dev/null ++++ b/configs/mt7622_bpir64_snand_defconfig +@@ -0,0 +1,88 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TARGET_MT7622=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEFAULT_DEVICE_TREE="mt7622-bananapi-bpi-r64-nand" ++CONFIG_SYS_LOAD_ADDR=0x40080000 ++CONFIG_DEBUG_UART_BASE=0x11002000 ++CONFIG_DEBUG_UART_CLOCK=25000000 ++CONFIG_PCI=y ++CONFIG_DEBUG_UART=y ++CONFIG_FIT=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7622-bananapi-bpi-r64-nand" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R64> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++# CONFIG_CMD_UNLZ4 is not set ++# CONFIG_CMD_UNZIP is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_PART=y ++CONFIG_CMD_READ=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_FAT=y ++CONFIG_CMD_FS_GENERIC=y ++CONFIG_CMD_UBI=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_UBI=y ++CONFIG_ENV_REDUNDANT=y ++CONFIG_ENV_UBI_PART="ubi" ++CONFIG_ENV_UBI_VOLUME="ubootenv" ++CONFIG_ENV_UBI_VOLUME_REDUND="ubootenv2" ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_BUTTON=y ++CONFIG_BUTTON_GPIO=y ++CONFIG_CLK=y ++CONFIG_GPIO_HOG=y ++CONFIG_LED=y ++CONFIG_LED_GPIO=y ++CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_MTK=y ++CONFIG_MTD=y ++CONFIG_DM_MTD=y ++CONFIG_MTD_SPI_NAND=y ++CONFIG_PHY_FIXED=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCIE_MEDIATEK=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7622=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_REGULATOR=y ++CONFIG_DM_REGULATOR_FIXED=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SNFI_SPI=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_FAT_WRITE=y ++CONFIG_HEXDUMP=y +-- +2.43.0 + diff --git a/patches/uboot/2026.01/0010-arm-mediatek-add-BananaPi-BPI-R4-MT7988A-board-suppo.patch b/patches/uboot/2026.01/0010-arm-mediatek-add-BananaPi-BPI-R4-MT7988A-board-suppo.patch new file mode 100644 index 000000000..8386f5889 --- /dev/null +++ b/patches/uboot/2026.01/0010-arm-mediatek-add-BananaPi-BPI-R4-MT7988A-board-suppo.patch @@ -0,0 +1,784 @@ +From 8b3d206ff8c398de5290a1c4237c841389655505 Mon Sep 17 00:00:00 2001 +From: Joachim Wiberg +Date: Sun, 15 Mar 2026 12:51:39 +0100 +Subject: [PATCH] arm: mediatek: add BananaPi BPI-R4 (MT7988A) board support +Organization: Wires + +Add complete U-Boot support for the BananaPi BPI-R4 router board, +based on MediaTek MT7988A (Filogic 880, quad-core Cortex-A73). + +Device tree (mt7988a-bananapi-bpi-r4.dts): +- UART0 (console) +- eMMC (8-bit, non-removable, 52 MHz, high-speed) +- SPI NAND via SPI0 +- Gigabit/10G Ethernet via MT7988 internal switch (usxgmii) +- PCIe x4 (pcie0-3) +- USB 3.0 (xhci1) +- PWM (fan control) +- I2C0: RT5190A PMIC +- I2C2: PCA9545 mux with PCF8563 RTC and 24C02 EEPROM on channel 0 +- gpio-keys: factory-reset / WPS button on GPIO14 (active-low); + U-Boot uses it for factory reset detection via the 'button' command, + Linux uses the same GPIO as KEY_WPS_BUTTON at runtime + +SD card variant (mt7988a-bananapi-bpi-r4-sd.dts + mt7988a_bpir4_sd_defconfig): +- MT7988A eMMC (pins 38-49) and SD card (pins 32-37) use separate + physical pads so both are electrically independent; only one can be + active per boot session via the single MMC controller (mmc@11230000) +- SD variant enables cap-sd-highspeed (50 MHz) vs legacy 25 MHz; + GPIO12 used as card-detect +- pinctrl-mt7988.c: add 'sdcard' pin group (pins 32-37, function 5) + to match the Linux kernel driver + +Board support (mt7988_rfb.c, Kconfig, defconfig): +- detect_boot_media(): reads BOOT_DEVICE register (0x1001f6f0 bits + 10-11) to set $bootmedia env var (nor/spim-nand/emmc/snand) +- detect_ram_size(): sets $ram_gb (4 or 8) based on detected DRAM +- board_late_init(): calls both detectors at late init +- ft_system_setup(): patches /chosen/rootdisk phandle in kernel DT + to point at the detected boot device node +- BOARD_BPI_R4 now selects BOARD_LATE_INIT and OF_SYSTEM_SETUP + +Defconfig gaps vs upstream filled in (FIT, eMMC, USB, PCIe/NVMe, I2C). +CONFIG_CMD_BUTTON=y added to both defconfigs for factory-reset button. + +The bpir4.c board file (from commit 57b3cd86) provides +board_fit_config_name_match() for BPI-R4 / BPI-R4-2g5 variant +selection via FIT image. + +Based on Frank Wunderlich's porting work: + https://github.com/frank-w/u-boot/tree/2026-01-bpi + +Signed-off-by: Joachim Wiberg +--- + arch/arm/dts/Makefile | 3 + + arch/arm/dts/mt7988a-bananapi-bpi-r4-2g5.dts | 16 ++ + arch/arm/dts/mt7988a-bananapi-bpi-r4-sd.dts | 33 +++ + arch/arm/dts/mt7988a-bananapi-bpi-r4.dts | 227 +++++++++++++++++++ + board/mediatek/mt7988/Kconfig | 2 + + board/mediatek/mt7988/bpir4.c | 23 +- + board/mediatek/mt7988/mt7988_rfb.c | 96 ++++++++ + configs/mt7988a_bpir4_defconfig | 33 ++- + configs/mt7988a_bpir4_sd_defconfig | 114 ++++++++++ + drivers/pinctrl/mediatek/pinctrl-mt7988.c | 6 +- + 10 files changed, 547 insertions(+), 6 deletions(-) + create mode 100644 arch/arm/dts/mt7988a-bananapi-bpi-r4-2g5.dts + create mode 100644 arch/arm/dts/mt7988a-bananapi-bpi-r4-sd.dts + create mode 100644 arch/arm/dts/mt7988a-bananapi-bpi-r4.dts + create mode 100644 configs/mt7988a_bpir4_sd_defconfig + +diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile +index d4255f95702..697d3383b01 100644 +--- a/arch/arm/dts/Makefile ++++ b/arch/arm/dts/Makefile +@@ -1134,6 +1134,9 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \ + mt7986b-emmc-rfb.dtb \ + mt7988-rfb.dtb \ + mt7988-sd-rfb.dtb \ ++ mt7988a-bananapi-bpi-r4.dtb \ ++ mt7988a-bananapi-bpi-r4-2g5.dtb \ ++ mt7988a-bananapi-bpi-r4-sd.dtb \ + mt8183-pumpkin.dtb \ + mt8512-bm1-emmc.dtb \ + mt8516-pumpkin.dtb \ +diff --git a/arch/arm/dts/mt7988a-bananapi-bpi-r4-2g5.dts b/arch/arm/dts/mt7988a-bananapi-bpi-r4-2g5.dts +new file mode 100644 +index 00000000000..0dd82cdc9fd +--- /dev/null ++++ b/arch/arm/dts/mt7988a-bananapi-bpi-r4-2g5.dts +@@ -0,0 +1,16 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2024 BananaPi ++ * Copyright (c) 2026 KernelKit ++ * ++ * U-Boot device tree for BananaPi BPI-R4-2g5 (MediaTek MT7988A) ++ * Variant with internal 2.5G PHY on GMAC1 instead of SFP+/USXGMII ++ */ ++ ++#include "mt7988a-bananapi-bpi-r4.dts" ++ ++/ { ++ model = "BananaPi BPI-R4-2g5"; ++ compatible = "bananapi,bpi-r4-2g5", "bananapi,bpi-r4", ++ "mediatek,mt7988a", "mediatek,mt7988"; ++}; +diff --git a/arch/arm/dts/mt7988a-bananapi-bpi-r4-sd.dts b/arch/arm/dts/mt7988a-bananapi-bpi-r4-sd.dts +new file mode 100644 +index 00000000000..4fb411bad4d +--- /dev/null ++++ b/arch/arm/dts/mt7988a-bananapi-bpi-r4-sd.dts +@@ -0,0 +1,33 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * SD card boot variant of the BananaPi BPI-R4 U-Boot device tree. ++ * eMMC and SD use separate physical pins on MT7988, so both are ++ * accessible simultaneously — boot from SD, flash eMMC. ++ */ ++ ++/dts-v1/; ++#include "mt7988a-bananapi-bpi-r4.dts" ++ ++/* Override mmc0 for SD card: swap pinctrl, enable high-speed, add CD */ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_sdcard>; ++ bus-width = <4>; ++ max-frequency = <52000000>; ++ cap-sd-highspeed; ++ cd-gpios = <&pio 12 GPIO_ACTIVE_LOW>; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_3p3v>; ++ /delete-property/ cap-mmc-highspeed; ++ /delete-property/ cap-mmc-hw-reset; ++ /delete-property/ non-removable; ++}; ++ ++&pio { ++ mmc0_pins_sdcard: mmc0-sdcard-pins { ++ mux { ++ function = "flash"; ++ groups = "sdcard"; ++ }; ++ }; ++}; +diff --git a/arch/arm/dts/mt7988a-bananapi-bpi-r4.dts b/arch/arm/dts/mt7988a-bananapi-bpi-r4.dts +new file mode 100644 +index 00000000000..d959d778716 +--- /dev/null ++++ b/arch/arm/dts/mt7988a-bananapi-bpi-r4.dts +@@ -0,0 +1,227 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2024 BananaPi ++ * Copyright (c) 2026 KernelKit ++ * ++ * U-Boot device tree for BananaPi BPI-R4 (MediaTek MT7988A) ++ * Based on Frank Wunderlich's work: https://github.com/frank-w/u-boot ++ */ ++ ++/dts-v1/; ++#include "mt7988.dtsi" ++#include ++#include ++ ++/ { ++ model = "BananaPi BPI-R4"; ++ compatible = "bananapi,bpi-r4", "mediatek,mt7988a", "mediatek,mt7988"; ++ ++ chosen { ++ stdout-path = &uart0; ++ }; ++ ++ memory@40000000 { ++ device_type = "memory"; ++ reg = <0 0x40000000 1 0x00000000>; /* 4 GiB */ ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ factory-reset { ++ label = "factory-reset"; ++ gpios = <&pio 14 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-1.8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-3.3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; ++ ++/* RT5190A PMIC */ ++&i2c0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c0_pins>; ++ status = "okay"; ++ ++ rt5190a: pmic@64 { ++ compatible = "richtek,rt5190a"; ++ reg = <0x64>; ++ }; ++}; ++ ++/* I2C mux: PCA9545 at 0x70, with RTC and board EEPROM on channel 0 */ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2c2_1_pins>; ++ status = "okay"; ++ ++ i2c_mux: i2c-mux@70 { ++ compatible = "nxp,pca9545"; ++ reg = <0x70>; ++ reset-gpios = <&pio 5 GPIO_ACTIVE_LOW>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c_ch0: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ rtc@51 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c02"; ++ reg = <0x57>; ++ }; ++ }; ++ }; ++}; ++ ++ð0 { ++ status = "okay"; ++ phy-mode = "usxgmii"; ++ mediatek,switch = "mt7988"; ++ ++ fixed-link { ++ speed = <10000>; ++ full-duplex; ++ pause; ++ }; ++}; ++ ++&pcie0 { ++ status = "okay"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; ++ ++&pcie2 { ++ status = "okay"; ++}; ++ ++&pcie3 { ++ status = "okay"; ++}; ++ ++&pio { ++ i2c0_pins: i2c0-g0-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c0_1"; ++ }; ++ }; ++ ++ i2c2_1_pins: i2c2-g1-pins { ++ mux { ++ function = "i2c"; ++ groups = "i2c2_1"; ++ }; ++ }; ++ ++ mmc0_pins_emmc: mmc0-emmc-pins { ++ mux { ++ function = "flash"; ++ groups = "emmc_51"; ++ }; ++ ++ conf-cmd-dat { ++ pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", ++ "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", ++ "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; ++ input-enable; ++ drive-strength = ; ++ mediatek,pull-up-adv = <1>; ++ }; ++ ++ conf-clk { ++ pins = "EMMC_CK"; ++ drive-strength = ; ++ mediatek,pull-down-adv = <2>; ++ }; ++ ++ conf-dsl { ++ pins = "EMMC_DSL"; ++ mediatek,pull-down-adv = <2>; ++ }; ++ ++ conf-rst { ++ pins = "EMMC_RSTB"; ++ drive-strength = ; ++ mediatek,pull-up-adv = <1>; ++ }; ++ }; ++ ++ spi0_flash_pins: spi0-flash-pins { ++ mux { ++ function = "spi"; ++ groups = "spi0", "spi0_wp_hold"; ++ }; ++ }; ++}; ++ ++&pwm { ++ status = "okay"; ++}; ++ ++/* SPI NAND */ ++&spi0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0_flash_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ enhance_timing; ++ dma_ext; ++ ipm_design; ++ support_quad; ++ tick_dly = <2>; ++ sample_sel = <0>; ++ ++ spi_nand: flash@0 { ++ compatible = "spi-nand"; ++ reg = <0>; ++ spi-max-frequency = <52000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; ++}; ++ ++/* eMMC */ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_emmc>; ++ max-frequency = <52000000>; ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ cap-mmc-hw-reset; ++ vmmc-supply = <®_3p3v>; ++ vqmmc-supply = <®_1p8v>; ++ non-removable; ++ status = "okay"; ++}; +diff --git a/board/mediatek/mt7988/Kconfig b/board/mediatek/mt7988/Kconfig +index 24c70417ec5..9bcad9ecefd 100644 +--- a/board/mediatek/mt7988/Kconfig ++++ b/board/mediatek/mt7988/Kconfig +@@ -2,6 +2,8 @@ if TARGET_MT7988 + + config BOARD_BPI_R4 + bool "BananaPi BPI-R4 / BPI-R4-2g5 board support" ++ select BOARD_LATE_INIT ++ select OF_SYSTEM_SETUP + help + Enable runtime variant detection for BananaPi BPI-R4 and BPI-R4-2g5, + selecting the correct device tree from a FIT image. +diff --git a/board/mediatek/mt7988/bpir4.c b/board/mediatek/mt7988/bpir4.c +index 46e22d38135..cfc05c607fc 100644 +--- a/board/mediatek/mt7988/bpir4.c ++++ b/board/mediatek/mt7988/bpir4.c +@@ -13,21 +13,36 @@ enum bpir4_variant { + + /* + * Detect which BPI-R4 variant this board is. +- * TODO: implement real hardware detection ++ * ++ * Unlike BPI-R3 vs R3-Mini, the R4-2g5 uses the MT7988A's internal 2.5G ++ * PHY (always present in SoC silicon at MDIO addr 15) rather than an ++ * external EN8811H, so MDIO probing cannot distinguish the variants. ++ * ++ * TODO: read variant ID from the 24C02 EEPROM on I2C2/PCA9545 ch0 (addr ++ * 0x57) once BananaPi's board-ID byte offset/format is known. + */ + static enum bpir4_variant detect_bpir4_variant(void) + { +- /* Stub: always report BPI-R4 */ ++ /* Stub: always report standard BPI-R4 */ + return BPIR4; + } + + int board_fit_config_name_match(const char *name) + { +- switch (detect_bpir4_variant()) { ++ static int variant = -1; ++ ++ if (variant < 0) ++ variant = detect_bpir4_variant(); ++ ++ switch (variant) { + case BPIR4_2G5: + return strcmp(name, "mt7988a-bananapi-bpi-r4-2g5") ? -1 : 0; + case BPIR4: + default: +- return strcmp(name, "mt7988a-bananapi-bpi-r4") ? -1 : 0; ++ if (!strcmp(name, "mt7988a-bananapi-bpi-r4") || ++ !strcmp(name, "mt7988a-bananapi-bpi-r4-sd")) ++ return 0; ++ return -1; + } + } ++ +diff --git a/board/mediatek/mt7988/mt7988_rfb.c b/board/mediatek/mt7988/mt7988_rfb.c +index 0ca87a88aed..ed184574b50 100644 +--- a/board/mediatek/mt7988/mt7988_rfb.c ++++ b/board/mediatek/mt7988/mt7988_rfb.c +@@ -4,3 +4,99 @@ + * Author: Sam Shih + */ + ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MT7988_BOOT_NOR 0 ++#define MT7988_BOOT_SPIM_NAND 1 ++#define MT7988_BOOT_EMMC 2 ++#define MT7988_BOOT_SNFI_NAND 3 ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++int board_init(void) ++{ ++ return 0; ++} ++ ++static void detect_boot_media(void) ++{ ++ const char *media; ++ ++ switch ((readl(0x1001f6f0) & 0xc00) >> 10) { ++ case MT7988_BOOT_NOR: ++ media = "nor"; ++ break; ++ case MT7988_BOOT_SPIM_NAND: ++ media = "spim-nand"; ++ break; ++ case MT7988_BOOT_EMMC: ++ media = "emmc"; ++ break; ++ case MT7988_BOOT_SNFI_NAND: ++ media = "snand"; ++ break; ++ default: ++ media = "unknown"; ++ break; ++ } ++ ++ env_set("bootmedia", media); ++} ++ ++static void detect_ram_size(void) ++{ ++ env_set("ram_gb", gd->ram_size > (6ULL << 30) ? "8" : "4"); ++} ++ ++int board_late_init(void) ++{ ++ const char *model; ++ ++ detect_boot_media(); ++ detect_ram_size(); ++ ++ model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); ++ if (model && strstr(model, "2g5")) ++ env_set("fdtfile", "mediatek/mt7988a-bananapi-bpi-r4-2g5.dtb"); ++ ++ return 0; ++} ++ ++int ft_system_setup(void *blob, struct bd_info *bd) ++{ ++ const u32 *media_handle_p; ++ int chosen, len, ret; ++ char media[32]; ++ const char *bootdev; ++ u32 media_handle; ++ ++ if (!env_get("bootmedia")) ++ detect_boot_media(); ++ ++ bootdev = env_get("bootmedia"); ++ snprintf(media, sizeof(media), "rootdisk-%s", bootdev); ++ ++ chosen = fdt_path_offset(blob, "/chosen"); ++ if (chosen <= 0) ++ return 0; ++ ++ media_handle_p = fdt_getprop(blob, chosen, media, &len); ++ if (!media_handle_p || len != 4) ++ return 0; ++ ++ media_handle = *media_handle_p; ++ ret = fdt_setprop(blob, chosen, "rootdisk", &media_handle, sizeof(media_handle)); ++ if (ret) { ++ printf("cannot set media phandle %s as rootdisk in /chosen\n", media); ++ return ret; ++ } ++ ++ printf("set /chosen/rootdisk to boot media: %s (phandle 0x%08x)\n", ++ media, fdt32_to_cpu(media_handle)); ++ return 0; ++} +diff --git a/configs/mt7988a_bpir4_defconfig b/configs/mt7988a_bpir4_defconfig +index e2e128ec29d..9d4a2f6e75e 100644 +--- a/configs/mt7988a_bpir4_defconfig ++++ b/configs/mt7988a_bpir4_defconfig +@@ -9,6 +9,7 @@ CONFIG_DEFAULT_DEVICE_TREE="mt7988a-bananapi-bpi-r4" + CONFIG_TARGET_MT7988=y + CONFIG_BOARD_BPI_R4=y + CONFIG_SPL_LOAD_FIT=y ++CONFIG_FIT=y + CONFIG_SYS_LOAD_ADDR=0x46000000 + CONFIG_DEBUG_UART_BASE=0x11000000 + CONFIG_DEBUG_UART_CLOCK=40000000 +@@ -16,6 +17,8 @@ CONFIG_DEBUG_UART=y + # CONFIG_EFI_LOADER is not set + # CONFIG_AUTOBOOT is not set + CONFIG_DEFAULT_FDT_FILE="mt7988a-bananapi-bpi-r4" ++CONFIG_MULTI_DTB_FIT=y ++CONFIG_OF_LIST="mt7988a-bananapi-bpi-r4 mt7988a-bananapi-bpi-r4-2g5" + CONFIG_SYS_CBSIZE=512 + CONFIG_SYS_PBSIZE=1049 + CONFIG_LOGLEVEL=7 +@@ -26,14 +29,19 @@ CONFIG_SYS_PROMPT="BPI-R4> " + # CONFIG_BOOTM_RTEMS is not set + # CONFIG_BOOTM_VXWORKS is not set + # CONFIG_CMD_ELF is not set ++CONFIG_CMD_BUTTON=y + CONFIG_CMD_CLK=y + CONFIG_CMD_DM=y + CONFIG_CMD_GPIO=y +-CONFIG_CMD_PWM=y ++CONFIG_CMD_I2C=y + CONFIG_CMD_MMC=y + CONFIG_CMD_MTD=y ++CONFIG_CMD_MDIO=y ++CONFIG_CMD_PCI=y + CONFIG_CMD_PING=y ++CONFIG_CMD_PWM=y + CONFIG_CMD_SMC=y ++CONFIG_CMD_USB=y + CONFIG_DOS_PARTITION=y + CONFIG_EFI_PARTITION=y + CONFIG_PARTITION_TYPE_GUID=y +@@ -49,8 +57,15 @@ CONFIG_NET_RANDOM_ETHADDR=y + CONFIG_REGMAP=y + CONFIG_SYSCON=y + CONFIG_CLK=y ++CONFIG_I2C=y ++CONFIG_DM_I2C=y ++CONFIG_SYS_I2C_MTK=y ++CONFIG_I2C_MUX=y ++CONFIG_I2C_MUX_PCA954x=y + CONFIG_MMC_HS200_SUPPORT=y ++CONFIG_MMC_WRITE=y + CONFIG_MMC_MTK=y ++CONFIG_SUPPORT_EMMC_BOOT=y + CONFIG_MTD=y + CONFIG_DM_MTD=y + CONFIG_MTD_SPI_NAND=y +@@ -67,7 +82,14 @@ CONFIG_SPI_FLASH_XMC=y + CONFIG_SPI_FLASH_XTX=y + CONFIG_SPI_FLASH_MTD=y + CONFIG_PHY_FIXED=y ++CONFIG_DM_MDIO=y ++CONFIG_DM_ETH_PHY=y ++CONFIG_PHY_ETHERNET_ID=y + CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_PCIE_MEDIATEK_GEN3=y ++CONFIG_NVME_PCI=y ++CONFIG_NVME=y + CONFIG_PINCTRL=y + CONFIG_PINCONF=y + CONFIG_PINCTRL_MT7988=y +@@ -78,8 +100,17 @@ CONFIG_PWM_MTK=y + CONFIG_RAM=y + CONFIG_DM_SERIAL=y + CONFIG_MTK_SERIAL=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y + CONFIG_SPI=y + CONFIG_DM_SPI=y + CONFIG_MTK_SPIM=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_BOARD_LATE_INIT=y + CONFIG_LZO=y + CONFIG_HEXDUMP=y +diff --git a/configs/mt7988a_bpir4_sd_defconfig b/configs/mt7988a_bpir4_sd_defconfig +new file mode 100644 +index 00000000000..7e78dc17e54 +--- /dev/null ++++ b/configs/mt7988a_bpir4_sd_defconfig +@@ -0,0 +1,114 @@ ++CONFIG_ARM=y ++CONFIG_SYS_HAS_NONCACHED_MEMORY=y ++CONFIG_POSITION_INDEPENDENT=y ++CONFIG_ARCH_MEDIATEK=y ++CONFIG_TEXT_BASE=0x41e00000 ++CONFIG_SYS_MALLOC_F_LEN=0x4000 ++CONFIG_NR_DRAM_BANKS=1 ++CONFIG_DEFAULT_DEVICE_TREE="mt7988a-bananapi-bpi-r4-sd" ++CONFIG_TARGET_MT7988=y ++CONFIG_BOARD_BPI_R4=y ++CONFIG_SPL_LOAD_FIT=y ++CONFIG_FIT=y ++CONFIG_SYS_LOAD_ADDR=0x46000000 ++CONFIG_DEBUG_UART_BASE=0x11000000 ++CONFIG_DEBUG_UART_CLOCK=40000000 ++CONFIG_DEBUG_UART=y ++# CONFIG_EFI_LOADER is not set ++# CONFIG_AUTOBOOT is not set ++CONFIG_DEFAULT_FDT_FILE="mt7988a-bananapi-bpi-r4-sd" ++CONFIG_MULTI_DTB_FIT=y ++CONFIG_OF_LIST="mt7988a-bananapi-bpi-r4-sd" ++CONFIG_SYS_CBSIZE=512 ++CONFIG_SYS_PBSIZE=1049 ++CONFIG_LOGLEVEL=7 ++CONFIG_LOG=y ++CONFIG_SYS_PROMPT="BPI-R4> " ++# CONFIG_BOOTM_NETBSD is not set ++# CONFIG_BOOTM_PLAN9 is not set ++# CONFIG_BOOTM_RTEMS is not set ++# CONFIG_BOOTM_VXWORKS is not set ++# CONFIG_CMD_ELF is not set ++CONFIG_CMD_BUTTON=y ++CONFIG_CMD_CLK=y ++CONFIG_CMD_DM=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_I2C=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_MTD=y ++CONFIG_CMD_MDIO=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_PING=y ++CONFIG_CMD_PWM=y ++CONFIG_CMD_SMC=y ++CONFIG_CMD_USB=y ++CONFIG_DOS_PARTITION=y ++CONFIG_EFI_PARTITION=y ++CONFIG_PARTITION_TYPE_GUID=y ++CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y ++CONFIG_USE_IPADDR=y ++CONFIG_IPADDR="192.168.1.1" ++CONFIG_USE_NETMASK=y ++CONFIG_NETMASK="255.255.255.0" ++CONFIG_USE_SERVERIP=y ++CONFIG_SERVERIP="192.168.1.2" ++CONFIG_PROT_TCP=y ++CONFIG_NET_RANDOM_ETHADDR=y ++CONFIG_REGMAP=y ++CONFIG_SYSCON=y ++CONFIG_CLK=y ++CONFIG_I2C=y ++CONFIG_DM_I2C=y ++CONFIG_SYS_I2C_MTK=y ++CONFIG_I2C_MUX=y ++CONFIG_I2C_MUX_PCA954x=y ++CONFIG_MMC_WRITE=y ++CONFIG_MMC_MTK=y ++CONFIG_MTD=y ++CONFIG_DM_MTD=y ++CONFIG_MTD_SPI_NAND=y ++CONFIG_DM_SPI_FLASH=y ++CONFIG_SPI_FLASH_SFDP_SUPPORT=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_XMC=y ++CONFIG_SPI_FLASH_XTX=y ++CONFIG_SPI_FLASH_MTD=y ++CONFIG_PHY_FIXED=y ++CONFIG_DM_MDIO=y ++CONFIG_DM_ETH_PHY=y ++CONFIG_PHY_ETHERNET_ID=y ++CONFIG_MEDIATEK_ETH=y ++CONFIG_PCI=y ++CONFIG_PCIE_MEDIATEK_GEN3=y ++CONFIG_NVME_PCI=y ++CONFIG_NVME=y ++CONFIG_PINCTRL=y ++CONFIG_PINCONF=y ++CONFIG_PINCTRL_MT7988=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_MTK_POWER_DOMAIN=y ++CONFIG_DM_PWM=y ++CONFIG_PWM_MTK=y ++CONFIG_RAM=y ++CONFIG_DM_SERIAL=y ++CONFIG_MTK_SERIAL=y ++CONFIG_PHY=y ++CONFIG_PHY_MTK_TPHY=y ++CONFIG_USB=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_MTK=y ++CONFIG_USB_STORAGE=y ++CONFIG_SPI=y ++CONFIG_DM_SPI=y ++CONFIG_MTK_SPIM=y ++CONFIG_OF_LIBFDT_OVERLAY=y ++CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_BOARD_LATE_INIT=y ++CONFIG_LZO=y ++CONFIG_HEXDUMP=y +diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/drivers/pinctrl/mediatek/pinctrl-mt7988.c +index 639e2415c63..317a325d8c6 100644 +--- a/drivers/pinctrl/mediatek/pinctrl-mt7988.c ++++ b/drivers/pinctrl/mediatek/pinctrl-mt7988.c +@@ -942,6 +942,9 @@ static const int mt7988_emmc_45_pins[] = { + 21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 }; + static const int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; + ++static const int mt7988_sdcard_pins[] = { 32, 33, 34, 35, 36, 37 }; ++static const int mt7988_sdcard_funcs[] = { 5, 5, 5, 5, 5, 5 }; ++ + static const int mt7988_emmc_51_pins[] = { + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49 }; + static const int mt7988_emmc_51_funcs[] = { +@@ -1101,6 +1104,7 @@ static const struct mtk_group_desc mt7988_groups[] = { + PINCTRL_PIN_GROUP("udi", mt7988_udi), + PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45), + PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51), ++ PINCTRL_PIN_GROUP("sdcard", mt7988_sdcard), + PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio), + PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio), + PINCTRL_PIN_GROUP("pcm", mt7988_pcm), +@@ -1197,7 +1201,7 @@ static const char *const mt7988_pmic_groups[] = { "pmic", }; + static const char *const mt7988_wdt_groups[] = { "watchdog", }; + static const char *const mt7988_spi_groups[] = { "spi0", "spi0_wp_hold", + "spi1", "spi2", "spi2_wp_hold", }; +-static const char *const mt7988_flash_groups[] = { "emmc_45", "snfi", ++static const char *const mt7988_flash_groups[] = { "emmc_45", "sdcard", "snfi", + "emmc_51" }; + static const char *const mt7988_uart_groups[] = { "uart2", "tops_uart0_0", + "uart2_0", "uart1_0", "uart2_1", +-- +2.43.0 + diff --git a/utils/mkimage.sh b/utils/mkimage.sh index 882d34bab..1b01e19e3 100755 --- a/utils/mkimage.sh +++ b/utils/mkimage.sh @@ -186,6 +186,13 @@ get_bootloader_name() echo "bpi_r3_sd_boot" fi ;; + bananapi-bpi-r4) + if [ "$target" = "emmc" ]; then + echo "bpi_r4_emmc_boot" + else + echo "bpi_r4_sd_boot" + fi + ;; bananapi-bpi-r64) if [ "$target" = "emmc" ]; then echo "bpi_r64_emmc_boot"