Files
Arch-R/build-kernel.sh
Douglas Teles 8650d940e2 Migrate to mainline kernel 6.12.61 + board/overlay architecture
Major architecture change: move from BSP kernel 6.6 with pre-merged panel
DTBs to mainline kernel 6.12.61 LTS with separated board DTBs + panel
overlays.

- Board DTB = hardware profile (GPIOs, PMIC, joypad, audio). 16 boards.
  Auto-selected by U-Boot via SARADC ADC reading (hwrev).
- Panel overlay = display init sequence. 20 panels. Applied at boot time
  via boot.ini fdt apply.
- Two image variants: original (a_boot.ini) and clone (b_boot.ini)
- Kernel cross-compiles from x86 host (no ARM chroot needed)
- Initramfs boot splash with SVG rendering at 0.7s
- Out-of-tree joypad driver (singleadc-joypad) for clone boards
- Panel generic-dsi driver with archr,generic-dsi compatible

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:20:09 -03:00

348 lines
12 KiB
Bash
Executable File

#!/bin/bash
#==============================================================================
# Arch R - Kernel Build Script
#==============================================================================
# Builds mainline Linux 6.12.x with Arch R patches for RK3326 R36S
# Applies: device patches, 6.12-LTS patches, mainline patches
# Builds: kernel Image + ALL DTBs + modules + out-of-tree joypad driver
#==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[$(date '+%H:%M:%S')]${NC} $1"; }
warn() { echo -e "${YELLOW}[$(date '+%H:%M:%S')] WARNING:${NC} $1"; }
error() { echo -e "${RED}[$(date '+%H:%M:%S')] ERROR:${NC} $1"; exit 1; }
#------------------------------------------------------------------------------
# Configuration
#------------------------------------------------------------------------------
KERNEL_VERSION="6.12.61"
KERNEL_URL="https://www.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz"
# Paths
KERNEL_SRC="$SCRIPT_DIR/kernel/src/linux-${KERNEL_VERSION}"
PATCHES_DIR="$SCRIPT_DIR/patches/linux"
DTS_DIR="$SCRIPT_DIR/kernel/dts/archr"
JOYPAD_DIR="$SCRIPT_DIR/kernel/drivers/archr-joypad"
CONFIG_BASE="$SCRIPT_DIR/config/linux-archr-base.config"
# Output
OUTPUT_DIR="$SCRIPT_DIR/output"
BOOT_DIR="$OUTPUT_DIR/boot"
MODULES_DIR="$OUTPUT_DIR/modules"
# Cross-compilation
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# Build parallelism
JOBS=$(nproc)
# DTS target directory inside kernel
KERNEL_DTS_DIR="$KERNEL_SRC/arch/arm64/boot/dts/rockchip"
log "================================================================"
log " Arch R - Kernel $KERNEL_VERSION (Mainline + Arch R patches)"
log "================================================================"
log ""
log "Source: $KERNEL_SRC"
log "Patches: $PATCHES_DIR"
log "DTS: $DTS_DIR"
log "Config: $CONFIG_BASE"
log "Jobs: $JOBS"
#------------------------------------------------------------------------------
# Step 1: Verify Kernel Source
#------------------------------------------------------------------------------
log ""
log "Step 1: Checking kernel source..."
if [ ! -d "$KERNEL_SRC" ]; then
TARBALL="$SCRIPT_DIR/kernel/src/linux-${KERNEL_VERSION}.tar.xz"
if [ ! -f "$TARBALL" ]; then
log " Downloading kernel $KERNEL_VERSION..."
wget -c "$KERNEL_URL" -O "$TARBALL"
fi
log " Extracting..."
tar -xf "$TARBALL" -C "$SCRIPT_DIR/kernel/src/"
fi
if [ ! -f "$KERNEL_SRC/Makefile" ]; then
error "Kernel source not found at: $KERNEL_SRC"
fi
ACTUAL_VERSION=$(make -C "$KERNEL_SRC" -s kernelversion 2>/dev/null)
log " Kernel: $ACTUAL_VERSION"
#------------------------------------------------------------------------------
# Step 2: Apply Patches (idempotent — skip already applied)
#------------------------------------------------------------------------------
log ""
log "Step 2: Applying patches..."
PATCH_MARKER="$KERNEL_SRC/.archr-patches-applied"
if [ -f "$PATCH_MARKER" ]; then
log " Patches already applied (marker exists). Skipping."
else
PATCH_COUNT=0
# Order: mainline first (GPIO API, input-polldev), then 6.12-LTS, then device-specific
for PATCH_SUBDIR in mainline 6.12-lts device; do
PDIR="$PATCHES_DIR/$PATCH_SUBDIR"
if [ ! -d "$PDIR" ]; then
warn " Patch dir not found: $PDIR"
continue
fi
for PATCH in $(ls "$PDIR"/*.patch 2>/dev/null | sort); do
PNAME=$(basename "$PATCH")
log " Applying [$PATCH_SUBDIR] $PNAME..."
if ! patch -d "$KERNEL_SRC" -p1 --forward --batch < "$PATCH" 2>&1 | tail -3; then
warn " Patch may have failed or already applied: $PNAME"
fi
PATCH_COUNT=$((PATCH_COUNT + 1))
done
done
touch "$PATCH_MARKER"
log " Applied $PATCH_COUNT patches"
fi
#------------------------------------------------------------------------------
# Step 3: Copy DTS files
#------------------------------------------------------------------------------
log ""
log "Step 3: Copying DTS files..."
if [ ! -d "$DTS_DIR" ]; then
error "DTS directory not found: $DTS_DIR"
fi
DTS_COUNT=0
for DTS_FILE in "$DTS_DIR"/*.dts "$DTS_DIR"/*.dtsi; do
[ -f "$DTS_FILE" ] || continue
DEST="$KERNEL_DTS_DIR/$(basename "$DTS_FILE")"
cp "$DTS_FILE" "$DEST"
DTS_COUNT=$((DTS_COUNT + 1))
done
# Add DTS entries to Makefile (for each .dts, ensure dtb- line exists)
ROCKCHIP_MAKEFILE="$KERNEL_DTS_DIR/Makefile"
for DTS_FILE in "$DTS_DIR"/*.dts; do
[ -f "$DTS_FILE" ] || continue
DTB_NAME=$(basename "$DTS_FILE" .dts)
if ! grep -q "${DTB_NAME}.dtb" "$ROCKCHIP_MAKEFILE"; then
# Add before the first empty line or at the end of the dtb list
echo "dtb-\$(CONFIG_ARCH_ROCKCHIP) += ${DTB_NAME}.dtb" >> "$ROCKCHIP_MAKEFILE"
log " Added to Makefile: ${DTB_NAME}.dtb"
fi
done
log " Copied $DTS_COUNT DTS files"
#------------------------------------------------------------------------------
# Step 4: Configure Kernel
#------------------------------------------------------------------------------
log ""
log "Step 4: Configuring kernel..."
if [ ! -f "$CONFIG_BASE" ]; then
error "Config base not found: $CONFIG_BASE"
fi
# Copy Arch R base config
cp "$CONFIG_BASE" "$KERNEL_SRC/.config"
# Replace placeholder for initramfs
INITRAMFS_DIR="$OUTPUT_DIR/initramfs"
if [ -d "$INITRAMFS_DIR" ] && [ -x "$INITRAMFS_DIR/init" ]; then
log " Embedding initramfs from: $INITRAMFS_DIR"
sed -i "s|@INITRAMFS_SOURCE@|${INITRAMFS_DIR}|" "$KERNEL_SRC/.config"
else
warn " Initramfs not found at $INITRAMFS_DIR"
warn " Run build-initramfs.sh first! Disabling embedded initramfs."
sed -i 's|CONFIG_INITRAMFS_SOURCE=.*|CONFIG_INITRAMFS_SOURCE=""|' "$KERNEL_SRC/.config"
fi
# Finalize config
make -C "$KERNEL_SRC" ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE olddefconfig
# Verify critical settings
log " Verifying config..."
check_config() {
local key="$1" expected="$2" desc="$3"
local val=$(grep "^${key}=" "$KERNEL_SRC/.config" 2>/dev/null | head -1)
if [ -z "$val" ]; then
val=$(grep "^# ${key} is not set" "$KERNEL_SRC/.config" 2>/dev/null | head -1)
fi
if echo "$val" | grep -q "$expected"; then
log " $desc: OK"
else
warn " $desc: UNEXPECTED ($val)"
fi
}
check_config "CONFIG_DRM_PANFROST" "=m" "Panfrost GPU"
check_config "CONFIG_DRM_PANEL_SITRONIX_ST7703" "=y" "ST7703 panel"
check_config "CONFIG_FRAMEBUFFER_CONSOLE" "=y" "fbcon"
check_config "CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER" "is not set" "No deferred takeover"
check_config "CONFIG_EXT4_FS" "=y" "ext4"
check_config "CONFIG_DEVTMPFS" "=y" "devtmpfs"
log " Kernel configured"
#------------------------------------------------------------------------------
# Step 5: Build Kernel Image
#------------------------------------------------------------------------------
log ""
log "Step 5: Building kernel Image..."
make -C "$KERNEL_SRC" -j$JOBS ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE Image 2>&1 | tail -5
if [ ! -f "$KERNEL_SRC/arch/arm64/boot/Image" ]; then
error "Kernel Image build failed!"
fi
IMAGE_SIZE=$(du -h "$KERNEL_SRC/arch/arm64/boot/Image" | cut -f1)
log " Kernel Image built ($IMAGE_SIZE)"
#------------------------------------------------------------------------------
# Step 6: Build ALL Device Trees
#------------------------------------------------------------------------------
log ""
log "Step 6: Building Device Trees..."
# Build dtbs target (compiles all DTBs referenced in Makefile)
make -C "$KERNEL_SRC" -j$JOBS ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE DTC_FLAGS=-@ dtbs 2>&1 | tail -10
# Verify R36S DTB was built
if [ ! -f "$KERNEL_DTS_DIR/rk3326-gameconsole-r36s.dtb" ]; then
error "R36S DTB not built!"
fi
DTB_COUNT=$(find "$KERNEL_DTS_DIR" -name "rk3326-*.dtb" | wc -l)
log " Built $DTB_COUNT RK3326 DTBs"
#------------------------------------------------------------------------------
# Step 7: Build Kernel Modules
#------------------------------------------------------------------------------
log ""
log "Step 7: Building kernel modules..."
make -C "$KERNEL_SRC" -j$JOBS ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE modules 2>&1 | tail -5
log " Kernel modules built"
#------------------------------------------------------------------------------
# Step 8: Build Out-of-Tree Drivers
#------------------------------------------------------------------------------
log ""
log "Step 8: Building out-of-tree drivers..."
if [ -d "$JOYPAD_DIR" ] && [ -f "$JOYPAD_DIR/Makefile" ]; then
log " Building archr-joypad..."
make -C "$KERNEL_SRC" ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE \
M="$JOYPAD_DIR" modules 2>&1 | tail -5
if find "$JOYPAD_DIR" -name "*.ko" | grep -q .; then
log " archr-joypad: OK"
else
warn " archr-joypad: no .ko files produced"
fi
else
warn " Joypad driver not found at: $JOYPAD_DIR"
fi
#------------------------------------------------------------------------------
# Step 9: Install to Output Directory
#------------------------------------------------------------------------------
log ""
log "Step 9: Installing artifacts..."
mkdir -p "$BOOT_DIR"
mkdir -p "$MODULES_DIR"
# Copy kernel image as KERNEL (Arch R naming convention)
cp "$KERNEL_SRC/arch/arm64/boot/Image" "$BOOT_DIR/KERNEL"
log " Copied: KERNEL"
# Copy ALL RK3326 DTBs to dtbs/ subdirectory
mkdir -p "$BOOT_DIR/dtbs"
for DTB in "$KERNEL_DTS_DIR"/rk3326-*.dtb; do
[ -f "$DTB" ] || continue
cp "$DTB" "$BOOT_DIR/dtbs/"
done
log " Copied: $(ls "$BOOT_DIR/dtbs"/rk3326-*.dtb 2>/dev/null | wc -l) DTBs to dtbs/"
# Install kernel modules
set -o pipefail
make -C "$KERNEL_SRC" ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE \
INSTALL_MOD_PATH="$MODULES_DIR" \
modules_install 2>&1 | tail -5
set +o pipefail
# Install joypad driver module
if find "$JOYPAD_DIR" -name "*.ko" | grep -q .; then
KREL=$(cat "$KERNEL_SRC/include/config/kernel.release" 2>/dev/null)
JOYPAD_DEST="$MODULES_DIR/lib/modules/$KREL/extra/archr-joypad"
mkdir -p "$JOYPAD_DEST"
cp "$JOYPAD_DIR"/*.ko "$JOYPAD_DEST/"
log " Installed joypad modules to: extra/archr-joypad/"
# Regenerate modules.dep
depmod -b "$MODULES_DIR" "$KREL"
fi
# Remove build/source symlinks (save space on target)
rm -f "$MODULES_DIR/lib/modules/"*/source 2>/dev/null || true
rm -f "$MODULES_DIR/lib/modules/"*/build 2>/dev/null || true
# Verify critical modules
KREL=$(cat "$KERNEL_SRC/include/config/kernel.release" 2>/dev/null)
for MOD in panfrost; do
if find "$MODULES_DIR/lib/modules/$KREL" -name "${MOD}.ko*" 2>/dev/null | grep -q .; then
log " Module OK: $MOD"
else
warn " Module MISSING: $MOD"
fi
done
# Note: rockchipdrm is CONFIG_DRM_ROCKCHIP=y (built-in, not a module) — no .ko to check
log " Modules installed"
#------------------------------------------------------------------------------
# Summary
#------------------------------------------------------------------------------
log ""
log "================================================================"
log " BUILD COMPLETE"
log "================================================================"
log ""
KERNEL_FULL=$(make -C "$KERNEL_SRC" -s kernelversion 2>/dev/null)
KERNEL_SIZE=$(du -h "$BOOT_DIR/KERNEL" | cut -f1)
MODULES_SIZE=$(du -sh "$MODULES_DIR" 2>/dev/null | cut -f1)
DTB_COUNT=$(ls "$BOOT_DIR/dtbs"/rk3326-*.dtb 2>/dev/null | wc -l)
log "Kernel: $KERNEL_FULL (mainline + Arch R patches)"
log "KERNEL: $BOOT_DIR/KERNEL ($KERNEL_SIZE)"
log "DTBs: $DTB_COUNT files in $BOOT_DIR/dtbs/"
log "Modules: $MODULES_DIR/ ($MODULES_SIZE)"
log ""
log "Key DTBs:"
for DTB in rk3326-gameconsole-r36s rk3326-odroid-go2 rk3326-gameconsole-r33s; do
if [ -f "$BOOT_DIR/dtbs/${DTB}.dtb" ]; then
log " ${DTB}.dtb ($(du -h "$BOOT_DIR/dtbs/${DTB}.dtb" | cut -f1))"
fi
done
log ""
log "Ready for deployment to SD card!"