Rewrite README to reflect tart LineageOS ATV port
This commit is contained in:
parent
9a659abcf3
commit
9063cf7f8e
3 changed files with 181 additions and 254 deletions
43
README.md
43
README.md
|
|
@ -1,16 +1,41 @@
|
|||
AOSP 16 device configuration for Orangepi 5 Pro.
|
||||
# android_device_rockchip_tart
|
||||
|
||||
Ported from KonstaKang's raspberry vanilla aosp 16 project.
|
||||
Device tree for building [LineageOS 23.2](https://lineageos.org/) (Android 16, Android TV variant) for the **Orange Pi 5 Ultra**, codename **`tart`**.
|
||||
|
||||
Not working -
|
||||
## Hardware
|
||||
|
||||
Camera
|
||||
3.5 mm audio
|
||||
- **SoC:** Rockchip RK3588 (4x Cortex-A76 @ 2.4GHz + 4x Cortex-A55 @ 1.8GHz)
|
||||
- **GPU:** ARM Mali-G610 MP4 "Odin" (Valhall, OpenGL ES 3.2 / Vulkan 1.2 / OpenCL 2.2)
|
||||
- **Ethernet:** 2.5GbE via Realtek RTL8125BG (PCIe)
|
||||
- **WiFi/BT:** WiFi 6E + Bluetooth 5.3 via Ampak AP6611S module (Synaptics SYN43711 chipset)
|
||||
- **Audio:** Everest ES8388 codec (3.5mm jack, mic, HDMI eARC)
|
||||
- **Display:** HDMI 2.1 out (8K60), 4-lane MIPI DSI out, HDMI 2.0 capture in
|
||||
|
||||
Working -
|
||||
## Status
|
||||
|
||||
everything else including vulkan.
|
||||
This is an active bring-up port, not a finished build. Working/not-working status changes frequently — the authoritative, currently-maintained list lives in [`AGENTS.md`](../../AGENTS.md) and [`CLAUDE.md`](../../CLAUDE.md) at the root of the parent project repo, not here. As of the last update to this README:
|
||||
|
||||
This project can be ported to any device which utilises Rockchip SoC with minor changes.
|
||||
**Working:**
|
||||
- Boots to Android on real hardware (kernel, all 8 CPUs, GPU/USB/PCIe detected)
|
||||
- `breakfast tart` + plain `mka` build system/vendor/boot/ramdisk images
|
||||
- GPT image creation (`mkimg.sh`) and flashing via U-Boot/extlinux
|
||||
|
||||
any doubts, feel free to mail me at vdarbha0473@gmail.com
|
||||
**Not working / deferred:**
|
||||
- GPU acceleration — stock AOSP mesa3d only, no Panfrost yet
|
||||
- SELinux enforcing (currently permissive)
|
||||
- Camera, HDMI capture input, RTL8125BG Ethernet firmware, and WiFi/BT driver support are all unverified/in progress
|
||||
|
||||
This device has **no Android recovery** (`TARGET_NO_RECOVERY := true`) — it boots via U-Boot + `extlinux.conf`, not a recovery/OTA-zip flow. Use plain `mka`, not `mka bacon` (see [`BoardConfig.mk`](BoardConfig.mk) and the parent project's build docs for why `bacon` fails on this device).
|
||||
|
||||
## Building and flashing
|
||||
|
||||
Full setup, sync, and build instructions live in the [`android_local_manifest`](https://git.bscubed.dev/lineage-rockchip/android_local_manifest) README — this repo is just one of several projects (device tree, kernel, vendor blobs) that manifest pulls in.
|
||||
|
||||
Two scripts in this repo are used post-build:
|
||||
|
||||
- [`mkimg.sh`](mkimg.sh) — assembles a flashable GPT image (U-Boot + FAT32 boot partition with `extlinux.conf`/kernel/DTB/ramdisk, plus system/vendor/metadata/userdata partitions) from the build output. Run from the source tree root after `mka`, in the same shell used to build (needs `TARGET_PRODUCT`/`ANDROID_PRODUCT_OUT` from `lunch`/`breakfast`). Do not run with `sudo` — it escalates internally per-command only where needed.
|
||||
- [`wrimg.sh`](wrimg.sh) — writes individual partition images (`boot`/`system`/`vendor`) directly to an already-flashed physical device for fast dev-iteration re-flashes, without rebuilding the whole GPT image. Also supports `wipe` (reformat userdata) and `wipe-metadata`. Auto-detects the target block device by matching partition labels/sizes against `mkimg.sh`'s 5-partition layout.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0. Originally forked from KonstaKang's Orange Pi 5 Pro AOSP device tree and dvab-sarma's port; substantially modified for the Orange Pi 5 Ultra / LineageOS ATV port.
|
||||
|
|
|
|||
201
mkimg.sh
201
mkimg.sh
|
|
@ -1,98 +1,191 @@
|
|||
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2025 Venkata Atchuta Bheemeswara Sarma Darbha
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
#!/bin/bash
|
||||
# Create an RK3588 GPT AOSP image (no changes to original sector/start/size values).
|
||||
# - Writes U-Boot at sector 64
|
||||
# - Creates GPT with named partitions so Android creates /dev/block/by-name/*
|
||||
# - Copies boot/system/vendor images (dd)
|
||||
# - Creates metadata/userdata ext4 and sets proper GPT & fs labels
|
||||
# - Uses kpartx to map partitions and cleans up reliably
|
||||
#
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
DEVICE_PATH=device/rockchip/tart
|
||||
KERNEL_PATH=device/rockchip/tart-kernel
|
||||
|
||||
# Helper: print error and cleanup
|
||||
exit_with_error() {
|
||||
echo $@
|
||||
echo "ERROR: $*" >&2
|
||||
cleanup || true
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check required env vars
|
||||
if [ -z ${TARGET_PRODUCT} ]; then
|
||||
exit_with_error "TARGET_PRODUCT environment variable is not set. Run lunch first."
|
||||
fi
|
||||
cleanup() {
|
||||
|
||||
if [ -z ${ANDROID_PRODUCT_OUT} ]; then
|
||||
exit_with_error "ANDROID_PRODUCT_OUT environment variable is not set. Run lunch first."
|
||||
fi
|
||||
if [ -n "${LOOPDEV:-}" ]; then
|
||||
if sudo kpartx -l "${IMAGE_PATH}" >/dev/null 2>&1; then
|
||||
sudo kpartx -d "${IMAGE_PATH}" || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Check required images
|
||||
for PARTITION in "boot" "system" "vendor"; do
|
||||
if [ ! -f ${ANDROID_PRODUCT_OUT}/${PARTITION}.img ]; then
|
||||
exit_with_error "Partition image not found: ${PARTITION}.img. Run 'make ${PARTITION}image' first."
|
||||
trap cleanup EXIT
|
||||
|
||||
|
||||
: "${TARGET_PRODUCT:?TARGET_PRODUCT environment variable is not set. Run lunch first.}"
|
||||
: "${ANDROID_PRODUCT_OUT:?ANDROID_PRODUCT_OUT environment variable is not set. Run lunch first.}"
|
||||
|
||||
|
||||
for PART in boot system vendor; do
|
||||
if [ ! -f "${ANDROID_PRODUCT_OUT}/${PART}.img" ]; then
|
||||
exit_with_error "Missing partition image: ${ANDROID_PRODUCT_OUT}/${PART}.img — run 'make ${PART}image' first."
|
||||
fi
|
||||
done
|
||||
|
||||
UBOOT_BIN=device/rockchip/tart-kernel/u-boot-rockchip.bin
|
||||
|
||||
if [ ! -f ${UBOOT_BIN} ]; then
|
||||
exit_with_error "Missing u-boot-rockchip.bin! Make sure it's built and placed at ${UBOOT_BIN}"
|
||||
UBOOT_BIN=${KERNEL_PATH}/u-boot-rockchip.bin
|
||||
if [ ! -f "${UBOOT_BIN}" ]; then
|
||||
exit_with_error "Missing U-Boot: ${UBOOT_BIN}"
|
||||
fi
|
||||
|
||||
VERSION=OrangePi_5Pro_aosp
|
||||
DATE=$(date +%Y%m%d)
|
||||
TARGET=$(echo ${TARGET_PRODUCT} | sed 's/^aosp_//')
|
||||
IMGNAME=${VERSION}-${DATE}-${TARGET}.img
|
||||
LINEAGE_VERSION=$(build/soong/bin/get_build_var LINEAGE_VERSION)
|
||||
if [ -z "${LINEAGE_VERSION}" ]; then
|
||||
exit_with_error "LINEAGE_VERSION is empty. Run 'lunch' first and ensure the build environment is configured."
|
||||
fi
|
||||
IMGSIZE=19456MiB
|
||||
IMAGE_PATH="${ANDROID_PRODUCT_OUT}/lineage-${LINEAGE_VERSION}.img"
|
||||
|
||||
if [ -f ${ANDROID_PRODUCT_OUT}/${IMGNAME} ]; then
|
||||
exit_with_error "${ANDROID_PRODUCT_OUT}/${IMGNAME} already exists!"
|
||||
if [ -f "${IMAGE_PATH}" ]; then
|
||||
echo "Overwriting existing image: ${IMAGE_PATH}"
|
||||
sudo rm -f "${IMAGE_PATH}"
|
||||
fi
|
||||
|
||||
echo "Creating image file ${ANDROID_PRODUCT_OUT}/${IMGNAME}..."
|
||||
sudo fallocate -l ${IMGSIZE} ${ANDROID_PRODUCT_OUT}/${IMGNAME}
|
||||
echo "Creating image file ${IMAGE_PATH} (${IMGSIZE})..."
|
||||
sudo fallocate -l "${IMGSIZE}" "${IMAGE_PATH}"
|
||||
sync
|
||||
|
||||
echo "Writing U-Boot to sector 64..."
|
||||
sudo dd if=${UBOOT_BIN} of=${ANDROID_PRODUCT_OUT}/${IMGNAME} seek=64 bs=512 conv=notrunc
|
||||
# write u-boot binary to offset 64*512 = sector 64
|
||||
sudo dd if="${UBOOT_BIN}" of="${IMAGE_PATH}" seek=64 bs=512 conv=notrunc status=progress
|
||||
sync
|
||||
|
||||
echo "Partitioning image using sfdisk..."
|
||||
echo "Partitioning image using sfdisk (GPT) with explicit partition NAMES..."
|
||||
|
||||
|
||||
PART_TABLE=$(cat <<EOF
|
||||
label: dos
|
||||
label: gpt
|
||||
unit: sectors
|
||||
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}1 : start=32768, size=262144, type=c, bootable
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}2 : start=294912, size=7122944, type=5
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}3 : start=7417856, type=83
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}5 : start=303104, size=6291456, type=83
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}6 : start=6596608, size=786432, type=83
|
||||
${ANDROID_PRODUCT_OUT}/${IMGNAME}7 : start=7385088, size=32768, type=83
|
||||
# Partition 1: boot (FAT32)
|
||||
${IMAGE_PATH}1 : start=32768, size=262144, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="boot"
|
||||
|
||||
# Partition 2: system (EXT4)
|
||||
${IMAGE_PATH}2 : start=303104, size=6291456, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="system"
|
||||
|
||||
# Partition 3: vendor (EXT4)
|
||||
${IMAGE_PATH}3 : start=6596608, size=786432, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="vendor"
|
||||
|
||||
# Partition 4: metadata (EXT4)
|
||||
${IMAGE_PATH}4 : start=7385088, size=32768, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="metadata"
|
||||
|
||||
# Partition 5: userdata (EXT4)
|
||||
${IMAGE_PATH}5 : start=7417856, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="userdata"
|
||||
EOF
|
||||
)
|
||||
|
||||
echo "$PART_TABLE" | sudo sfdisk ${ANDROID_PRODUCT_OUT}/${IMGNAME}
|
||||
# Use a temporary file for sfdisk input so variable interpolation is safe
|
||||
echo "${PART_TABLE}" | sudo sfdisk "${IMAGE_PATH}"
|
||||
sync
|
||||
|
||||
LOOPDEV=$(sudo kpartx -av ${ANDROID_PRODUCT_OUT}/${IMGNAME} | awk 'NR==1{ sub(/p[0-9]$/, "", $3); print $3 }')
|
||||
if [ -z ${LOOPDEV} ]; then
|
||||
exit_with_error "Unable to find loop device!"
|
||||
echo "Mapping partitions using kpartx..."
|
||||
|
||||
KPARTX_OUT=$(sudo kpartx -av "${IMAGE_PATH}")
|
||||
echo "${KPARTX_OUT}"
|
||||
|
||||
LOOPDEV=$(echo "${KPARTX_OUT}" | awk '/add map/ {dev=$3} END { sub(/p[0-9]+$/, "", dev); print dev }')
|
||||
if [ -z "${LOOPDEV}" ]; then
|
||||
exit_with_error "kpartx failed to map partitions or to return a loop device name."
|
||||
fi
|
||||
echo "Image mounted as /dev/${LOOPDEV}"
|
||||
echo "Mapped image as /dev/mapper/${LOOPDEV}p* (base loop: ${LOOPDEV})"
|
||||
|
||||
# Wait for device nodes to appear
|
||||
sleep 1
|
||||
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
||||
echo "Waiting a bit longer for /dev/mapper/${LOOPDEV}p1 to appear..."
|
||||
sleep 1
|
||||
fi
|
||||
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
||||
exit_with_error "Device mapper nodes not found (e.g. /dev/mapper/${LOOPDEV}p1). Check kpartx output."
|
||||
fi
|
||||
|
||||
echo "Copying boot..."
|
||||
sudo dd if=${ANDROID_PRODUCT_OUT}/boot.img of=/dev/mapper/${LOOPDEV}p1 bs=1M
|
||||
echo "Copying system..."
|
||||
sudo dd if=${ANDROID_PRODUCT_OUT}/system.img of=/dev/mapper/${LOOPDEV}p5 bs=1M
|
||||
echo "Copying vendor..."
|
||||
sudo dd if=${ANDROID_PRODUCT_OUT}/vendor.img of=/dev/mapper/${LOOPDEV}p6 bs=1M
|
||||
# --- Copy images into partitions ---
|
||||
echo "Creating FAT32 filesystem on p1 (boot partition)..."
|
||||
sudo mkfs.vfat -F 32 -n "boot" "/dev/mapper/${LOOPDEV}p1"
|
||||
|
||||
# Mount the boot partition and copy kernel/boot files
|
||||
BOOT_MOUNT=$(mktemp -d)
|
||||
sudo mount "/dev/mapper/${LOOPDEV}p1" "${BOOT_MOUNT}"
|
||||
sudo cp ${KERNEL_PATH}/Image "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/rk3588-orangepi-5-ultra.dtb "${BOOT_MOUNT}/"
|
||||
sudo mkdir -p "${BOOT_MOUNT}/extlinux"
|
||||
sudo tee "${BOOT_MOUNT}/extlinux/extlinux.conf" > /dev/null << 'EXTLINUX_EOF'
|
||||
label LineageOS Android TV
|
||||
kernel /Image
|
||||
fdt /rk3588-orangepi-5-ultra.dtb
|
||||
initrd /ramdisk.img
|
||||
append console=ttyS2,1500000 no_console_suspend root=/dev/ram0 rootwait androidboot.hardware=tart androidboot.selinux=permissive androidboot.boot_devices=fe2c0000.mmc
|
||||
EXTLINUX_EOF
|
||||
sudo cp ${KERNEL_PATH}/boot.scr "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/android-sdcard.dtbo "${BOOT_MOUNT}/"
|
||||
sudo cp "${ANDROID_PRODUCT_OUT}/ramdisk.img" "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/config.txt "${BOOT_MOUNT}/"
|
||||
sudo umount "${BOOT_MOUNT}"
|
||||
rmdir "${BOOT_MOUNT}"
|
||||
|
||||
echo "Creating metadata..."
|
||||
sudo mkfs.ext4 /dev/mapper/${LOOPDEV}p7 -I 512 -L metadata
|
||||
echo "Writing system image to p2 (raw dd)."
|
||||
# Use conv=notrunc so we don't shrink partition image area; status=progress for visibility
|
||||
sudo dd if="${ANDROID_PRODUCT_OUT}/system.img" of="/dev/mapper/${LOOPDEV}p2" bs=1M conv=notrunc status=progress
|
||||
|
||||
echo "Writing vendor image to p3 (raw dd)."
|
||||
sudo dd if="${ANDROID_PRODUCT_OUT}/vendor.img" of="/dev/mapper/${LOOPDEV}p3" bs=1M conv=notrunc status=progress
|
||||
|
||||
echo "Creating userdata..."
|
||||
sudo mkfs.ext4 /dev/mapper/${LOOPDEV}p3 -I 512 -L userdata
|
||||
sync
|
||||
|
||||
sudo kpartx -d "/dev/${LOOPDEV}"
|
||||
sudo chown ${USER}:${USER} ${ANDROID_PRODUCT_OUT}/${IMGNAME}
|
||||
# --- Ensure filesystem labels and types are correct ---
|
||||
# Note: dd'ing system/vendor may already contain an internal FS label; we force the GPT
|
||||
# partition name above and set the filesystem label to match as a guard.
|
||||
echo "Setting filesystem labels on p2 (system) and p3 (vendor) and creating metadata/userdata..."
|
||||
|
||||
echo "✅ Done! Created ${ANDROID_PRODUCT_OUT}/${IMGNAME} with U-Boot and properly aligned partitions."
|
||||
# Try to set ext4 label on system; if it isn't an ext4, warn but continue.
|
||||
set +e
|
||||
sudo e2label "/dev/mapper/${LOOPDEV}p2" system 2>/dev/null
|
||||
E2_RC=$?
|
||||
if [ "${E2_RC}" -ne 0 ]; then
|
||||
echo "Warning: /dev/mapper/${LOOPDEV}p2 does not appear to be ext4 or e2label failed. Continuing."
|
||||
fi
|
||||
sudo e2label "/dev/mapper/${LOOPDEV}p3" vendor 2>/dev/null || echo "Warning: e2label on vendor failed (maybe not ext4)."
|
||||
|
||||
set -e
|
||||
|
||||
# Create/format metadata and userdata partitions and set filesystem labels
|
||||
sudo mkfs.ext4 -F -L metadata "/dev/mapper/${LOOPDEV}p4"
|
||||
sudo mkfs.ext4 -F -L userdata "/dev/mapper/${LOOPDEV}p5"
|
||||
sync
|
||||
|
||||
# Final sanity: list by-name symlinks
|
||||
echo "Partition mapping summary (kpartx):"
|
||||
sudo ls -l /dev/mapper/"${LOOPDEV}"* || true
|
||||
|
||||
# Unmap now that we have set labels
|
||||
sudo kpartx -d "${IMAGE_PATH}" || true
|
||||
# fix ownership
|
||||
sudo chown "${USER}:${USER}" "${IMAGE_PATH}"
|
||||
|
||||
echo "✅ Created ${IMAGE_PATH} with GPT partition names and filesystem labels."
|
||||
echo "You should now be able to write this image to your SD/NVMe and boot RK3588. "
|
||||
|
||||
|
||||
sudo sgdisk -p "${IMAGE_PATH}"
|
||||
exit 0
|
||||
|
|
|
|||
191
mkimg_gpt.sh
191
mkimg_gpt.sh
|
|
@ -1,191 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2025 Venkata Atchuta Bheemeswara Sarma Darbha
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Create an RK3588 GPT AOSP image (no changes to original sector/start/size values).
|
||||
# - Writes U-Boot at sector 64
|
||||
# - Creates GPT with named partitions so Android creates /dev/block/by-name/*
|
||||
# - Copies boot/system/vendor images (dd)
|
||||
# - Creates metadata/userdata ext4 and sets proper GPT & fs labels
|
||||
# - Uses kpartx to map partitions and cleans up reliably
|
||||
#
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
DEVICE_PATH=device/rockchip/tart
|
||||
KERNEL_PATH=device/rockchip/tart-kernel
|
||||
|
||||
# Helper: print error and cleanup
|
||||
exit_with_error() {
|
||||
echo "ERROR: $*" >&2
|
||||
cleanup || true
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
|
||||
if [ -n "${LOOPDEV:-}" ]; then
|
||||
if sudo kpartx -l "${IMAGE_PATH}" >/dev/null 2>&1; then
|
||||
sudo kpartx -d "${IMAGE_PATH}" || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
|
||||
: "${TARGET_PRODUCT:?TARGET_PRODUCT environment variable is not set. Run lunch first.}"
|
||||
: "${ANDROID_PRODUCT_OUT:?ANDROID_PRODUCT_OUT environment variable is not set. Run lunch first.}"
|
||||
|
||||
|
||||
for PART in boot system vendor; do
|
||||
if [ ! -f "${ANDROID_PRODUCT_OUT}/${PART}.img" ]; then
|
||||
exit_with_error "Missing partition image: ${ANDROID_PRODUCT_OUT}/${PART}.img — run 'make ${PART}image' first."
|
||||
fi
|
||||
done
|
||||
|
||||
UBOOT_BIN=${KERNEL_PATH}/u-boot-rockchip.bin
|
||||
if [ ! -f "${UBOOT_BIN}" ]; then
|
||||
exit_with_error "Missing U-Boot: ${UBOOT_BIN}"
|
||||
fi
|
||||
|
||||
LINEAGE_VERSION=$(build/soong/bin/get_build_var LINEAGE_VERSION)
|
||||
if [ -z "${LINEAGE_VERSION}" ]; then
|
||||
exit_with_error "LINEAGE_VERSION is empty. Run 'lunch' first and ensure the build environment is configured."
|
||||
fi
|
||||
IMGSIZE=19456MiB
|
||||
IMAGE_PATH="${ANDROID_PRODUCT_OUT}/lineage-${LINEAGE_VERSION}.img"
|
||||
|
||||
if [ -f "${IMAGE_PATH}" ]; then
|
||||
echo "Overwriting existing image: ${IMAGE_PATH}"
|
||||
sudo rm -f "${IMAGE_PATH}"
|
||||
fi
|
||||
|
||||
echo "Creating image file ${IMAGE_PATH} (${IMGSIZE})..."
|
||||
sudo fallocate -l "${IMGSIZE}" "${IMAGE_PATH}"
|
||||
sync
|
||||
|
||||
echo "Writing U-Boot to sector 64..."
|
||||
# write u-boot binary to offset 64*512 = sector 64
|
||||
sudo dd if="${UBOOT_BIN}" of="${IMAGE_PATH}" seek=64 bs=512 conv=notrunc status=progress
|
||||
sync
|
||||
|
||||
echo "Partitioning image using sfdisk (GPT) with explicit partition NAMES..."
|
||||
|
||||
|
||||
PART_TABLE=$(cat <<EOF
|
||||
label: gpt
|
||||
unit: sectors
|
||||
|
||||
# Partition 1: boot (FAT32)
|
||||
${IMAGE_PATH}1 : start=32768, size=262144, type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, name="boot"
|
||||
|
||||
# Partition 2: system (EXT4)
|
||||
${IMAGE_PATH}2 : start=303104, size=6291456, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="system"
|
||||
|
||||
# Partition 3: vendor (EXT4)
|
||||
${IMAGE_PATH}3 : start=6596608, size=786432, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="vendor"
|
||||
|
||||
# Partition 4: metadata (EXT4)
|
||||
${IMAGE_PATH}4 : start=7385088, size=32768, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="metadata"
|
||||
|
||||
# Partition 5: userdata (EXT4)
|
||||
${IMAGE_PATH}5 : start=7417856, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, name="userdata"
|
||||
EOF
|
||||
)
|
||||
|
||||
# Use a temporary file for sfdisk input so variable interpolation is safe
|
||||
echo "${PART_TABLE}" | sudo sfdisk "${IMAGE_PATH}"
|
||||
sync
|
||||
|
||||
echo "Mapping partitions using kpartx..."
|
||||
|
||||
KPARTX_OUT=$(sudo kpartx -av "${IMAGE_PATH}")
|
||||
echo "${KPARTX_OUT}"
|
||||
|
||||
LOOPDEV=$(echo "${KPARTX_OUT}" | awk '/add map/ {dev=$3} END { sub(/p[0-9]+$/, "", dev); print dev }')
|
||||
if [ -z "${LOOPDEV}" ]; then
|
||||
exit_with_error "kpartx failed to map partitions or to return a loop device name."
|
||||
fi
|
||||
echo "Mapped image as /dev/mapper/${LOOPDEV}p* (base loop: ${LOOPDEV})"
|
||||
|
||||
# Wait for device nodes to appear
|
||||
sleep 1
|
||||
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
||||
echo "Waiting a bit longer for /dev/mapper/${LOOPDEV}p1 to appear..."
|
||||
sleep 1
|
||||
fi
|
||||
if [ ! -b "/dev/mapper/${LOOPDEV}p1" ]; then
|
||||
exit_with_error "Device mapper nodes not found (e.g. /dev/mapper/${LOOPDEV}p1). Check kpartx output."
|
||||
fi
|
||||
|
||||
# --- Copy images into partitions ---
|
||||
echo "Creating FAT32 filesystem on p1 (boot partition)..."
|
||||
sudo mkfs.vfat -F 32 -n "boot" "/dev/mapper/${LOOPDEV}p1"
|
||||
|
||||
# Mount the boot partition and copy kernel/boot files
|
||||
BOOT_MOUNT=$(mktemp -d)
|
||||
sudo mount "/dev/mapper/${LOOPDEV}p1" "${BOOT_MOUNT}"
|
||||
sudo cp ${KERNEL_PATH}/Image "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/rk3588-orangepi-5-ultra.dtb "${BOOT_MOUNT}/"
|
||||
sudo mkdir -p "${BOOT_MOUNT}/extlinux"
|
||||
sudo tee "${BOOT_MOUNT}/extlinux/extlinux.conf" > /dev/null << 'EXTLINUX_EOF'
|
||||
label LineageOS Android TV
|
||||
kernel /Image
|
||||
fdt /rk3588-orangepi-5-ultra.dtb
|
||||
initrd /ramdisk.img
|
||||
append console=ttyS2,1500000 no_console_suspend root=/dev/ram0 rootwait androidboot.hardware=tart androidboot.selinux=permissive androidboot.boot_devices=fe2c0000.mmc
|
||||
EXTLINUX_EOF
|
||||
sudo cp ${KERNEL_PATH}/boot.scr "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/android-sdcard.dtbo "${BOOT_MOUNT}/"
|
||||
sudo cp "${ANDROID_PRODUCT_OUT}/ramdisk.img" "${BOOT_MOUNT}/"
|
||||
sudo cp ${KERNEL_PATH}/config.txt "${BOOT_MOUNT}/"
|
||||
sudo umount "${BOOT_MOUNT}"
|
||||
rmdir "${BOOT_MOUNT}"
|
||||
|
||||
echo "Writing system image to p2 (raw dd)."
|
||||
# Use conv=notrunc so we don't shrink partition image area; status=progress for visibility
|
||||
sudo dd if="${ANDROID_PRODUCT_OUT}/system.img" of="/dev/mapper/${LOOPDEV}p2" bs=1M conv=notrunc status=progress
|
||||
|
||||
echo "Writing vendor image to p3 (raw dd)."
|
||||
sudo dd if="${ANDROID_PRODUCT_OUT}/vendor.img" of="/dev/mapper/${LOOPDEV}p3" bs=1M conv=notrunc status=progress
|
||||
|
||||
sync
|
||||
|
||||
# --- Ensure filesystem labels and types are correct ---
|
||||
# Note: dd'ing system/vendor may already contain an internal FS label; we force the GPT
|
||||
# partition name above and set the filesystem label to match as a guard.
|
||||
echo "Setting filesystem labels on p2 (system) and p3 (vendor) and creating metadata/userdata..."
|
||||
|
||||
# Try to set ext4 label on system; if it isn't an ext4, warn but continue.
|
||||
set +e
|
||||
sudo e2label "/dev/mapper/${LOOPDEV}p2" system 2>/dev/null
|
||||
E2_RC=$?
|
||||
if [ "${E2_RC}" -ne 0 ]; then
|
||||
echo "Warning: /dev/mapper/${LOOPDEV}p2 does not appear to be ext4 or e2label failed. Continuing."
|
||||
fi
|
||||
sudo e2label "/dev/mapper/${LOOPDEV}p3" vendor 2>/dev/null || echo "Warning: e2label on vendor failed (maybe not ext4)."
|
||||
|
||||
set -e
|
||||
|
||||
# Create/format metadata and userdata partitions and set filesystem labels
|
||||
sudo mkfs.ext4 -F -L metadata "/dev/mapper/${LOOPDEV}p4"
|
||||
sudo mkfs.ext4 -F -L userdata "/dev/mapper/${LOOPDEV}p5"
|
||||
sync
|
||||
|
||||
# Final sanity: list by-name symlinks
|
||||
echo "Partition mapping summary (kpartx):"
|
||||
sudo ls -l /dev/mapper/"${LOOPDEV}"* || true
|
||||
|
||||
# Unmap now that we have set labels
|
||||
sudo kpartx -d "${IMAGE_PATH}" || true
|
||||
# fix ownership
|
||||
sudo chown "${USER}:${USER}" "${IMAGE_PATH}"
|
||||
|
||||
echo "✅ Created ${IMAGE_PATH} with GPT partition names and filesystem labels."
|
||||
echo "You should now be able to write this image to your SD/NVMe and boot RK3588. "
|
||||
|
||||
|
||||
sudo sgdisk -p "${IMAGE_PATH}"
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue