RK3588 制作 ubuntu 固件

基于友善

Posted by LXG on June 22, 2026

sd-fuse_rk3588

下载SDK

  1. 百度网盘下载 friendlywrt-rk3588-v24.10-20250703.tar
  2. MD5 校验: md5sum -c friendlywrt-rk3588-v24.10-20250703.tar.hash.md
  3. 解压: tar -xvf friendlywrt-rk3588-v24.10-20250703.tar

代码初始化


lxg@lxg:~/code/open_source_board/friendlyelec/friendlywrt-rk3588-v24.10$ cat README.txt 
# Step 1: Execute the following command to unpack the source code
./repo/repo sync -l --no-clone-bundle

# Step 2: Use local cache (optional)
(cd pre-download && ./unpack.sh)

# Step 3: View help information
./build.sh

# The final step: Start building
./build.sh rk3588.mk

# Or build image with built-in Docker
./build.sh rk3588_docker.mk

# More information
https://wiki.friendlyarm.com/wiki/index.php/How_to_Build_FriendlyWrt
https://github.com/friendlyarm/Actions-FriendlyWrt

友善rootfs.img放荣品SDK中编译ubuntu

  1. 从百度网盘>FriendlyELEC-RK…>03_分区镜像文件
  2. 解压 tar -xvf ubuntu-jammy-desktop-arm64-images.tgz
  3. 替换

cd /home/lxg/code/project/linux/rk3588_linux

# 1) 备份旧镜像(可选但建议)
[ -f ubuntu/ubuntu.img ] && mv ubuntu/ubuntu.img ubuntu/ubuntu.img.bak

# 2) 用你解压目录里的 rootfs.img 替换为 SDK 需要的 ubuntu.img
cp -av ubuntu/ubuntu-jammy-desktop-arm64/rootfs.img ubuntu/ubuntu.img

# 3) 校验
ls -lh ubuntu/ubuntu.img
file ubuntu/ubuntu.img

  1. 格式转换

cd /home/lxg/code/project/linux/rk3588_linux

# 1) 先确认有 simg2img
which simg2img

# 2) 备份当前 sparse 镜像
mv ubuntu/ubuntu.img ubuntu/ubuntu.img.sparse.bak

# 3) sparse -> raw ext4
simg2img ubuntu/ubuntu.img.sparse.bak ubuntu/ubuntu.img

# 4) 校验应显示 ext4 filesystem data(而不是 Android sparse image)
file ubuntu/ubuntu.img

rootfs 不同开发板厂家的rootfs.img是通用的吗

结论:

同一 CPU 架构(都为 ARM64)只能说明“有机会启动”,不代表可直接用。是否能稳定运行,取决于 BSP 适配,而不是 rootfs 本身。

主要不兼容点:

  1. 内核版本与用户态驱动不匹配: 例如 Mali、NPU、VPU、Camera、RGA、WiFi/BT 的库和内核模块版本要配套。
  2. 启动链和分区约定不同: 不同厂商对 boot、rootfs、userdata、fstab、init 脚本、挂载点有不同约定。
  3. 板级配置不同: 网卡名、串口、音频卡号、显示输出、触摸、传感器等设备节点和默认配置可能不一致。
  4. 厂商定制服务差异: 很多板厂会在 rootfs 里放自家服务、脚本、固件加载逻辑,换板后可能缺失。

基于友善buildroot SDK + ubuntu 文件系统编译ubuntu 固件


commit 6fed667d3250d3562e58690ad9d89c8e28871c7f
Author: lxg <xiaogang.li>
Date:   Mon Jun 22 17:48:40 2026 +0800

    增加nanopi_r6c-ubuntu-jammy-desktop.mk编译选项

diff --git a/buildroot-rk3588/README.txt b/buildroot-rk3588/README.txt
index 96ca5348f..cfb1e8674 100644
--- a/buildroot-rk3588/README.txt
+++ b/buildroot-rk3588/README.txt
@@ -10,5 +10,18 @@
 # The final step: Start building
 ./build.sh rk3588.mk
 
+# Build Ubuntu image (minimal integration, use ubuntu/rootfs-ubuntu-jammy-desktop-arm64.tgz)
+./build.sh rk3588-ubuntu-jammy-desktop.mk
+
+# Build Ubuntu image for NanoPi R6C
+./build.sh nanopi_r6c-ubuntu-jammy-desktop.mk
+
+# Optional split build
+./build.sh rootfs
+./build.sh sd-img
+
+# Pack USB flashing image (update.img)
+sudo ./build.sh usb-img
+
 # More information
 https://wiki.friendlyelec.com/wiki/index.php/Buildroot
diff --git a/buildroot-rk3588/device/friendlyelec/rk3588/nanopi_r6c-ubuntu-jammy-desktop.mk b/buildroot-rk3588/device/friendlyelec/rk3588/nanopi_r6c-ubuntu-jammy-desktop.mk
new file mode 100644
index 000000000..5cf894c0c
--- /dev/null
+++ b/buildroot-rk3588/device/friendlyelec/rk3588/nanopi_r6c-ubuntu-jammy-desktop.mk
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+. device/friendlyelec/rk3588/nanopi_r6c.mk
+
+TARGET_OSNAME=ubuntu-jammy-desktop-arm64
+TARGET_IMAGE_DIRNAME=${TARGET_OSNAME}
+TARGET_ROOTFS_ARCHIVE=ubuntu/rootfs-ubuntu-jammy-desktop-arm64.tgz
+
+TARGET_SD_RAW_FILENAME=ubuntu-jammy-desktop_$(date +%Y%m%d)_nanopi-r6c_arm64_sd.img
+TARGET_EFLASHER_RAW_FILENAME=ubuntu-jammy-desktop_$(date +%Y%m%d)_nanopi-r6c_arm64_eflasher.img
diff --git a/buildroot-rk3588/scripts/build.sh b/buildroot-rk3588/scripts/build.sh
index df690ab3b..f9a083328 100755
--- a/buildroot-rk3588/scripts/build.sh
+++ b/buildroot-rk3588/scripts/build.sh
@@ -49,7 +49,9 @@ usage()
     echo "  ./build.sh all                -build all"
     echo "  ./build.sh uboot              -build uboot only"
     echo "  ./build.sh kernel             -build kernel only"
-    echo "  ./build.sh buildroot          -build buildroot rootfs only"
+    echo "  ./build.sh rootfs             -build configured rootfs (buildroot or external archive)"
+    echo "  ./build.sh buildroot          -build buildroot rootfs only (legacy alias)"
+    echo "  ./build.sh usb-img            -pack Rockchip update.img for USB flashing"
     echo "  ./build.sh sd-img             -pack sd-card image, used to create bootable SD card"
     echo "  ./build.sh emmc-img           -pack sd-card image, used to write buildroot to emmc"
     echo "# clean"
@@ -143,15 +145,53 @@ function build_buildroot(){
     fi
 }
 
+function resolve_rootfs_archive(){
+    if [ ! -z "${TARGET_ROOTFS_ARCHIVE:-}" ]; then
+        echo "${TARGET_ROOTFS_ARCHIVE}"
+        return 0
+    fi
+
+    case "${TARGET_OSNAME}" in
+        buildroot*)
+            echo "${BUILDROOT_SRC}/${BUILDROOT_OUTDIR}/images/rootfs.tar"
+            return 0
+            ;;
+    esac
+
+    return 1
+}
+
+function build_rootfs(){
+    case "${TARGET_OSNAME}" in
+        buildroot*)
+            build_buildroot
+            ;;
+        *)
+            ROOTFS_ARCHIVE=$(resolve_rootfs_archive || true)
+            if [ -z "${ROOTFS_ARCHIVE}" ]; then
+                log_error "No rootfs archive configured for TARGET_OSNAME=${TARGET_OSNAME}."
+                log_error "Set TARGET_ROOTFS_ARCHIVE in your board mk file."
+                exit 1
+            fi
+            if [ ! -f "${TOP_DIR}/${ROOTFS_ARCHIVE}" ]; then
+                log_error "rootfs archive not found: ${TOP_DIR}/${ROOTFS_ARCHIVE}"
+                exit 1
+            fi
+            log_info "Use external rootfs archive: ${TOP_DIR}/${ROOTFS_ARCHIVE}"
+            ;;
+    esac
+}
+
 function build_all() {
     build_uboot
     build_kernel
-    build_buildroot
+    build_rootfs
 }
 
 function clean_old_images(){
     (cd ${TOP_DIR}/out && {
         rm -f *.img
+        rm -f update-*.img
         rm -f *.7z
         rm -f *.zip
         rm -rf boot.*
@@ -159,6 +199,61 @@ function clean_old_images(){
     })
 }
 
+function resolve_pack_tool_dir(){
+    local CANDIDATES=(
+        "${RK_PACK_TOOL_DIR:-}"
+        "${TOP_DIR}/tools/linux/Linux_Pack_Firmware/rockdev"
+        "/home/lxg/code/project/linux/rk3588_linux/tools/linux/Linux_Pack_Firmware/rockdev"
+    )
+
+    for d in "${CANDIDATES[@]}"; do
+        if [ ! -z "$d" ] && [ -x "$d/afptool" ] && [ -x "$d/rkImageMaker" ]; then
+            echo "$d"
+            return 0
+        fi
+    done
+
+    return 1
+}
+
+function generate_package_file(){
+    local IMAGE_DIR=$1
+    local PKG_FILE=$2
+
+    (
+        cd ${IMAGE_DIR}
+        echo -e "# NAME\tPATH"
+        echo -e "package-file\tpackage-file"
+        echo -e "parameter\tparameter.txt"
+        [ ! -r MiniLoaderAll.bin ] || echo -e "bootloader\tMiniLoaderAll.bin"
+
+        local PARTITIONS=$(sed -n 's/.*CMDLINE:[^:]*://p' parameter.txt | tr ',' '\n' | sed -n 's/.*(\([^)]\+\)).*/\1/p')
+        for part in ${PARTITIONS}; do
+            local part_name=${part%%:*}
+            case $part_name in
+                backup)
+                    echo -e "backup\tRESERVED"
+                    continue
+                    ;;
+                system|system_[ab])
+                    IMAGE=rootfs.img
+                    ;;
+                *_a)
+                    IMAGE="${part_name%_a}.img"
+                    ;;
+                *_b)
+                    IMAGE="${part_name%_b}.img"
+                    ;;
+                *)
+                    IMAGE="$part_name.img"
+                    ;;
+            esac
+
+            [ ! -r "$IMAGE" ] || echo -e "$part_name\t$IMAGE"
+        done
+    ) > ${PKG_FILE}
+}
+
 function clean_all(){
     echo "clean uboot, kernel, buildroot, img files"
     cd ${TOP_DIR}/u-boot/ && make distclean && cd -
@@ -176,6 +271,21 @@ function copy_and_verify(){
     cp $1 $2
 }
 
+function prepare_userdata_image(){
+    local IMAGE_DIR=$1
+    local USERDATA_IMG=${IMAGE_DIR}/userdata.img
+    local USERDATA_SIZE_MB=${TARGET_USERDATA_IMG_SIZE_MB:-64}
+
+    if [ -r ${USERDATA_IMG} ]; then
+        return 0
+    fi
+
+    log_info "prepare userdata.img (${USERDATA_SIZE_MB}MB ext4) ..."
+    rm -f ${USERDATA_IMG}
+    dd if=/dev/zero of=${USERDATA_IMG} bs=1M count=${USERDATA_SIZE_MB} status=none
+    mkfs.ext4 -F -L userdata ${USERDATA_IMG} >/dev/null 2>&1
+}
+
 function prepare_image_for_friendlyelec_eflasher(){
     local OS_DIR=$1
     if [ ! -d ${SDFUSE_DIR}/${OS_DIR} ]; then
@@ -191,8 +301,31 @@ function prepare_image_for_friendlyelec_eflasher(){
         rm -rf ${SDFUSE_DIR}/out/rootfs.*
         ROOTFS_DIR=$(mktemp -d ${SDFUSE_DIR}/out/rootfs.XXXXXXXXX)
     fi
-    log_info "Extracting ${TOP_DIR}/${BUILDROOT_SRC}/${BUILDROOT_OUTDIR}/images/rootfs.tar to ${ROOTFS_DIR}/"
-    tar -C ${ROOTFS_DIR}/ -xf ${TOP_DIR}/${BUILDROOT_SRC}/${BUILDROOT_OUTDIR}/images/rootfs.tar
+    local ROOTFS_ARCHIVE=$(resolve_rootfs_archive || true)
+    if [ -z "${ROOTFS_ARCHIVE}" ]; then
+        log_error "Unable to resolve rootfs archive for TARGET_OSNAME=${TARGET_OSNAME}"
+        return 1
+    fi
+    if [ ! -f "${TOP_DIR}/${ROOTFS_ARCHIVE}" ]; then
+        log_error "rootfs archive not found: ${TOP_DIR}/${ROOTFS_ARCHIVE}"
+        return 1
+    fi
+    log_info "Extracting ${TOP_DIR}/${ROOTFS_ARCHIVE} to ${ROOTFS_DIR}/"
+    tar -C ${ROOTFS_DIR}/ -xf ${TOP_DIR}/${ROOTFS_ARCHIVE}
+
+    # Some external rootfs archives are nested as <name>/rootfs/...
+    # Normalize them to ROOTFS_DIR directly so sd-fuse tools can find /lib, /usr, etc.
+    if [ ! -e ${ROOTFS_DIR}/lib ] && [ ! -e ${ROOTFS_DIR}/usr ]; then
+        local NESTED_ROOTFS=$(find ${ROOTFS_DIR} -mindepth 2 -maxdepth 2 -type d -name rootfs | head -n 1)
+        if [ ! -z "${NESTED_ROOTFS}" ]; then
+            log_info "Normalizing nested rootfs: ${NESTED_ROOTFS}"
+            local TMP_MOVED=$(mktemp -d ${SDFUSE_DIR}/out/rootfs.norm.XXXXXXXXX)
+            (cd ${NESTED_ROOTFS} && tar -cf - .) | (cd ${TMP_MOVED} && tar -xf -)
+            rm -rf ${ROOTFS_DIR}/*
+            (cd ${TMP_MOVED} && tar -cf - .) | (cd ${ROOTFS_DIR} && tar -xf -)
+            rm -rf ${TMP_MOVED}
+        fi
+    fi
 
     # oem
     [ -d ${ROOTFS_DIR}/oem ] || mkdir ${ROOTFS_DIR}/oem
@@ -253,6 +386,12 @@ function prepare_image_for_friendlyelec_eflasher(){
             return 1
         fi
 
+        prepare_userdata_image ./${OS_DIR}
+        if [ $? -ne 0 ]; then
+            log_error "error: fail to gen userdata.img."
+            return 1
+        fi
+
         cat > ./${OS_DIR}/info.conf << EOL
 title=${OS_DIR}
 require-board=${TARGET_PLAT}
@@ -355,6 +494,73 @@ function build_emmcimg() {
     })
 }
 
+function build_usbimg(){
+    source ${SDFUSE_DIR}/tools/util.sh
+    local HAS_BUILT_UBOOT=`has_built_uboot ${TOP_DIR}/u-boot ${SDFUSE_DIR}/out`
+    local HAS_BUILD_KERN=`has_built_kernel ${TOP_DIR}/kernel ${SDFUSE_DIR}/out`
+    local HAS_BUILD_KERN_MODULES=`has_built_kernel_modules ${TOP_DIR}/kernel ${SDFUSE_DIR}/out`
+
+    if [ ${HAS_BUILT_UBOOT} -ne 1 ]; then
+        log_error "error: please build u-boot first."
+        exit 1
+    fi
+
+    if [ ${HAS_BUILD_KERN} -ne 1 ]; then
+        log_error "error: please build kernel first."
+        exit 1
+    fi
+
+    if [ ${HAS_BUILD_KERN_MODULES} -ne 1 ]; then
+        log_error "error: please build kernel first (miss kernel modules)."
+        exit 1
+    fi
+
+    local PACK_TOOL_DIR=$(resolve_pack_tool_dir || true)
+    if [ -z "$PACK_TOOL_DIR" ]; then
+        log_error "Cannot find Rockchip pack tools (afptool/rkImageMaker)."
+        log_error "Set RK_PACK_TOOL_DIR to tools/linux/Linux_Pack_Firmware/rockdev"
+        exit 1
+    fi
+
+    prepare_image_for_friendlyelec_eflasher ${TARGET_IMAGE_DIRNAME}
+
+    local IMAGE_DIR=${SDFUSE_DIR}/${TARGET_IMAGE_DIRNAME}
+    local OUT_UPDATE_IMG=${TOP_DIR}/out/update-${TARGET_IMAGE_DIRNAME}.img
+
+    if [ ! -r ${IMAGE_DIR}/parameter.txt ]; then
+        log_error "missing ${IMAGE_DIR}/parameter.txt"
+        exit 1
+    fi
+
+    if [ ! -r ${IMAGE_DIR}/MiniLoaderAll.bin ]; then
+        log_error "missing ${IMAGE_DIR}/MiniLoaderAll.bin"
+        exit 1
+    fi
+
+    generate_package_file ${IMAGE_DIR} ${IMAGE_DIR}/package-file
+
+    (cd ${IMAGE_DIR} && {
+        rm -f update.raw.img update.img
+        ${PACK_TOOL_DIR}/afptool -pack ./ update.raw.img
+
+        TAG=RK$(hexdump -s 21 -n 4 -e '4 "%c"' MiniLoaderAll.bin | rev)
+        ${PACK_TOOL_DIR}/rkImageMaker -${TAG} MiniLoaderAll.bin \
+            update.raw.img update.img -os_type:androidos
+    })
+
+    cp -f ${IMAGE_DIR}/update.img ${OUT_UPDATE_IMG}
+    cp -f ${IMAGE_DIR}/update.img ${TOP_DIR}/out/update.img
+
+    echo "-----------------------------------------"
+    echo "USB flash image generated:"
+    echo "    ${OUT_UPDATE_IMG}"
+    echo "Recommended flash commands (Linux):"
+    echo "    rkbin/tools/upgrade_tool LD"
+    echo "    rkbin/tools/upgrade_tool EF ${IMAGE_DIR}/MiniLoaderAll.bin"
+    echo "    rkbin/tools/upgrade_tool UF ${OUT_UPDATE_IMG}"
+    echo "-----------------------------------------"
+}
+
 ##############################################
 
 
@@ -399,8 +605,8 @@ else
     elif [ $BUILD_TARGET == kernel ];then
         build_kernel
         exit 0
-    elif [ $BUILD_TARGET == buildroot ];then
-        build_buildroot
+    elif [ $BUILD_TARGET == rootfs -o $BUILD_TARGET == buildroot ];then
+        build_rootfs
         exit 0
     elif [ $BUILD_TARGET == sd-img ]; then
         # Automatically re-run script under sudo if not root
@@ -411,6 +617,15 @@ else
         fi
         build_sdimg
         exit 0
+    elif [ $BUILD_TARGET == usb-img ]; then
+        # Automatically re-run script under sudo if not root
+        if [ $(id -u) -ne 0 ]; then
+            echo "Re-running script under sudo..."
+            sudo --preserve-env "$0" "$@"
+            exit
+        fi
+        build_usbimg
+        exit 0
     elif [ $BUILD_TARGET == emmc-img ]; then
         # Automatically re-run script under sudo if not root
         if [ $(id -u) -ne 0 ]; then


编译命令


sudo ./build.sh nanopi_r6c-ubuntu-jammy-desktop.mk

sudo ./build.sh usb-img

将其他主板的驱动移植到友善SDK上即可编译对应硬件的ubuntu固件


commit b311a19cf853691469b6c31c528d04c5be8ddd67
Author: lxg <xiaogang.li>
Date:   Tue Jun 23 16:56:03 2026 +0800

    适配 WIF 3588主板

diff --git a/buildroot-rk3588/README.txt b/buildroot-rk3588/README.txt
index cfb1e8674..7aca96354 100644
--- a/buildroot-rk3588/README.txt
+++ b/buildroot-rk3588/README.txt
@@ -10,12 +10,16 @@
 # The final step: Start building
 ./build.sh rk3588.mk
 
-# Build Ubuntu image (minimal integration, use ubuntu/rootfs-ubuntu-jammy-desktop-arm64.tgz)
-./build.sh rk3588-ubuntu-jammy-desktop.mk
 
 # Build Ubuntu image for NanoPi R6C
 ./build.sh nanopi_r6c-ubuntu-jammy-desktop.mk
 
+# Build custom board: RK3588 V3 WIF HDMI (DTB: rk3588-nanopi6-rev0e.dtb, board hw-rev 0x0e)
+./build.sh wif-ubuntu-jammy-desktop.mk
+
+# Build kernel only for the custom board (packs only rk3588-nanopi6-rev0e.dtb into resource.img)
+./build.sh kernel
+
 # Optional split build
 ./build.sh rootfs
 ./build.sh sd-img
diff --git a/buildroot-rk3588/device/friendlyelec/rk3588/wif-ubuntu-jammy-desktop.mk b/buildroot-rk3588/device/friendlyelec/rk3588/wif-ubuntu-jammy-desktop.mk
new file mode 100644
index 000000000..4cc9f50d6
--- /dev/null
+++ b/buildroot-rk3588/device/friendlyelec/rk3588/wif-ubuntu-jammy-desktop.mk
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Custom board config: RK3588 V3 WIF HDMI (EVB-based)
+# Rootfs: ubuntu-jammy-desktop-arm64
+# Kernel DTB: rk3588-nanopi6-rev0e.dtb (board hw-rev 0x0e; name must match
+# U-Boot set_dtb_name() -> "rk3588-nanopi6-rev%02x.dtb"), packed alone into resource.img
+
+. device/friendlyelec/rk3588/base.mk
+
+# Rootfs (ubuntu desktop archive)
+TARGET_OSNAME=ubuntu-jammy-desktop-arm64
+TARGET_IMAGE_DIRNAME=${TARGET_OSNAME}
+TARGET_ROOTFS_ARCHIVE=ubuntu/rootfs-ubuntu-jammy-desktop-arm64.tgz
+
+# Only build/pack the custom board DTB into resource.img
+TARGET_KERNEL_DTBS=rk3588-nanopi6-rev0e.dtb
+
+# Output image names
+TARGET_SD_RAW_FILENAME=wif-ubuntu-jammy-desktop_$(date +%Y%m%d)_rk3588_arm64_sd.img
+TARGET_EFLASHER_RAW_FILENAME=wif-ubuntu-jammy-desktop_$(date +%Y%m%d)_rk3588_arm64_eflasher.img
diff --git a/buildroot-rk3588/kernel/arch/arm64/Makefile b/buildroot-rk3588/kernel/arch/arm64/Makefile
index b557e9bbc..dde61b24c 100644
--- a/buildroot-rk3588/kernel/arch/arm64/Makefile
+++ b/buildroot-rk3588/kernel/arch/arm64/Makefile
@@ -240,7 +240,7 @@ kernel.img: Image
 	@echo '  Image:  kernel.img is ready'
 
 ifeq ($(CONFIG_VENDOR_FRIENDLYELEC),y)
-DTBS := rk3*-nanopi*-rev*.dtb
+DTBS ?= rk3*-nanopi*-rev*.dtb
 
 resource.img: dtbs $(LOGO) $(LOGO_KERNEL)
 	$(Q)$(srctree)/scripts/mkimg --dtb $(DTBS) --keep-dtb-name
diff --git a/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/Makefile b/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/Makefile
index b32bf4f44..b6e07c419 100644
--- a/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/Makefile
+++ b/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/Makefile
@@ -49,6 +49,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
 	rk3588-nanopi6-rev0b.dtb \
 	rk3588-nanopi6-rev0c.dtb
 
+dtb-$(CONFIG_ARCH_ROCKCHIP) += \
+	rk3588-nanopi6-rev0e.dtb
+
 else
 
 dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-evb.dtb
diff --git a/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev0e.dts b/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev0e.dts
new file mode 100644
index 000000000..6871ebde2
--- /dev/null
+++ b/buildroot-rk3588/kernel/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev0e.dts
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
+ *
+ * Custom board: RK3588 EVB7 LP4 V10 (WIF/HDMI), rebased on the native
+ * kernel-6.1 EVB7 device-tree chain so it boots on this BSP.
+ *
+ * The DTB filename must stay rk3588-nanopi6-rev0e.dtb so that U-Boot
+ * set_dtb_name() ("rk3588-nanopi6-rev%02x.dtb", board hw-rev 0x0e) loads it.
+ */
+
+/dts-v1/;
+
+#include "rk3588-evb7-lp4.dtsi"
+/*
+ * The EVB7 imx415 camera overlay is intentionally NOT included: this board has
+ * no MIPI camera, and its vcc_mipidphy0 regulator / mipidphy0_pwr pinctrl claim
+ * gpio1 PB2, which this board needs for the HDMI-RX hotplug-detect input.
+ */
+#include "rk3588-linux.dtsi"
+
+/ {
+	model = "Rockchip RK3588 EVB7 LP4 V10 Board";
+	compatible = "rockchip,rk3588-evb7-lp4-v10", "rockchip,rk3588";
+};
+
+/ {
+	/*
+	 * Override the mmc aliases from rk3588-linux.dtsi (mmc0=&sdhci ->
+	 * eMMC=mmcblk0). The FriendlyElec rootfs + bootargs expect the stock
+	 * numbering where eMMC is mmcblk2 (root=/dev/mmcblk2p8, data on
+	 * mmcblk2p9). Without this the initramfs cannot find the root device
+	 * and drops to the (initramfs) rescue shell.
+	 */
+	aliases {
+		mmc0 = &sdmmc;   /* micro-SD -> mmcblk0 */
+		mmc1 = &sdio;    /* WiFi SDIO -> mmcblk1 */
+		mmc2 = &sdhci;   /* eMMC -> mmcblk2 */
+	};
+};
+
+/*
+ * PCIe FIX derived from the known-good 5.10 board DTS for THIS exact board
+ * (rk3588-wif-hdmi-1024x768.dtsi). The EVB7 6.1 PCIe nodes describe different
+ * wiring, which is why a config read to the on-board RTL8111 NIC on pcie2x1l0
+ * (fe170000) never returns and hard-locks CPU3 in dw_pcie_read().
+ *
+ * Root-cause deltas vs. EVB7 (all corrected below):
+ *  - pcie2x1l0: EVB7 omits the rtl8111_isolate pinctrl that puts the NIC
+ *    reset/isolation pin (gpio1 PB4) in GPIO + pull-up. Without it the NIC
+ *    reset is ineffective -> config read hangs.
+ *  - pcie3x4: EVB7 uses the wrong reset pin (gpio4 PB3) and lacks prsnt-gpios,
+ *    num-lanes and perst timing. The real board uses gpio4 PB6 / prsnt PB5.
+ *  - vcc3v3_pcie30: EVB7 enable-gpio is gpio2 PC5; the real board is gpio1 PC6.
+ */
+&pinctrl {
+	rtl8111 {
+		rtl8111_isolate: rtl8111-isolate {
+			rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+&vcc3v3_pcie30 {
+	gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>;
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&rtl8111_isolate>;
+	status = "okay";
+};
+
+&pcie3x4 {
+	num-lanes = <2>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	prsnt-gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>;
+	rockchip,perst-inactive-ms = <500>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	/* drop EVB7's pcie30x4_clkreqn_m1 pinctrl (not used on this board) */
+	/delete-property/ pinctrl-0;
+	/delete-property/ pinctrl-names;
+	status = "okay";
+};
+
+/* =====================================================================
+ * Board peripheral configuration ported from the known-good WIF/HDMI
+ * board DTS (rk3588-wif-hdmi-1024x768.dtsi, kernel-5.10) so the EVB7 6.1
+ * base actually matches THIS board's wiring.
+ *
+ * The EVB7 base defines a superset of nodes but with EVB7 GPIO wiring;
+ * everything below re-points those nodes at the real board's pins and
+ * disables EVB7-only peripherals that are not present on this board.
+ * ===================================================================== */
+
+/* ---- New board-only devices (not present in the EVB7 base) ---- */
+/ {
+	/* USB OTG port 5V power switch */
+	vcc5v0_otg: vcc5v0-otg-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_otg";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+		vin-supply = <&vcc5v0_usb>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v0_otg_en>;
+	};
+
+	leds: leds {
+		compatible = "gpio-leds";
+		status = "disabled";
+		power-green {
+			gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&run_led>;
+			linux,default-trigger = "none";
+			default-state = "on";
+			retain-state-suspended;
+		};
+	};
+
+	/* EC20/EC200N 4G module power control */
+	lzt-ec20 {
+		compatible = "rockchip,lzt-ec20";
+		lte-power-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_LOW>;	/* 4G_DC_EN */
+		status = "okay";
+	};
+
+	/* Board-specific GPIO bring-up (power rails / mux selects) */
+	wif_gpio {
+		status = "okay";
+		compatible = "wif_gpio";
+		otg_host {
+			gpio_num = <&gpio2 RK_PC0 GPIO_ACTIVE_LOW>;	/* 0:otg,1:host */
+			gpio_function = <0>;	/* 0:output 1:input */
+		};
+		5v_en1 {
+			gpio_num = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+			gpio_function = <0>;
+		};
+		5v_en2 {
+			gpio_num = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>;
+			gpio_function = <0>;
+		};
+		12v_en1 {
+			gpio_num = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
+			gpio_function = <0>;
+		};
+		12v_en2 {
+			gpio_num = <&gpio2 RK_PC3 GPIO_ACTIVE_HIGH>;
+			gpio_function = <0>;
+		};
+		gpio0b2 {
+			gpio_num = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
+			gpio_function = <0>;
+		};
+		gpio1a5 {
+			gpio_num = <&gpio1 RK_PA5 GPIO_ACTIVE_LOW>;
+			gpio_function = <0>;
+		};
+		gpio1a7 {
+			gpio_num = <&gpio1 RK_PA7 GPIO_ACTIVE_LOW>;
+			gpio_function = <0>;
+		};
+		gpio1d7 {
+			gpio_num = <&gpio1 RK_PD7 GPIO_ACTIVE_LOW>;
+			gpio_function = <0>;
+		};
+		run_led {
+			gpio_num = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>;
+			gpio_function = <0>;
+		};
+	};
+};
+
+/* ---- Audio: ES8388 codec card ---- */
+&es8388_sound {
+	hp-det-gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>;
+	spk-con-gpio = <&gpio4 RK_PA4 GPIO_ACTIVE_LOW>;
+	/* this board has no separate headphone enable / power-sequencing GPIO */
+	/delete-property/ hp-con-gpio;
+	/delete-property/ rockchip,pre-power-on-delay-ms;
+	/delete-property/ rockchip,post-power-down-delay-ms;
+	rockchip,audio-routing =
+		"Headphone", "LOUT1",
+		"Headphone", "ROUT1",
+		"Speaker", "LOUT1",
+		"Speaker", "ROUT1",
+		"Headphone", "Headphone Power",
+		"Headphone", "Headphone Power",
+		"Speaker", "Speaker Power",
+		"Speaker", "Speaker Power",
+		"LINPUT1", "Main Mic",
+		"LINPUT2", "Main Mic",
+		"RINPUT1", "Headset Mic",
+		"RINPUT2", "Headset Mic";
+
+	play-pause-key {
+		press-threshold-microvolt = <5000>;
+	};
+
+	button-up {
+		label = "Volume Up";
+		linux,code = <KEY_VOLUMEUP>;
+		press-threshold-microvolt = <80000>;
+	};
+
+	button-down {
+		label = "Volume Down";
+		linux,code = <KEY_VOLUMEDOWN>;
+		press-threshold-microvolt = <115000>;
+	};
+};
+
+/* ---- Ethernet: GMAC1 + RTL8211F PHY ---- */
+&gmac1 {
+	phy-mode = "rgmii";
+	rx_delay = <0x3f>;
+};
+
+/* ---- HDMI: only HDMI1 (TX) + HDMI-RX are wired on this board ---- */
+&hdmi0 {
+	/delete-property/ enable-gpios;
+	status = "disabled";
+};
+
+&hdmi0_in_vp0 {
+	status = "disabled";
+};
+
+&hdmi0_sound {
+	status = "disabled";
+};
+
+&hdptxphy_hdmi0 {
+	status = "disabled";
+};
+
+&route_hdmi0 {
+	status = "disabled";
+};
+
+&hdmi1 {
+	/delete-property/ enable-gpios;
+};
+
+&hdmirx_ctrler {
+	/* HPD-detect input moves from EVB7's gpio1 PD5 to this board's gpio1 PB2 */
+	hdmirx-det-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_LOW>;
+};
+
+/* ---- EVB7-only display / storage / sensors not present on this board ---- */
+&backlight {
+	status = "disabled";
+};
+
+&dp0 {
+	status = "disabled";
+};
+
+&dp0_in_vp2 {
+	status = "disabled";
+};
+
+&dp1 {
+	status = "disabled";
+};
+
+&dp1_in_vp2 {
+	status = "disabled";
+};
+
+&dsi0 {
+	status = "disabled";
+};
+
+&dsi0_in_vp3 {
+	status = "disabled";
+};
+
+&route_dsi0 {
+	status = "disabled";
+};
+
+&sata0 {
+	status = "disabled";
+};
+
+&i2c5 {
+	/* EVB7 capacitive-touch panel (gt1x / hynitron) – not on this board */
+	status = "disabled";
+};
+
+&icm42607_acc {
+	status = "disabled";
+};
+
+&icm42607_gyro {
+	status = "disabled";
+};
+
+&i2s5_8ch {
+	status = "disabled";
+};
+
+&pwm1 {
+	status = "disabled";
+};
+
+&pwm3 {
+	status = "disabled";
+};
+
+&fan {
+	status = "disabled";
+};
+
+/* Free the MIPI-CSI power pins (gpio1 PD2/PD3) for wif_gpio – no cameras here */
+&vcc_mipicsi0 {
+	status = "disabled";
+};
+
+&vcc_mipicsi1 {
+	status = "disabled";
+};
+
+/* ---- USB power switches and PHYs ---- */
+&vcc5v0_host {
+	gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
+};
+
+&vcc_3v3_sd_s0 {
+	gpio = <&gpio0 RK_PD3 GPIO_ACTIVE_LOW>;
+};
+
+&u2phy0_otg {
+	vbus-supply = <&vcc5v0_otg>;
+};
+
+&u2phy1_otg {
+	/delete-property/ phy-supply;
+	vbus-supply = <&vcc5v0_host>;
+};
+
+&usbdp_phy1_u3 {
+	maximum-speed = "high-speed";
+};
+
+/*
+ * USB3 host-only port (fcd00000). In 6.1 the parent wrapper usbhost3_0 is
+ * disabled by default, so it must be enabled too — the 5.10 source only set
+ * the usbhost_dwc3_0 child because its base enabled the wrapper differently.
+ */
+&usbhost3_0 {
+	status = "okay";
+};
+
+&usbhost_dwc3_0 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+/* ---- WiFi (AP6256) / Bluetooth / SDIO ---- */
+&sdio_pwrseq {
+	reset-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_LOW>;
+};
+
+&wireless_wlan {
+	wifi_chip_type = "ap6256";
+	WIFI,host_wake_irq = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>;
+	WIFI,poweren_gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
+	status = "disabled";
+};
+
+&wireless_bluetooth {
+	BT,reset_gpio    = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>;
+	BT,wake_gpio     = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>;
+	BT,wake_host_irq = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+	status = "disabled";
+};
+
+/* ---- Serial ports: RS485 (uart0), RS232 (uart7), uart8 ---- */
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0m0_xfer>;
+	status = "okay";
+};
+
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart7m1_xfer>;
+	status = "okay";
+};
+
+&uart8 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart8m0_xfer>;
+	status = "okay";
+};
+
+/* ---- Re-point existing EVB7 pinctrl groups at this board's pins ---- */
+&vcc5v0_host_en {
+	rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+};
+
+&hdmirx_det {
+	rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>;
+};
+
+&sd_s0_pwr {
+	rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
+};
+
+&wifi_enable_h {
+	rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+};
+
+&wifi_host_wake_irq {
+	rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>;
+};
+
+&bt_reset_gpio {
+	rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>;
+};
+
+&bt_wake_gpio {
+	rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
+};
+
+&bt_irq_gpio {
+	rockchip,pins = <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
+};
+
+/* ---- New pinctrl groups for board-only devices ---- */
+&pinctrl {
+	led {
+		run_led: run-led {
+			rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		vcc5v0_otg_en: vcc5v0-otg-en {
+			rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
diff --git a/buildroot-rk3588/scripts/build.sh b/buildroot-rk3588/scripts/build.sh
index f9a083328..35ed832d1 100755
--- a/buildroot-rk3588/scripts/build.sh
+++ b/buildroot-rk3588/scripts/build.sh
@@ -113,10 +113,11 @@ function build_kernel(){
     echo "TARGET_PLAT          = $TARGET_PLAT"
     echo "TARGET_KERNEL_CONFIG = $TARGET_KERNEL_CONFIG"
     echo "TARGET_OSNAME        = $TARGET_OSNAME"
+    echo "TARGET_KERNEL_DTBS   = ${TARGET_KERNEL_DTBS:-<all nanopi>}"
     echo "=========================================="
 
     (cd ${SDFUSE_DIR} && {
-        SKIP_DISTCLEAN=1 DISABLE_MKIMG=1 KCFG=${TARGET_KERNEL_CONFIG} KERNEL_SRC=${TOP_DIR}/kernel ./build-kernel.sh ${TARGET_OSNAME}
+        SKIP_DISTCLEAN=1 DISABLE_MKIMG=1 KCFG=${TARGET_KERNEL_CONFIG} DTBS="${TARGET_KERNEL_DTBS:-}" KERNEL_SRC=${TOP_DIR}/kernel ./build-kernel.sh ${TARGET_OSNAME}
     })
 
     if [ $? -eq 0 ]; then
diff --git a/buildroot-rk3588/scripts/sd-fuse/build-kernel.sh b/buildroot-rk3588/scripts/sd-fuse/build-kernel.sh
index 286e3902c..bfebe6aea 100755
--- a/buildroot-rk3588/scripts/sd-fuse/build-kernel.sh
+++ b/buildroot-rk3588/scripts/sd-fuse/build-kernel.sh
@@ -27,6 +27,7 @@ true ${KERNEL_LOGO:=}
 true ${MK_HEADERS_DEB:=0}
 true ${SKIP_DISTCLEAN:=0}
 true ${BUILD_THIRD_PARTY_DRIVER:=1}
+true ${DTBS:=}
 DEFAULT_KCFG="nanopi6_linux_defconfig kvm.config"
 true ${KCFG:=${DEFAULT_KCFG}}
 true ${TARGET_OS:=$(echo ${1,,}|sed 's/\///g')}
@@ -237,7 +238,7 @@ function build_kernel() {
         sed -i "s/\(.*PROT_MT_SLOT\).*/# \1 is not set/g" .config
     fi
 
-    make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} ${KALL} -j$(nproc)
+    make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} ${KALL} ${DTBS:+DTBS="${DTBS}"} -j$(nproc)
     if [ $? -ne 0 ]; then
             echo "failed to build kernel."
             exit 1


编译命令


sudo ./build.sh wif-ubuntu-jammy-desktop.mk

sudo ./build.sh usb-img