12 Commits

Author SHA1 Message Date
Douglas Teles 70342ca457 ROADMAP: detail beta1.2 system changes and update last-updated
Input merger, RetroArch tuning, panel ordering, no-panel variant,
mirror list, boot.ini autodetect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:24:00 -03:00
Douglas Teles b6eff2e748 ROADMAP: beta1.1 pre-merged DTBs + beta1.2 Flasher diary entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:20:21 -03:00
Douglas Teles 9c30a92cab Add variant-sync service, update mirrors, native DTB names
- build-rootfs.sh: archr-variant-sync.service copies /boot/variant
  to /etc/archr/variant on first boot (for Flasher no-panel images).
  Runs once via ConditionPathExists, Before=panel-detect.service
- build-rootfs.sh: update ALARM mirror list (remove eu.mirror/403,
  add de4/gr/tw/tw2/ca.us, reorder Americas first for Brazil)
- build-image.sh: no-panel variant uses native DTB names
  (kernel-panel4.dtb, kernel-clone8.dtb) instead of inherited
  kernel-original.dtb / kernel-clone.dtb

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 00:11:28 -03:00
Douglas Teles cbc39b8802 Add no-panel universal image variant for Flasher app
Third build variant (--variant no-panel) that includes all 18 panel
DTBs for both original and clone hardware. Designed for the future
Arch R Flasher app to inject the correct kernel.dtb at flash time.

- boot.ini: auto-detect root device from mmcdev (no more __ROOTDEV__)
- build-image.sh: no-panel uses mainline U-Boot, copies all DTBs
- panel-detect.py: wizard disabled for no-panel variant
- build-all.sh: generates third image (ArchR-R36S-no-panel)
2026-03-01 22:11:37 -03:00
Douglas Teles 87719600d2 Update README: split panel list by variant, fix panel.txt format
Separate panel tables into Original (6 panels) and Clone (12 panels)
with numerical ordering and beep counts. Update manual selection to
use PanelDTB= format (pre-merged DTBs). Note: ordering available
from beta1.2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:54:37 -03:00
Douglas Teles baaeb69a19 Input merger, RetroArch tuning, panel ordering fix
- input-merge daemon: combines gpio-keys + adc-joystick into single
  virtual "Arch R Gamepad" via uinput so RetroArch sees one device
  (fixes analog sticks ignored due to max_users=1)
- retroarch-launch.sh: start/stop input-merge, VT blank on launch
- retroarch.cfg: ROCKNIX-based tuning (48kHz audio, triple buffer,
  late input polling, autosave, core options path)
- retroarch-core-options.cfg: per-core tuning from ROCKNIX RK3326
  (mupen64plus, pcsx_rearmed, flycast, mame2003-plus, melonds, etc.)
- archr-gamepad.cfg: autoconfig for merged virtual device
- panel-detect.py: panels in numerical order (beep count = position),
  default_panel searches by empty dtb_name instead of panels[0]
- build-rootfs.sh: compile input-merge, install core options and
  autoconfig, add input-merge and kill to sudoers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:48:49 -03:00
Douglas Teles a1efd4fc01 Pre-merged panel DTBs: eliminate U-Boot fdt apply bugs
Users reported that non-default panel overlays caused broken display,
audio, and controls. Root cause: BSP U-Boot's fdt apply has bugs with
property replacement of different-sized data, corrupting the DTB.

Fix: apply overlays at build-time using fdtoverlay (verified working)
instead of at boot-time. Each panel now gets a pre-merged kernel-*.dtb.
U-Boot simply loads the right DTB by name — no fdt apply needed.

- generate-panel-dtbos.sh: add fdtoverlay pre-merge step
- build-image.sh: copy pre-merged DTBs instead of ScreenFiles
- boot.ini: load PanelDTB by name, remove fdt addr/resize/apply
- panel-detect.py: write DTB filename instead of DTBO overlay path
2026-02-28 00:14:54 -03:00
Douglas Teles e4294ab47b Two-image build pipeline, clone support, initramfs splash
- Clone variant: mainline U-Boot v2025.10, boot.scr, clone DTS (type5)
- Initramfs splash: archr-init.c with embedded BMP, sub-second display
- Panel wizard: auto-detect with fsync persistence, evdev X-button reset
- Hotkeys: adc-keys volume for clone, HP jack detection, brightness persist
- Boot.ini: ASCII-only (no Unicode), GPIO check removed
- ES wrapper: removed framebuffer blanking (preserves splash)
- Build pipeline: both variants, splash generation, panel DTBOs
- .gitignore: exclude large bootloader trees and build artifacts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 22:38:47 -03:00
Douglas Teles 70765e96bd update 26.02.25 2026-02-25 17:22:34 -03:00
Douglas Teles 2ccf5383ac update 26.02.23 2026-02-23 03:03:09 -03:00
Douglas Teles 476b05cd9a fix roadmap 2026-02-22 14:46:19 -03:00
Douglas Teles a9029b419f Fix ROADMAP.md diary timeline ordering
Move Day 17-18 entry to correct chronological position
(before "What's Left for v1.0 Stable", not after it).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:43:37 -03:00
25 changed files with 4199 additions and 451 deletions
+20
View File
@@ -71,3 +71,23 @@ restore-mesa26-gbm.sh
# Website (separate project)
website/
# Environment secrets
.env
# Bootloader source trees (cloned/downloaded during build)
bootloader/rkbin/
bootloader/u-boot-mainline/
bootloader/u-boot-rk3326-clone/
# Pre-built U-Boot backups (working binaries, not part of build pipeline)
bootloader/u-boot-clone-working/
# Extracted DTBs (debugging artifacts)
bootloader/u-boot-r36s-working/extracted_dtb_*.dtb
# Clone U-Boot build output
bootloader/u-boot-clone-build/
# Others
feedback/
+97 -7
View File
@@ -153,11 +153,100 @@ Arch-R/
## Supported Panels
Arch R supports 18 display panels via DTBO overlays:
Arch R supports 18 display panels via pre-merged DTBs. Each panel variant has its own DTB file with the correct init sequence and timings applied at build-time.
**Original R36S:** Panel 0, Panel 1 (V10), Panel 2 (V12), Panel 3 (V20), Panel 4 (V22, default), Panel 5 (V22 Q8)
There are two separate images: **Original** (for genuine R36S) and **Clone** (for R36S clones like G80CA, K36, etc.). Each image has its own panel list.
**Clones:** Clone Panel 1-10 (ST7703, NV3051D variants), R36 Max, RX6S
> **Note:** The numerical panel ordering below is available starting from **beta1.2**. Earlier versions may have a different order.
### Panel Auto-Detection
On first boot, Arch R runs a **panel detection wizard** that guides you through selecting your display panel:
1. **If your screen works** (you see text on screen): press **A** to confirm the current panel
2. **If your screen is black** (wrong panel): listen for audio beeps and use buttons to navigate:
- Each panel plays a different number of beeps (Panel 0 = 1 beep, Panel 1 = 2 beeps, etc.)
- Press **B** to skip to the next panel
- Press **A** to confirm (you'll hear 3 rapid beeps)
- The system reboots with the correct panel applied
Your selection is saved permanently. To reset it later, **hold X during boot**.
### R36S Original (6 panels)
Default: **Panel 4-V22** (~60% of units)
| Beeps | Panel | DTB | Notes |
|-------|-------|-----|-------|
| 1 | Panel 0 | kernel-panel0.dtb | Early R36S units |
| 2 | Panel 1-V10 | kernel-panel1.dtb | V10 board marking |
| 3 | Panel 2-V12 | kernel-panel2.dtb | V12 board marking |
| 4 | Panel 3-V20 | kernel-panel3.dtb | V20 board marking |
| 5 | **Panel 4-V22** *(default)* | kernel.dtb | Most common |
| 6 | Panel 5-V22 Q8 | kernel-panel5.dtb | V22 Q8 variant |
### R36S Clone (12 panels)
Default: **Clone 8 ST7703 G80CA**
| Beeps | Panel | DTB | Notes |
|-------|-------|-----|-------|
| 1 | Clone 1 | kernel-clone1.dtb | ST7703 |
| 2 | Clone 2 | kernel-clone2.dtb | ST7703 |
| 3 | Clone 3 | kernel-clone3.dtb | NV3051D |
| 4 | Clone 4 | kernel-clone4.dtb | NV3051D |
| 5 | Clone 5 | kernel-clone5.dtb | ST7703 |
| 6 | Clone 6 | kernel-clone6.dtb | NV3051D |
| 7 | Clone 7 | kernel-clone7.dtb | JD9365DA |
| 8 | **Clone 8** *(default)* | kernel.dtb | ST7703 (G80CA-MB) |
| 9 | Clone 9 | kernel-clone9.dtb | NV3051D |
| 10 | Clone 10 | kernel-clone10.dtb | ST7703 variant |
| 11 | R36 Max | kernel-r36max.dtb | 720x720 ST7703 |
| 12 | RX6S | kernel-rx6s.dtb | NV3051D variant |
### Manual Panel Selection
If you prefer to set the panel manually (e.g., you know which panel you have from ArkOS/dArkOS):
**Step 1 -- Mount the BOOT partition on your PC**
```bash
lsblk
sudo mount /dev/sdX1 /mnt
```
**Step 2 -- Create panel.txt**
```bash
# Example: Panel 3-V20 (original R36S)
echo 'PanelNum=3
PanelDTB=kernel-panel3.dtb' | sudo tee /mnt/panel.txt
# Mark as confirmed (skip wizard on next boot)
echo 'confirmed' | sudo tee /mnt/panel-confirmed
```
For default panels (no custom DTB needed):
```bash
# Original R36S: Panel 4-V22 (default)
echo 'PanelNum=4
PanelDTB=' | sudo tee /mnt/panel.txt
# Clone R36S: Clone 8 G80CA (default)
echo 'PanelNum=C8
PanelDTB=' | sudo tee /mnt/panel.txt
echo 'confirmed' | sudo tee /mnt/panel-confirmed
```
**Step 3 -- Unmount and boot**
```bash
sudo umount /mnt
sync
```
**To reset panel selection:** hold **X** during boot, or delete `panel-confirmed` from the BOOT partition.
## Boot Flow
@@ -165,11 +254,12 @@ Arch R supports 18 display panels via DTBO overlays:
Power On
→ U-Boot (idbloader → trust → uboot.img)
→ logo.bmp displayed on screen
extlinux/extlinux.conf loaded (primary)
→ Kernel 6.6.89 + rk3326-gameconsole-r36s.dtb
→ systemd → archr-boot-setup (GPU + governors)
boot.ini: load panel.txt → load pre-merged DTB (kernel-panelN.dtb)
→ Kernel 6.6.89 + initramfs splash (0.7s)
→ systemd → panel-detect.service (first boot only)
→ archr-boot-setup (GPU + governors)
→ emulationstation.service → EmulationStation UI
≈ 19 seconds total
≈ 19 seconds total (+ wizard on first boot)
```
## Contributing
+824 -153
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+36 -4
View File
@@ -44,6 +44,7 @@ usage() {
echo "Options:"
echo " --kernel Build kernel only"
echo " --rootfs Build rootfs only"
echo " --uboot Build U-Boot only"
echo " --image Build image only"
echo " --all Build everything (default)"
echo " --clean Clean all build artifacts"
@@ -53,6 +54,7 @@ usage() {
BUILD_KERNEL=false
BUILD_ROOTFS=false
BUILD_UBOOT=false
BUILD_IMAGE=false
CLEAN=false
@@ -60,14 +62,16 @@ CLEAN=false
if [ $# -eq 0 ]; then
BUILD_KERNEL=true
BUILD_ROOTFS=true
BUILD_UBOOT=true
BUILD_IMAGE=true
else
while [[ $# -gt 0 ]]; do
case $1 in
--kernel) BUILD_KERNEL=true; shift ;;
--rootfs) BUILD_ROOTFS=true; shift ;;
--uboot) BUILD_UBOOT=true; shift ;;
--image) BUILD_IMAGE=true; shift ;;
--all) BUILD_KERNEL=true; BUILD_ROOTFS=true; BUILD_IMAGE=true; shift ;;
--all) BUILD_KERNEL=true; BUILD_ROOTFS=true; BUILD_UBOOT=true; BUILD_IMAGE=true; shift ;;
--clean) CLEAN=true; shift ;;
--help) usage; exit 0 ;;
*) error "Unknown option: $1" ;;
@@ -180,13 +184,41 @@ log "═════════════════════════
chmod +x "$SCRIPT_DIR/scripts/generate-panel-dtbos.sh"
"$SCRIPT_DIR/scripts/generate-panel-dtbos.sh"
# Build custom U-Boot (optional — requires arm-linux-gnueabihf toolchain)
if [ "$BUILD_UBOOT" = true ] && [ -f "$SCRIPT_DIR/build-uboot.sh" ]; then
if command -v aarch64-linux-gnu-gcc &>/dev/null; then
log ""
log "═══════════════════════════════════════════════════════════════"
log " BUILDING U-BOOT"
log "═══════════════════════════════════════════════════════════════"
chmod +x "$SCRIPT_DIR/build-uboot.sh"
"$SCRIPT_DIR/build-uboot.sh"
else
warn "Skipping U-Boot build: aarch64-linux-gnu-gcc not found"
warn "Install: sudo apt install gcc-aarch64-linux-gnu"
fi
fi
if [ "$BUILD_IMAGE" = true ]; then
chmod +x "$SCRIPT_DIR/build-image.sh"
log ""
log "═══════════════════════════════════════════════════════════════"
log " BUILDING IMAGE"
log " BUILDING IMAGE (original)"
log "═══════════════════════════════════════════════════════════════"
chmod +x "$SCRIPT_DIR/build-image.sh"
"$SCRIPT_DIR/build-image.sh"
"$SCRIPT_DIR/build-image.sh" --variant original
log ""
log "═══════════════════════════════════════════════════════════════"
log " BUILDING IMAGE (clone)"
log "═══════════════════════════════════════════════════════════════"
"$SCRIPT_DIR/build-image.sh" --variant clone
log ""
log "═══════════════════════════════════════════════════════════════"
log " BUILDING IMAGE (no-panel)"
log "═══════════════════════════════════════════════════════════════"
"$SCRIPT_DIR/build-image.sh" --variant no-panel
fi
#------------------------------------------------------------------------------
+293 -105
View File
File diff suppressed because it is too large Load Diff
+35 -5
View File
@@ -31,8 +31,9 @@ KERNEL_REPO="https://github.com/rockchip-linux/kernel.git"
DEFCONFIG="rockchip_linux_defconfig"
CONFIG_FRAGMENT="$SCRIPT_DIR/config/archr-6.6-r36s.config"
# DTS target
# DTS targets
R36S_DTB="rk3326-gameconsole-r36s"
CLONE_DTB="rk3326-gameconsole-r36s-clone-type5"
# Paths
KERNEL_SRC="${KERNEL_SRC:-/home/dgateles/Documentos/Projetos/kernel}"
@@ -93,6 +94,14 @@ else
fi
fi
# Copy clone DTS (if available)
CLONE_DTS_SRC="$SCRIPT_DIR/kernel/dts/${CLONE_DTB}.dts"
CLONE_DTS_DEST="$KERNEL_SRC/arch/arm64/boot/dts/rockchip/${CLONE_DTB}.dts"
if [ -f "$CLONE_DTS_SRC" ]; then
cp "$CLONE_DTS_SRC" "$CLONE_DTS_DEST"
log " DTS (clone): copied from repo"
fi
#------------------------------------------------------------------------------
# Step 2: Configure Kernel
#------------------------------------------------------------------------------
@@ -164,6 +173,17 @@ fi
log " DTB built: ${R36S_DTB}.dtb"
# Build clone DTB (if DTS was copied)
if [ -f "$CLONE_DTS_DEST" ]; then
make -C "$KERNEL_SRC" -j$JOBS ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE \
"rockchip/${CLONE_DTB}.dtb" 2>&1 | tail -5
if [ -f "$KERNEL_SRC/arch/arm64/boot/dts/rockchip/${CLONE_DTB}.dtb" ]; then
log " DTB built (clone): ${CLONE_DTB}.dtb"
else
warn "Clone DTB build failed: ${CLONE_DTB}.dtb"
fi
fi
#------------------------------------------------------------------------------
# Step 5: Build Kernel Modules
#------------------------------------------------------------------------------
@@ -192,6 +212,12 @@ log " Copied: Image"
cp "$KERNEL_SRC/arch/arm64/boot/dts/rockchip/${R36S_DTB}.dtb" "$BOOT_DIR/"
log " Copied: ${R36S_DTB}.dtb"
# Copy clone DTB (if built)
if [ -f "$KERNEL_SRC/arch/arm64/boot/dts/rockchip/${CLONE_DTB}.dtb" ]; then
cp "$KERNEL_SRC/arch/arm64/boot/dts/rockchip/${CLONE_DTB}.dtb" "$BOOT_DIR/"
log " Copied: ${CLONE_DTB}.dtb"
fi
# Install modules (use pipefail to catch errors masked by tail)
set -o pipefail
make -C "$KERNEL_SRC" ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE \
@@ -231,9 +257,13 @@ MODULES_SIZE=$(du -sh "$MODULES_DIR" 2>/dev/null | cut -f1 || echo "N/A")
log "Kernel: $KERNEL_FULL"
log ""
CLONE_DTB_SIZE="N/A"
[ -f "$BOOT_DIR/${CLONE_DTB}.dtb" ] && CLONE_DTB_SIZE=$(du -h "$BOOT_DIR/${CLONE_DTB}.dtb" | cut -f1)
log "Artifacts:"
log " Image: $BOOT_DIR/Image ($IMAGE_SIZE)"
log " DTB: $BOOT_DIR/${R36S_DTB}.dtb ($DTB_SIZE)"
log " Modules: $MODULES_DIR/ ($MODULES_SIZE)"
log " Image: $BOOT_DIR/Image ($IMAGE_SIZE)"
log " DTB: $BOOT_DIR/${R36S_DTB}.dtb ($DTB_SIZE)"
log " DTB clone: $BOOT_DIR/${CLONE_DTB}.dtb ($CLONE_DTB_SIZE)"
log " Modules: $MODULES_DIR/ ($MODULES_SIZE)"
log ""
log "Kernel 6.6 ready for R36S!"
log "Kernel 6.6 ready for R36S (original + clone)!"
+82 -12
View File
@@ -123,15 +123,19 @@ log " ✓ Pacman CheckSpace disabled (QEMU chroot compatibility)"
# Add multiple fallback mirrors (default mirror often has stale/404 packages)
cat > "$ROOTFS_DIR/etc/pacman.d/mirrorlist" << 'MIRRORS_EOF'
# Arch Linux ARM mirrors - multiple fallbacks for reliability
Server = http://de.mirror.archlinuxarm.org/$arch/$repo
Server = http://eu.mirror.archlinuxarm.org/$arch/$repo
Server = http://dk.mirror.archlinuxarm.org/$arch/$repo
Server = http://de3.mirror.archlinuxarm.org/$arch/$repo
Server = http://hu.mirror.archlinuxarm.org/$arch/$repo
Server = http://mirror.archlinuxarm.org/$arch/$repo
# Arch Linux ARM mirrors - all official mirrors, Americas first
Server = http://fl.us.mirror.archlinuxarm.org/$arch/$repo
Server = http://nj.us.mirror.archlinuxarm.org/$arch/$repo
Server = http://ca.us.mirror.archlinuxarm.org/$arch/$repo
Server = http://de.mirror.archlinuxarm.org/$arch/$repo
Server = http://de4.mirror.archlinuxarm.org/$arch/$repo
Server = http://dk.mirror.archlinuxarm.org/$arch/$repo
Server = http://hu.mirror.archlinuxarm.org/$arch/$repo
Server = http://gr.mirror.archlinuxarm.org/$arch/$repo
Server = http://de3.mirror.archlinuxarm.org/$arch/$repo
Server = http://tw.mirror.archlinuxarm.org/$arch/$repo
Server = http://tw2.mirror.archlinuxarm.org/$arch/$repo
Server = http://mirror.archlinuxarm.org/$arch/$repo
MIRRORS_EOF
log " ✓ Multiple ALARM mirrors configured (fallback for 404s)"
@@ -353,6 +357,7 @@ fi
cat > /etc/systemd/system/firstboot.service << 'FB_EOF'
[Unit]
Description=Arch R First Boot Setup
After=local-fs.target
Before=emulationstation.service
ConditionPathExists=!/var/lib/archr/.first-boot-done
@@ -367,6 +372,46 @@ FB_EOF
systemctl enable firstboot
# Variant sync: copies variant marker from BOOT → /etc/archr/variant
# Only runs if /etc/archr/variant doesn't exist yet (no-panel images flashed by Flasher)
cat > /etc/systemd/system/archr-variant-sync.service << 'VARSYNC_EOF'
[Unit]
Description=Sync variant from BOOT partition
After=local-fs.target
Before=panel-detect.service
RequiresMountsFor=/boot
ConditionPathExists=!/etc/archr/variant
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'test -f /boot/variant && mkdir -p /etc/archr && cp /boot/variant /etc/archr/variant'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
VARSYNC_EOF
systemctl enable archr-variant-sync
# Panel auto-detect wizard (first boot / X-button reset)
cat > /etc/systemd/system/panel-detect.service << 'PANELDET_EOF'
[Unit]
Description=Arch R Panel Detection Wizard
After=local-fs.target
Before=emulationstation.service
RequiresMountsFor=/boot
[Service]
Type=oneshot
ExecStart=/usr/local/bin/panel-detect.py
TimeoutStartSec=600
[Install]
WantedBy=multi-user.target
PANELDET_EOF
systemctl enable panel-detect
# EmulationStation launch — PRIMARY: systemd service (created by build-emulationstation.sh)
# FALLBACK: autologin + .bash_profile (if ES service not installed)
# The emulationstation.service Conflicts with getty@tty1, so only one runs.
@@ -403,9 +448,12 @@ fi
PROFILE_EOF
chown archr:archr /home/archr/.bash_profile
# Disable old custom splash if it exists
# Boot splash: handled by initramfs (archr-init with embedded BMP).
# Initramfs displays splash at ~0.7s after kernel start, before systemd.
# No systemd service needed — splash persists until ES takes DRM master.
systemctl disable splash 2>/dev/null || true
rm -f /etc/systemd/system/splash.service
systemctl disable archr-splash 2>/dev/null || true
rm -f /etc/systemd/system/splash.service /etc/systemd/system/archr-splash.service
# Battery LED warning service
cat > /etc/systemd/system/battery-led.service << 'BATT_EOF'
@@ -483,7 +531,8 @@ TIMING_EOF
systemctl enable boot-timing
# Delete initramfs (not used — extlinux.conf has no INITRD line)
# Delete stock ALARM initramfs and kernel (we use our own kernel + initramfs)
# Our initramfs.img is built by build-image.sh and placed on BOOT partition
rm -f /boot/initramfs-linux.img /boot/Image /boot/Image.gz 2>/dev/null
# Clean kernel modules: remove media tuners (154 modules, 13MB — useless for gaming)
@@ -497,7 +546,7 @@ dd if=/dev/urandom of=/var/lib/systemd/random-seed bs=512 count=1 2>/dev/null
chmod 600 /var/lib/systemd/random-seed
# Sudoers for perfmax/perfnorm/pmic-poweroff (allow archr to run without password)
echo "archr ALL=(ALL) NOPASSWD: /usr/local/bin/perfmax, /usr/local/bin/perfnorm, /usr/local/bin/pmic-poweroff, /usr/bin/ln, /usr/bin/dmesg, /usr/bin/chvt, /usr/bin/cp, /usr/bin/chmod, /bin/bash" > /etc/sudoers.d/archr-perf
echo "archr ALL=(ALL) NOPASSWD: /usr/local/bin/perfmax, /usr/local/bin/perfnorm, /usr/local/bin/pmic-poweroff, /usr/local/bin/input-merge, /usr/bin/kill, /usr/bin/ln, /usr/bin/dmesg, /usr/bin/chvt, /usr/bin/cp, /usr/bin/chmod, /bin/bash" > /etc/sudoers.d/archr-perf
chmod 440 /etc/sudoers.d/archr-perf
# Allow archr to use negative nice values (needed for nice -n -19 in ES launch commands)
@@ -928,8 +977,22 @@ install -m 755 "$SCRIPT_DIR/scripts/perfmax" "$ROOTFS_DIR/usr/local/bin/perfmax"
install -m 755 "$SCRIPT_DIR/scripts/perfnorm" "$ROOTFS_DIR/usr/local/bin/perfnorm"
install -m 755 "$SCRIPT_DIR/scripts/pmic-poweroff" "$ROOTFS_DIR/usr/local/bin/pmic-poweroff"
install -m 755 "$SCRIPT_DIR/scripts/retroarch-launch.sh" "$ROOTFS_DIR/usr/local/bin/retroarch-launch"
# RetroArch joypad autoconfig (gpio-keys buttons + adc-joystick analog sticks)
# RetroArch core options (per-core tuning for RK3326, from ROCKNIX)
install -m 644 "$SCRIPT_DIR/config/retroarch-core-options.cfg" "$ROOTFS_DIR/home/archr/.config/retroarch/retroarch-core-options.cfg"
log " ✓ RetroArch core options installed"
# Input merger daemon: combines gpio-keys + adc-joystick into single virtual device
# RetroArch needs all inputs on one device (udev driver assigns each to separate port)
if command -v aarch64-linux-gnu-gcc &>/dev/null; then
aarch64-linux-gnu-gcc -static -O2 -o "$ROOTFS_DIR/usr/local/bin/input-merge" \
"$SCRIPT_DIR/scripts/input-merge.c"
chmod 755 "$ROOTFS_DIR/usr/local/bin/input-merge"
log " ✓ input-merge compiled and installed"
else
warn "aarch64-linux-gnu-gcc not found — input-merge not compiled"
fi
# RetroArch joypad autoconfig (merged device + individual fallbacks)
mkdir -p "$ROOTFS_DIR/usr/share/retroarch/autoconfig/udev"
install -m 644 "$SCRIPT_DIR/config/autoconfig/udev/archr-gamepad.cfg" "$ROOTFS_DIR/usr/share/retroarch/autoconfig/udev/"
install -m 644 "$SCRIPT_DIR/config/autoconfig/udev/gpio-keys.cfg" "$ROOTFS_DIR/usr/share/retroarch/autoconfig/udev/"
install -m 644 "$SCRIPT_DIR/config/autoconfig/udev/adc-joystick.cfg" "$ROOTFS_DIR/usr/share/retroarch/autoconfig/udev/"
# systemd shutdown hook — runs pmic-poweroff at the very end of shutdown sequence
@@ -968,6 +1031,13 @@ log " ✓ Distro version installed (text.plymouth)"
install -m 755 "$SCRIPT_DIR/scripts/first-boot.sh" "$ROOTFS_DIR/usr/local/bin/first-boot.sh"
log " ✓ First boot script installed"
# Boot splash: no binary needed in rootfs — splash is embedded in initramfs /init
# (built by build-image.sh: archr-init.c + embedded splash BMP → initramfs.img)
# Panel detection wizard
install -m 755 "$SCRIPT_DIR/scripts/panel-detect.py" "$ROOTFS_DIR/usr/local/bin/panel-detect.py"
log " ✓ Panel detection wizard installed"
# RetroArch config (install to user's config dir where retroarch expects it)
mkdir -p "$ROOTFS_DIR/home/archr/.config/retroarch"
cp "$SCRIPT_DIR/config/retroarch.cfg" "$ROOTFS_DIR/home/archr/.config/retroarch/retroarch.cfg"
+174
View File
@@ -0,0 +1,174 @@
#!/bin/bash
#==============================================================================
# Arch R - Build Mainline U-Boot for R36S Clones
#==============================================================================
# Uses mainline U-Boot v2025.10 + ROCKNIX patches
# Produces: idbloader.img, uboot.img, trust.img (Rockchip format)
#
# Usage:
# ./build-uboot-clone.sh [--uart5]
#
# --uart5: Build for K36 clones that use UART5 instead of UART2
#==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
UBOOT_SRC="$SCRIPT_DIR/bootloader/u-boot-mainline"
RKBIN_DIR="$SCRIPT_DIR/bootloader/rkbin"
OUTPUT_DIR="$SCRIPT_DIR/bootloader/u-boot-clone-build"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[UBOOT-CLONE]${NC} $1"; }
warn() { echo -e "${YELLOW}[UBOOT-CLONE] WARNING:${NC} $1"; }
error() { echo -e "${RED}[UBOOT-CLONE] ERROR:${NC} $1"; exit 1; }
#------------------------------------------------------------------------------
# Parse arguments
#------------------------------------------------------------------------------
UART5=0
for arg in "$@"; do
case "$arg" in
--uart5) UART5=1 ;;
esac
done
#------------------------------------------------------------------------------
# Verify prerequisites
#------------------------------------------------------------------------------
CROSS_COMPILE="aarch64-linux-gnu-"
if ! command -v ${CROSS_COMPILE}gcc &>/dev/null; then
error "Cross-compiler not found. Install: sudo apt install gcc-aarch64-linux-gnu"
fi
if ! python3 -c "import elftools" 2>/dev/null; then
error "pyelftools not found. Install: pip3 install pyelftools"
fi
if ! command -v swig &>/dev/null; then
error "swig not found. Install: sudo apt install swig"
fi
[ -d "$UBOOT_SRC" ] || error "Mainline U-Boot source not found: $UBOOT_SRC"
[ -d "$RKBIN_DIR" ] || error "rkbin not found: $RKBIN_DIR"
#------------------------------------------------------------------------------
# Rockchip firmware binaries
#------------------------------------------------------------------------------
PKG_DDR_BIN="$RKBIN_DIR/bin/rk33/rk3326_ddr_333MHz_v2.11.bin"
PKG_MINILOADER="$RKBIN_DIR/bin/rk33/rk3326_miniloader_v1.40.bin"
PKG_BL31="$RKBIN_DIR/bin/rk33/rk3326_bl31_v1.34.elf"
[ -f "$PKG_DDR_BIN" ] || error "DDR binary not found: $PKG_DDR_BIN"
[ -f "$PKG_MINILOADER" ] || error "Miniloader not found: $PKG_MINILOADER"
[ -f "$PKG_BL31" ] || error "BL31 not found: $PKG_BL31"
#------------------------------------------------------------------------------
# UART5 DDR binary (for K36 clones)
#------------------------------------------------------------------------------
if [ "$UART5" -eq 1 ]; then
log "Building UART5 variant for K36 clones"
PKG_DDR_BIN_UART5="$RKBIN_DIR/rk3326_ddr_uart5.bin"
if [ ! -f "$PKG_DDR_BIN_UART5" ]; then
log "Creating UART5-tuned DDR binary..."
DDRBIN_TOOL="$RKBIN_DIR/tools/ddrbin_tool"
if [ ! -x "$DDRBIN_TOOL" ]; then
error "ddrbin_tool not found or not executable: $DDRBIN_TOOL"
fi
cp "$PKG_DDR_BIN" "$PKG_DDR_BIN_UART5"
"$DDRBIN_TOOL" rk3326 -g "$RKBIN_DIR/rk3326_ddr_uart5.txt" "$PKG_DDR_BIN_UART5"
sed -i 's|uart id=.*$|uart id=5|' "$RKBIN_DIR/rk3326_ddr_uart5.txt"
"$DDRBIN_TOOL" rk3326 "$RKBIN_DIR/rk3326_ddr_uart5.txt" "$PKG_DDR_BIN_UART5" >/dev/null
log "UART5 DDR binary created"
fi
PKG_DDR_BIN="$PKG_DDR_BIN_UART5"
fi
#------------------------------------------------------------------------------
# Build U-Boot
#------------------------------------------------------------------------------
JOBS=$(nproc)
DEFCONFIG="rk3326-handheld_defconfig"
log "=== Building Mainline U-Boot v2025.10 for R36S Clone ==="
log "Cross-compiler: $(${CROSS_COMPILE}gcc --version | head -1)"
log "Defconfig: $DEFCONFIG"
log "Jobs: $JOBS"
[ "$UART5" -eq 1 ] && log "UART: UART5 (0xFF178000)" || log "UART: UART2 (0xFF160000)"
cd "$UBOOT_SRC"
log "Step 1: Clean..."
make CROSS_COMPILE="$CROSS_COMPILE" ARCH=arm mrproper 2>&1 | tail -1
log "Step 2: Configure..."
make CROSS_COMPILE="$CROSS_COMPILE" ARCH=arm "$DEFCONFIG" 2>&1 | tail -1
# UART5 variant: override config
if [ "$UART5" -eq 1 ]; then
./scripts/config --set-val CONFIG_DEBUG_UART_BASE 0xFF178000
./scripts/config --set-str CONFIG_DEVICE_TREE_INCLUDES "rk3326-odroid-go2-emmc.dtsi rk3326-odroid-go2-uart5.dtsi"
log "UART5 config applied"
fi
log "Step 3: Compile..."
make CROSS_COMPILE="$CROSS_COMPILE" ARCH=arm -j"$JOBS" u-boot-dtb.bin 2>&1 | tail -20
[ -f "u-boot-dtb.bin" ] || error "Build failed: u-boot-dtb.bin not found"
log "u-boot-dtb.bin built: $(du -h u-boot-dtb.bin | cut -f1)"
#------------------------------------------------------------------------------
# Package: idbloader.img
#------------------------------------------------------------------------------
log "Step 4: Creating idbloader.img..."
"$UBOOT_SRC/tools/mkimage" -n px30 -T rksd -d "$PKG_DDR_BIN" -C bzip2 idbloader.img
cat "$PKG_MINILOADER" >> idbloader.img
log "idbloader.img: $(du -h idbloader.img | cut -f1)"
#------------------------------------------------------------------------------
# Package: uboot.img
#------------------------------------------------------------------------------
log "Step 5: Creating uboot.img..."
"$RKBIN_DIR/tools/loaderimage" --pack --uboot u-boot-dtb.bin uboot.img 0x00200000 2>&1 | tail -3
log "uboot.img: $(du -h uboot.img | cut -f1)"
#------------------------------------------------------------------------------
# Package: trust.img
#------------------------------------------------------------------------------
log "Step 6: Creating trust.img..."
cat >trust.ini <<EOF
[BL30_OPTION]
SEC=0
[BL31_OPTION]
SEC=1
PATH=${PKG_BL31}
ADDR=0x00010000
[BL32_OPTION]
SEC=0
[BL33_OPTION]
SEC=0
[OUTPUT]
PATH=trust.img
EOF
"$RKBIN_DIR/tools/trust_merger" --verbose trust.ini 2>&1 | tail -5
log "trust.img: $(du -h trust.img | cut -f1)"
#------------------------------------------------------------------------------
# Copy to output directory
#------------------------------------------------------------------------------
mkdir -p "$OUTPUT_DIR"
cp idbloader.img uboot.img trust.img "$OUTPUT_DIR/"
log ""
log "=== Build Complete ==="
log "Output: $OUTPUT_DIR/"
ls -lh "$OUTPUT_DIR/"*.img
log ""
log "Flash with:"
log " ./flash-uboot-clone.sh /dev/sdX"
+65 -35
View File
@@ -1,9 +1,18 @@
#!/bin/bash
#==============================================================================
# Arch R - Build U-Boot for R36S
# Arch R - U-Boot Build Script for R36S
#==============================================================================
# Builds U-Boot bootloader for RK3326 (R36S/RG351MP compatible)
# Builds custom U-Boot with R36S original/clone auto-detection via eMMC probe.
# Cross-compiles for aarch64 (CONFIG_ARM64=y in defconfig).
#
# Custom modifications:
# - cmd/hwrev.c: R36S detection via eMMC probe (original vs clone)
# - r36s-uboot.dts: U-Boot display DTB for original (Panel 4-V22 NV3052C)
# - r36s-clone-uboot.dts: U-Boot display DTB for clone (Type5 NV3052C)
#
# Prerequisites:
# sudo apt install gcc-aarch64-linux-gnu
#==============================================================================
set -e
@@ -29,7 +38,10 @@ UBOOT_REPO="https://github.com/christianhaitian/RG351MP-u-boot"
UBOOT_SRC="$UBOOT_DIR/u-boot-rk3326"
OUTPUT_DIR="$SCRIPT_DIR/output/bootloader"
log "=== Arch R - Build U-Boot ==="
# U-Boot for RK3326 is aarch64 (CONFIG_ARM64=y in defconfig)
CROSS_COMPILE="aarch64-linux-gnu-"
log "=== Arch R - U-Boot Builder (Custom R36S) ==="
#------------------------------------------------------------------------------
# Step 1: Clone U-Boot
@@ -42,59 +54,77 @@ mkdir -p "$UBOOT_DIR"
if [ ! -d "$UBOOT_SRC" ]; then
log " Cloning U-Boot for RK3326..."
git clone --depth 1 "$UBOOT_REPO" "$UBOOT_SRC"
log " ✓ U-Boot cloned"
log " Cloned"
else
log " ✓ U-Boot source exists"
log " Source exists"
fi
#------------------------------------------------------------------------------
# Step 2: Verify toolchain
#------------------------------------------------------------------------------
log ""
log "Step 2: Checking toolchain..."
if ! command -v ${CROSS_COMPILE}gcc &>/dev/null; then
error "aarch64 toolchain not found!\n Install: sudo apt install gcc-aarch64-linux-gnu"
fi
log " $(${CROSS_COMPILE}gcc --version | head -1)"
#------------------------------------------------------------------------------
# Step 3: Build U-Boot
#------------------------------------------------------------------------------
log ""
log "Step 3: Building U-Boot..."
cd "$UBOOT_SRC"
# GCC 13+ adds stricter warnings that U-Boot 2017.09 doesn't pass.
# Disable specific -Werror flags that break with modern GCC:
# address-of-packed-member: disk/part_efi.c (packed struct pointer)
# enum-int-mismatch: common/command.c (enum command_ret_t vs int)
# maybe-uninitialized: common/edid.c (hdmi_len variable)
GCC_COMPAT_FLAGS="-Wno-error=address-of-packed-member -Wno-error=enum-int-mismatch -Wno-error=maybe-uninitialized"
make CROSS_COMPILE=$CROSS_COMPILE odroidgoa_defconfig
make CROSS_COMPILE=$CROSS_COMPILE KCFLAGS="$GCC_COMPAT_FLAGS" -j$(nproc)
log " Built"
#------------------------------------------------------------------------------
# Step 2: Build U-Boot
# Step 4: Copy artifacts
#------------------------------------------------------------------------------
log ""
log "Step 2: Building U-Boot..."
# Set up cross-compiler (use Linaro if available, otherwise system)
if [ -d "/opt/toolchains/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu" ]; then
export PATH=/opt/toolchains/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin:$PATH
fi
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
# Build for OdroidGoA (compatible with R36S/RG351MP)
./make.sh odroidgoa 2>&1 | tail -20 || true
log " ✓ U-Boot built"
#------------------------------------------------------------------------------
# Step 3: Copy artifacts
#------------------------------------------------------------------------------
log ""
log "Step 3: Copying bootloader files..."
log "Step 4: Copying bootloader files..."
mkdir -p "$OUTPUT_DIR"
# Copy the bootloader images
if [ -d "sd_fuse" ]; then
if [ -d "sd_fuse" ] && [ -f "sd_fuse/idbloader.img" ]; then
cp sd_fuse/idbloader.img "$OUTPUT_DIR/"
cp sd_fuse/uboot.img "$OUTPUT_DIR/"
cp sd_fuse/trust.img "$OUTPUT_DIR/"
log " Bootloader files copied"
log " Bootloader binaries copied"
else
error "sd_fuse directory not found - U-Boot build may have failed"
error "sd_fuse directory not found U-Boot build may have failed"
fi
# Copy R36S U-Boot DTBs
for dtb in r36s-uboot.dtb r36s-clone-uboot.dtb; do
if [ -f "arch/arm/dts/$dtb" ]; then
cp "arch/arm/dts/$dtb" "$OUTPUT_DIR/"
log " DTB copied: $dtb"
else
warn "DTB not found: $dtb"
fi
done
#------------------------------------------------------------------------------
# Summary
#------------------------------------------------------------------------------
log ""
log "=== U-Boot Build Complete ==="
log ""
log "Bootloader files:"
ls -la "$OUTPUT_DIR/"
log "Bootloader: $OUTPUT_DIR/"
ls -lh "$OUTPUT_DIR/"
log ""
log "These will be automatically installed by build-image.sh"
log ""
log "✓ U-Boot ready for R36S!"
log "These will be installed by build-image.sh"
+73
View File
@@ -0,0 +1,73 @@
# Arch R Gamepad (merged gpio-keys + adc-joystick)
# Created by input-merge daemon — combines buttons and analog sticks
# into a single virtual device for RetroArch.
input_driver = "udev"
input_device = "Arch R Gamepad"
input_device_display_name = "Arch R Gamepad"
# Face buttons
input_b_btn = "0"
input_a_btn = "1"
input_y_btn = "2"
input_x_btn = "3"
# Shoulders
input_l_btn = "4"
input_r_btn = "5"
input_l2_btn = "6"
input_r2_btn = "7"
# Select / Start / Hotkey
input_select_btn = "8"
input_start_btn = "9"
input_enable_hotkey_btn = "10"
# Thumbstick clicks
input_l3_btn = "11"
input_r3_btn = "12"
# D-Pad
input_up_btn = "13"
input_down_btn = "14"
input_left_btn = "15"
input_right_btn = "16"
# Left analog stick
input_l_x_plus_axis = "+0"
input_l_x_minus_axis = "-0"
input_l_y_plus_axis = "+1"
input_l_y_minus_axis = "-1"
# Right analog stick
input_r_x_plus_axis = "+2"
input_r_x_minus_axis = "-2"
input_r_y_plus_axis = "+3"
input_r_y_minus_axis = "-3"
# Labels
input_b_btn_label = "B"
input_a_btn_label = "A"
input_y_btn_label = "Y"
input_x_btn_label = "X"
input_l_btn_label = "L1"
input_r_btn_label = "R1"
input_l2_btn_label = "L2"
input_r2_btn_label = "R2"
input_select_btn_label = "Select"
input_start_btn_label = "Start"
input_enable_hotkey_btn_label = "Mode"
input_l3_btn_label = "L3"
input_r3_btn_label = "R3"
input_up_btn_label = "D-Pad Up"
input_down_btn_label = "D-Pad Down"
input_left_btn_label = "D-Pad Left"
input_right_btn_label = "D-Pad Right"
input_l_x_plus_axis_label = "LS Right"
input_l_x_minus_axis_label = "LS Left"
input_l_y_plus_axis_label = "LS Down"
input_l_y_minus_axis_label = "LS Up"
input_r_x_plus_axis_label = "RS Right"
input_r_x_minus_axis_label = "RS Left"
input_r_y_plus_axis_label = "RS Down"
input_r_y_minus_axis_label = "RS Up"
+62 -16
View File
@@ -1,24 +1,70 @@
ODROIDGOA-UBOOT-CONFIG
odroidgoa-uboot-config
########################################################################
# Arch R Boot Configuration for R36S — Kernel 6.6 + Systemd
# Default panel: Panel 4-V22 (hardcoded in base DTB, no overlay needed)
# Primary boot: extlinux/extlinux.conf (U-Boot tries it first)
# This boot.ini is a fallback if extlinux is missing.
# Arch R Boot Configuration
#
# Auto-detects SD card MMC device AND root partition:
# Original R36S: eMMC=mmc0, SD=mmc1 → root=/dev/mmcblk1p2
# Clone (no eMMC): SD=mmc0 → root=/dev/mmcblk0p2
#
# Panel config from panel.txt (managed by panel-detect.py).
# Panel reset handled in Linux (panel-detect.py) -- no GPIO check here
# because X button GPIO differs between boards (modular!).
########################################################################
# Memory addresses — kernel at 0x02008000 (matches working R36S firmware)
setenv dtb_loadaddr "0x01f00000"
setenv loadaddr "0x02008000"
# --- Turn on LED immediately (feedback: device is booting) ---
gpio set b5
# Load kernel Image
if load mmc 1:1 ${loadaddr} Image
then
# Load DTB
if load mmc 1:1 ${dtb_loadaddr} rk3326-gameconsole-r36s.dtb
then
# Boot without initrd — use device path directly
setenv bootargs "root=/dev/mmcblk1p2 rootwait rw console=ttyFIQ0 loglevel=0 quiet vt.global_cursor_default=0 consoleblank=0 printk.devkmsg=off fsck.mode=skip"
setenv tmp_loadaddr "0x01e00000"
setenv dtb_loadaddr "0x01f00000"
setenv loadaddr "0x02000000"
# --- Auto-detect MMC device (loads kernel Image into memory) ---
setenv mmcdev 1
if load mmc 1:1 ${loadaddr} Image; then
setenv mmcdev 1
elif load mmc 0:1 ${loadaddr} Image; then
setenv mmcdev 0
else
sleep 15
poweroff
fi
# --- Panel DTB selection (read panel.txt written by panel-detect.py) ---
# Pre-merged DTBs: overlay already applied at build-time (no fdt apply needed).
# panel.txt contains PanelDTB=kernel-panelN.dtb (or empty for default).
setenv PanelDTB ""
mw.b ${tmp_loadaddr} 0x00 0x400
if load mmc ${mmcdev}:1 ${tmp_loadaddr} panel.txt; then
env import -t ${tmp_loadaddr} ${filesize}
fi
# Select DTB: pre-merged panel DTB if set, otherwise default kernel.dtb
if test -n "${PanelDTB}"; then
setenv dtb_name "${PanelDTB}"
echo "Panel DTB: ${PanelDTB}"
else
setenv dtb_name "kernel.dtb"
fi
# --- Auto-detect root device (SD card partition 2) ---
# mmcdev already detected above: 1 = original (eMMC+SD), 0 = clone (SD only)
if test "${mmcdev}" = "1"; then
setenv rootdev "/dev/mmcblk1p2"
else
setenv rootdev "/dev/mmcblk0p2"
fi
# --- Load DTB and boot (Image already loaded above) ---
if load mmc ${mmcdev}:1 ${dtb_loadaddr} ${dtb_name}; then
setenv bootargs "root=${rootdev} rootwait rw console=ttyFIQ0 loglevel=0 quiet vt.global_cursor_default=0 consoleblank=0 printk.devkmsg=off fsck.mode=skip"
# Load initramfs (splash appears immediately after kernel boot, before systemd)
setenv initrd_loadaddr "0x04000000"
if load mmc ${mmcdev}:1 ${initrd_loadaddr} initramfs.img; then
booti ${loadaddr} ${initrd_loadaddr}:${filesize} ${dtb_loadaddr}
else
booti ${loadaddr} - ${dtb_loadaddr}
fi
fi
+152
View File
@@ -0,0 +1,152 @@
mupen64plus-alt-map = "False"
mupen64plus-aspect = "4:3"
mupen64plus-astick-deadzone = "15"
mupen64plus-astick-sensitivity = "100"
mupen64plus-BackgroundMode = "Stripped"
mupen64plus-BilinearMode = "standard"
mupen64plus-CorrectTexrectCoords = "Auto"
mupen64plus-CountPerOp = "0"
mupen64plus-CountPerOpDenomPot = "0"
mupen64plus-cpucore = "dynamic_recompiler"
mupen64plus-d-cbutton = "C3"
mupen64plus-DitheringPattern = "True"
mupen64plus-DitheringQuantization = "True"
mupen64plus-EnableCopyAuxToRDRAM = "True"
mupen64plus-EnableCopyColorToRDRAM = "Async"
mupen64plus-EnableCopyDepthToRDRAM = "Software"
mupen64plus-EnableEnhancedHighResStorage = "False"
mupen64plus-EnableEnhancedTextureStorage = "False"
mupen64plus-EnableFBEmulation = "True"
mupen64plus-EnableFragmentDepthWrite = "False"
mupen64plus-EnableHiResAltCRC = "False"
mupen64plus-EnableHWLighting = "True"
mupen64plus-EnableInaccurateTextureCoordinates = "False"
mupen64plus-EnableLegacyBlending = "False"
mupen64plus-EnableLODEmulation = "True"
mupen64plus-EnableNativeResFactor = "1"
mupen64plus-EnableNativeResTexrects = "Optimized"
mupen64plus-EnableOverscan = "Enabled"
mupen64plus-EnableTexCoordBounds = "False"
mupen64plus-EnableTextureCache = "True"
mupen64plus-ForceDisableExtraMem = "False"
mupen64plus-FrameDuping = "True"
mupen64plus-Framerate = "Original"
mupen64plus-FXAA = "0"
mupen64plus-GLideN64IniBehaviour = "late"
mupen64plus-HybridFilter = "True"
mupen64plus-IgnoreTLBExceptions = "False"
mupen64plus-l-cbutton = "C2"
mupen64plus-MaxHiResTxVramLimit = "0"
mupen64plus-MaxTxCacheSize = "8000"
mupen64plus-MultiSampling = "0"
mupen64plus-OverscanBottom = "0"
mupen64plus-OverscanLeft = "0"
mupen64plus-OverscanRight = "0"
mupen64plus-OverscanTop = "0"
mupen64plus-pak1 = "memory"
mupen64plus-pak2 = "none"
mupen64plus-pak3 = "none"
mupen64plus-pak4 = "none"
mupen64plus-r-cbutton = "C1"
mupen64plus-rdp-plugin = "gliden64"
mupen64plus-RDRAMImageDitheringMode = "BlueNoise"
mupen64plus-rsp-plugin = "hle"
mupen64plus-ThreadedRenderer = "True"
mupen64plus-txCacheCompression = "True"
mupen64plus-txEnhancementMode = "None"
mupen64plus-txFilterIgnoreBG = "True"
mupen64plus-txFilterMode = "None"
mupen64plus-txHiresEnable = "False"
mupen64plus-txHiresFullAlphaChannel = "False"
mupen64plus-u-cbutton = "C4"
mupen64plus-virefresh = "Auto"
pcsx_rearmed_analog_axis_modifier = "circle"
pcsx_rearmed_async_cd = "sync"
pcsx_rearmed_bios = "auto"
pcsx_rearmed_display_internal_fps = "disabled"
pcsx_rearmed_dithering = "enabled"
pcsx_rearmed_drc = "enabled"
pcsx_rearmed_duping_enable = "enabled"
pcsx_rearmed_frameskip_type = "disabled"
pcsx_rearmed_gteregsunneeded = "disabled"
pcsx_rearmed_gunconadjustratiox = "1"
pcsx_rearmed_gunconadjustratioy = "1"
pcsx_rearmed_gunconadjustx = "0"
pcsx_rearmed_gunconadjusty = "0"
pcsx_rearmed_idiablofix = "disabled"
pcsx_rearmed_input_sensitivity = "1.00"
pcsx_rearmed_inuyasha_fix = "disabled"
pcsx_rearmed_memcard2 = "disabled"
pcsx_rearmed_multitap1 = "auto"
pcsx_rearmed_multitap2 = "auto"
pcsx_rearmed_negcon_deadzone = "0"
pcsx_rearmed_negcon_response = "linear"
pcsx_rearmed_neon_enhancement_enable = "disabled"
pcsx_rearmed_neon_enhancement_no_main = "disabled"
pcsx_rearmed_neon_interlace_enable = "disabled"
pcsx_rearmed_nocdaudio = "enabled"
pcsx_rearmed_nogteflags = "disabled"
pcsx_rearmed_nosmccheck = "disabled"
pcsx_rearmed_noxadecoding = "enabled"
pcsx_rearmed_pad1type = "standard"
pcsx_rearmed_pad2type = "standard"
pcsx_rearmed_pad3type = "none"
pcsx_rearmed_pad4type = "none"
pcsx_rearmed_pad5type = "none"
pcsx_rearmed_pad6type = "none"
pcsx_rearmed_pad7type = "none"
pcsx_rearmed_pad8type = "none"
pcsx_rearmed_pe2_fix = "disabled"
pcsx_rearmed_psxclock = "57"
pcsx_rearmed_region = "auto"
pcsx_rearmed_show_bios_bootlogo = "disabled"
pcsx_rearmed_show_other_input_settings = "disabled"
pcsx_rearmed_spu_interpolation = "simple"
pcsx_rearmed_spu_reverb = "enabled"
pcsx_rearmed_spuirq = "disabled"
pcsx_rearmed_vibration = "enabled"
gambatte_gb_colorization = "disabled"
gambatte_gb_internal_palette = ""
mame2003-plus_analog = "digital"
mame2003-plus_art_resolution = "1"
mame2003-plus_brightness = "1.0"
mame2003-plus_cheat_input_ports = "disabled"
mame2003-plus_core_save_subfolder = "enabled"
mame2003-plus_core_sys_subfolder = "enabled"
mame2003-plus_dcs_speedhack = "enabled"
mame2003-plus_deadzone = "20"
mame2003-plus_digital_joy_centering = "enabled"
mame2003-plus_display_artwork = "enabled"
mame2003-plus_display_setup = "disabled"
mame2003-plus_four_way_emulation = "disabled"
mame2003-plus_frameskip = "0"
mame2003-plus_gamma = "1.0"
mame2003-plus_input_interface = "retropad"
mame2003-plus_machine_timing = "enabled"
mame2003-plus_mame_remapping = "enabled"
mame2003-plus_mouse_device = "mouse"
mame2003-plus_sample_rate = "48000"
mame2003-plus_skip_disclaimer = "disabled"
mame2003-plus_skip_warnings = "disabled"
flycast_internal_resolution = "640x480"
flycast_alpha_sorting = "per-strip (fast, least accurate)"
flycast_enable_dsp = "disabled"
flycast_threaded_rendering = "enabled"
flycast_anisotropic_filtering = "off"
flycast_synchronous_rendering = "enabled"
flycast_enable_rtt = "disabled"
flycast_enable_rttb = "disabled"
flycast_delay_frame_swapping = "disabled"
flycast_div_matching = "auto"
flycast_texupscale = "off"
flycast_auto_skip_frame = "normal"
opera_swi_hle = "enabled"
opera_dsp_threaded = "enabled"
opera_madam_matrix_engine = "software"
puae_deadzone = "25"
melonds_screen_layout = "Left/Right"
melonds_swapscreen_mode = "Toggle"
melonds_threaded_renderer = "enabled"
melonds_touch_mode = "Joystick"
virtualjaguar_bios = "enabled"
virtualjaguar_usefastblitter = "enabled"
+17 -8
View File
@@ -1,5 +1,5 @@
# Arch R - RetroArch Configuration for R36S
# Optimized for 640x480 display
# Optimized for 640x480 display, tuned from ROCKNIX RK3326 defaults
# Video
video_driver = "gl"
@@ -7,22 +7,22 @@ video_context_driver = ""
video_fullscreen = "true"
video_windowed_fullscreen = "false"
video_vsync = "true"
video_max_swapchain_images = "2"
video_max_swapchain_images = "3"
video_smooth = "false"
video_scale_integer = "true"
video_scale_integer = "false"
video_rotation = "0"
video_aspect_ratio_auto = "true"
video_fullscreen_x = "640"
video_fullscreen_y = "480"
# Audio — matches dArkOS RG351MP (RK3326) settings
# Audio — tuned for RK3326 rk817 codec (48kHz native)
# alsathread: non-blocking audio, better for ARM
# audio_device empty: uses ALSA default (plug → hw:0,0 from asound.conf)
# 48kHz avoids double resampling (RA→44.1k→ALSA→48k)
# audio_volume +6dB: software boost to compensate rk817 codec low output level
audio_driver = "alsathread"
audio_device = ""
audio_out_rate = "44100"
audio_latency = "128"
audio_out_rate = "48000"
audio_latency = "64"
audio_sync = "true"
audio_enable = "true"
audio_volume = "6.000000"
@@ -31,6 +31,7 @@ audio_mixer_mute_enable = "false"
audio_rate_control = "true"
audio_rate_control_delta = "0.005000"
audio_resampler = "sinc"
audio_resampler_quality = "2"
audio_max_timing_skew = "0.050000"
# Microphone — DISABLED (binary built with --disable-microphone, belt-and-suspenders)
@@ -41,9 +42,10 @@ input_driver = "udev"
input_joypad_driver = "udev"
input_autodetect_enable = "true"
input_max_users = "1"
input_poll_type_behavior = "2"
joypad_autoconfig_dir = "/usr/share/retroarch/autoconfig"
# Menu (rgui — lightweight, better for 640x480 like dArkOS)
# Menu (rgui — lightweight, better for 640x480)
menu_driver = "rgui"
menu_swap_ok_cancel_buttons = "false"
@@ -55,10 +57,17 @@ libretro_directory = "/usr/lib/libretro"
libretro_info_path = "/usr/share/libretro/info"
assets_directory = "/usr/share/retroarch/assets"
system_directory = "/roms/bios"
core_options_path = "/home/archr/.config/retroarch/retroarch-core-options.cfg"
# Performance
video_threaded = "true"
video_frame_delay = "0"
game_specific_options = "true"
auto_overrides_enable = "true"
auto_remaps_enable = "true"
# Save protection (autosave SRAM every 10s, prevents loss on power-off)
autosave_interval = "10"
# Power Saving
suspend_screensaver_enable = "false"
+139
View File
@@ -0,0 +1,139 @@
#!/bin/bash
#==============================================================================
# Arch R - Flash Mainline U-Boot to Clone SD Card
#==============================================================================
# Flashes mainline U-Boot binaries to an existing Arch R SD card for clones.
# Does NOT touch partitions or rootfs — only U-Boot area.
#
# Also creates a minimal boot.scr for mainline U-Boot (distro boot).
#
# Usage:
# ./flash-uboot-clone.sh /dev/sdX
#==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[FLASH-CLONE]${NC} $1"; }
warn() { echo -e "${YELLOW}[FLASH-CLONE] WARNING:${NC} $1"; }
error() { echo -e "${RED}[FLASH-CLONE] ERROR:${NC} $1"; exit 1; }
#------------------------------------------------------------------------------
# Parse arguments
#------------------------------------------------------------------------------
if [ -z "$1" ]; then
echo "Usage: $0 /dev/sdX"
echo ""
echo "Available devices:"
lsblk -d -o NAME,SIZE,MODEL,TRAN | grep -E "sd|mmcblk" || true
exit 1
fi
DEVICE="$1"
if [ ! -b "$DEVICE" ]; then
error "Device not found: $DEVICE"
fi
# Safety check
if mount | grep -q "^${DEVICE}"; then
warn "Device $DEVICE has mounted partitions:"
mount | grep "^${DEVICE}" || true
echo ""
read -p "Continue anyway? (y/N) " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
fi
#------------------------------------------------------------------------------
# Verify binaries
#------------------------------------------------------------------------------
BUILD_DIR="$SCRIPT_DIR/bootloader/u-boot-clone-build"
for f in "$BUILD_DIR/idbloader.img" "$BUILD_DIR/uboot.img" "$BUILD_DIR/trust.img"; do
[ -f "$f" ] || error "Missing: $f (run build-uboot-clone.sh first)"
done
log "Device: $DEVICE"
log "Binaries: $BUILD_DIR"
log ""
log "Will flash:"
log " idbloader.img → sector 64 ($(du -h "$BUILD_DIR/idbloader.img" | cut -f1))"
log " uboot.img → sector 16384 ($(du -h "$BUILD_DIR/uboot.img" | cut -f1))"
log " trust.img → sector 24576 ($(du -h "$BUILD_DIR/trust.img" | cut -f1))"
log ""
read -p "Flash to $DEVICE? (y/N) " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
#------------------------------------------------------------------------------
# Flash U-Boot binaries (raw sectors)
#------------------------------------------------------------------------------
log "Flashing idbloader.img..."
pkexec dd if="$BUILD_DIR/idbloader.img" of="$DEVICE" bs=512 seek=64 conv=sync,noerror,notrunc 2>/dev/null
log "Flashing uboot.img..."
pkexec dd if="$BUILD_DIR/uboot.img" of="$DEVICE" bs=512 seek=16384 conv=sync,noerror,notrunc 2>/dev/null
log "Flashing trust.img..."
pkexec dd if="$BUILD_DIR/trust.img" of="$DEVICE" bs=512 seek=24576 conv=sync,noerror,notrunc 2>/dev/null
log "U-Boot binaries flashed"
#------------------------------------------------------------------------------
# Create boot.scr on BOOT partition
#------------------------------------------------------------------------------
BOOT_PART="${DEVICE}1"
if [ ! -b "$BOOT_PART" ]; then
BOOT_PART="${DEVICE}p1"
fi
if [ ! -b "$BOOT_PART" ]; then
warn "BOOT partition not found — boot.scr NOT created"
else
MOUNT_TMP=$(mktemp -d)
pkexec mount "$BOOT_PART" "$MOUNT_TMP"
# Create boot.scr from boot.ini (strip BSP-specific commands)
MKIMAGE="$SCRIPT_DIR/bootloader/u-boot-mainline/tools/mkimage"
if [ -x "$MKIMAGE" ] && [ -f "$MOUNT_TMP/boot.ini" ]; then
log "Creating boot.scr from boot.ini..."
TMP_SCR=$(mktemp)
# Strip 'odroidgoa-uboot-config' (BSP command, not in mainline)
grep -v '^odroidgoa-uboot-config' "$MOUNT_TMP/boot.ini" > "$TMP_SCR"
"$MKIMAGE" -T script -d "$TMP_SCR" "$MOUNT_TMP/boot.scr" 2>/dev/null && \
log "boot.scr created" || \
warn "boot.scr creation failed"
rm -f "$TMP_SCR"
fi
log "BOOT partition contents:"
ls "$MOUNT_TMP/" | head -20
pkexec umount "$MOUNT_TMP"
rmdir "$MOUNT_TMP"
fi
#------------------------------------------------------------------------------
# Done
#------------------------------------------------------------------------------
sync
log ""
log "=== Mainline U-Boot flashed to $DEVICE ==="
log ""
log "This is MAINLINE U-Boot (not BSP). Key differences:"
log " - Uses go2.c board detection (not hwrev.c)"
log " - Boots via boot.scr / extlinux.conf (not boot.ini directly)"
log " - Display: mainline DRM (may not show boot logo)"
log ""
log "If boot fails, restore working clone U-Boot:"
log " pkexec dd if=bootloader/u-boot-clone-working/uboot.img of=$DEVICE bs=512 seek=16384 conv=notrunc"
log " pkexec dd if=bootloader/u-boot-clone-working/idbloader.img of=$DEVICE bs=512 seek=64 conv=notrunc"
log " pkexec dd if=bootloader/u-boot-clone-working/trust.img of=$DEVICE bs=512 seek=24576 conv=notrunc"
Executable
+136
View File
@@ -0,0 +1,136 @@
#!/bin/bash
#==============================================================================
# Arch R - Flash Custom U-Boot to SD Card
#==============================================================================
# Flashes custom U-Boot binaries + display DTBs to an existing Arch R SD card.
# Does NOT touch partitions or rootfs — only U-Boot area + BOOT partition DTBs.
#
# Usage:
# ./flash-uboot.sh /dev/sdX
#==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[FLASH]${NC} $1"; }
warn() { echo -e "${YELLOW}[FLASH] WARNING:${NC} $1"; }
error() { echo -e "${RED}[FLASH] ERROR:${NC} $1"; exit 1; }
#------------------------------------------------------------------------------
# Parse arguments
#------------------------------------------------------------------------------
if [ -z "$1" ]; then
echo "Usage: $0 /dev/sdX"
echo ""
echo "Available devices:"
lsblk -d -o NAME,SIZE,MODEL,TRAN | grep -E "sd|mmcblk" || true
exit 1
fi
DEVICE="$1"
if [ ! -b "$DEVICE" ]; then
error "Device not found: $DEVICE"
fi
# Safety: refuse whole-disk devices that look like system disks
if mount | grep -q "^${DEVICE}"; then
warn "Device $DEVICE has mounted partitions:"
mount | grep "^${DEVICE}" || true
echo ""
read -p "Continue anyway? (y/N) " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
fi
#------------------------------------------------------------------------------
# Verify binaries
#------------------------------------------------------------------------------
SDFUSE="$SCRIPT_DIR/bootloader/u-boot-rk3326/sd_fuse"
DTS_DIR="$SCRIPT_DIR/bootloader/u-boot-rk3326/arch/arm/dts"
for f in "$SDFUSE/idbloader.img" "$SDFUSE/uboot.img" "$SDFUSE/trust.img"; do
[ -f "$f" ] || error "Missing: $f"
done
for f in "$DTS_DIR/r36s-uboot.dtb" "$DTS_DIR/r36-uboot.dtb"; do
[ -f "$f" ] || error "Missing: $f"
done
log "Device: $DEVICE"
log "Binaries: $SDFUSE"
log ""
log "Will flash:"
log " idbloader.img → sector 64 ($(du -h "$SDFUSE/idbloader.img" | cut -f1))"
log " uboot.img → sector 16384 ($(du -h "$SDFUSE/uboot.img" | cut -f1))"
log " trust.img → sector 24576 ($(du -h "$SDFUSE/trust.img" | cut -f1))"
log " r36s-uboot.dtb + r36-uboot.dtb → BOOT partition"
log ""
read -p "Flash to $DEVICE? (y/N) " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 1
#------------------------------------------------------------------------------
# Flash U-Boot binaries (raw sectors)
#------------------------------------------------------------------------------
log "Flashing idbloader.img..."
pkexec dd if="$SDFUSE/idbloader.img" of="$DEVICE" bs=512 seek=64 conv=sync,noerror,notrunc 2>/dev/null
log "Flashing uboot.img..."
pkexec dd if="$SDFUSE/uboot.img" of="$DEVICE" bs=512 seek=16384 conv=sync,noerror,notrunc 2>/dev/null
log "Flashing trust.img..."
pkexec dd if="$SDFUSE/trust.img" of="$DEVICE" bs=512 seek=24576 conv=sync,noerror,notrunc 2>/dev/null
log "U-Boot binaries flashed"
#------------------------------------------------------------------------------
# Copy display DTBs to BOOT partition
#------------------------------------------------------------------------------
BOOT_PART="${DEVICE}1"
if [ ! -b "$BOOT_PART" ]; then
# Try mmcblk style (p1)
BOOT_PART="${DEVICE}p1"
fi
if [ ! -b "$BOOT_PART" ]; then
warn "BOOT partition not found ($BOOT_PART) — display DTBs NOT copied"
warn "Copy manually: r36s-uboot.dtb + r36-uboot.dtb to BOOT partition"
else
MOUNT_TMP=$(mktemp -d)
pkexec mount "$BOOT_PART" "$MOUNT_TMP"
pkexec cp "$DTS_DIR/r36s-uboot.dtb" "$MOUNT_TMP/"
pkexec cp "$DTS_DIR/r36-uboot.dtb" "$MOUNT_TMP/"
# Verify
log "BOOT partition contents:"
ls -la "$MOUNT_TMP/"*.dtb 2>/dev/null || true
pkexec umount "$MOUNT_TMP"
rmdir "$MOUNT_TMP"
log "Display DTBs copied to BOOT partition"
fi
#------------------------------------------------------------------------------
# Done
#------------------------------------------------------------------------------
sync
log ""
log "=== Custom U-Boot flashed to $DEVICE ==="
log ""
log "Test on R36S original → should detect eMMC → r36s-uboot.dtb → logo"
log "Test on R36S clone → no eMMC → r36-uboot.dtb → logo"
log ""
log "If boot fails (red LED blink), restore working U-Boot:"
log " Original: bootloader/u-boot-r36s-working/"
log " Clone: bootloader/u-boot-clone-working/"
File diff suppressed because it is too large Load Diff
+26 -12
View File
@@ -25,9 +25,12 @@ except ImportError:
sys.exit(1)
# Volume step (percentage per key press)
VOL_STEP = 2
VOL_STEP = 5
# Brightness step (percentage per key press)
BRIGHT_STEP = 3
BRIGHT_STEP = 5
# Minimum interval between volume/brightness actions (seconds)
# adc-keys autorepeat fires at ~30Hz — throttle to ~3 events/sec
VOL_THROTTLE = 0.3
# Minimum brightness percentage (prevent black screen)
BRIGHT_MIN = 5
# Brightness persistence file
@@ -177,6 +180,7 @@ def brightness_up():
def brightness_down():
if get_brightness_pct() <= BRIGHT_MIN:
return
log(f"BRIGHT- brightnessctl s {BRIGHT_STEP}%-")
run_cmd(f"brightnessctl -q s {BRIGHT_STEP}%-")
# Clamp: if we went below minimum, set to minimum
if get_brightness_pct() < BRIGHT_MIN:
@@ -203,7 +207,7 @@ def find_devices():
name = dev.name.lower()
caps = dev.capabilities()
if 'gpio-keys' in name:
if 'gpio-keys' in name or 'adc-keys' in name:
# Distinguish vol device from gamepad by checking for KEY_VOLUMEUP
key_caps = caps.get(ecodes.EV_KEY, [])
if ecodes.KEY_VOLUMEUP in key_caps:
@@ -253,6 +257,8 @@ def main():
# Track MODE button state for brightness hotkey combo
mode_held = False
# Throttle: last time a volume/brightness action was executed
last_vol_action = 0.0
print("Hotkey daemon ready.")
# Clear previous log on fresh start
@@ -298,18 +304,26 @@ def main():
elif val == 0:
mode_held = False
# Volume keys from gpio-keys-vol (grabbed)
# Volume keys (grabbed): accept press + repeat,
# but throttle to max ~3 events/sec (300ms interval).
# adc-keys autorepeat fires at ~30Hz natively.
elif key == ecodes.KEY_VOLUMEUP and val in (1, 2):
if mode_held:
brightness_up()
else:
volume_up()
now = time.monotonic()
if now - last_vol_action >= VOL_THROTTLE:
last_vol_action = now
if mode_held:
brightness_up()
else:
volume_up()
elif key == ecodes.KEY_VOLUMEDOWN and val in (1, 2):
if mode_held:
brightness_down()
else:
volume_down()
now = time.monotonic()
if now - last_vol_action >= VOL_THROTTLE:
last_vol_action = now
if mode_held:
brightness_down()
else:
volume_down()
# Headphone jack switch
elif event.type == ecodes.EV_SW:
+325
View File
@@ -0,0 +1,325 @@
/*
* archr-init — initramfs /init for Arch R
*
* Shows splash on /dev/fb0 IMMEDIATELY after kernel boot (before systemd).
* Splash image is EMBEDDED in the binary (no file I/O needed).
* Then mounts the real root filesystem and switch_root to /sbin/init.
*
* Initramfs contents:
* /init → this binary (static aarch64, includes splash data)
* /dev/ → empty (devtmpfs mounted here)
* /proc/ → empty (proc mounted temporarily)
* /newroot/ → empty (real root mounted here)
*
* Build:
* xxd -i splash.bmp > splash_data.h
* aarch64-linux-gnu-gcc -static -O2 -o archr-init archr-init.c
*/
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <linux/fb.h>
#include <errno.h>
#include <time.h>
/* Embedded splash image (generated by xxd -i splash.bmp) */
#include "splash_data.h"
/* ---- Logging (dmesg + in-memory buffer, flushed to file after root mount) ---- */
static int kmsg_fd = -1;
#define LOG_BUF_SIZE 4096
static char log_buf[LOG_BUF_SIZE];
static int log_pos = 0;
/* Simple snprintf — avoid pulling in full stdio */
static int fmt_int(char *buf, int val)
{
if (val < 0) { *buf++ = '-'; val = -val; return 1 + fmt_int(buf, val); }
if (val >= 10) { int n = fmt_int(buf, val / 10); return n + fmt_int(buf + n, val % 10); }
*buf = '0' + val;
return 1;
}
static void klog(const char *msg)
{
/* Save msg pointer before we iterate */
const char *saved_msg = msg;
/* Write to dmesg */
if (kmsg_fd < 0)
kmsg_fd = open("/dev/kmsg", O_WRONLY);
if (kmsg_fd >= 0) {
char buf[256];
int i = 0;
const char *prefix = "archr-init: ";
while (*prefix) buf[i++] = *prefix++;
while (*msg && i < 250) buf[i++] = *msg++;
buf[i++] = '\n';
write(kmsg_fd, buf, i);
}
/* Buffer for file log (using saved pointer) */
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (log_pos < LOG_BUF_SIZE - 200) {
log_pos += fmt_int(log_buf + log_pos, (int)ts.tv_sec);
log_buf[log_pos++] = '.';
int ms = (int)(ts.tv_nsec / 1000000);
if (ms < 100) log_buf[log_pos++] = '0';
if (ms < 10) log_buf[log_pos++] = '0';
log_pos += fmt_int(log_buf + log_pos, ms);
log_buf[log_pos++] = ' ';
while (*saved_msg && log_pos < LOG_BUF_SIZE - 2)
log_buf[log_pos++] = *saved_msg++;
log_buf[log_pos++] = '\n';
}
}
static void klog_num(const char *prefix, int val)
{
char buf[128];
int i = 0;
while (*prefix && i < 100) buf[i++] = *prefix++;
i += fmt_int(buf + i, val);
buf[i] = 0;
klog(buf);
}
static void flush_log(const char *path)
{
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd >= 0) {
write(fd, log_buf, log_pos);
close(fd);
}
}
/* ---- BMP parsing (from embedded data) ---- */
#pragma pack(push, 1)
typedef struct {
uint16_t type;
uint32_t size;
uint16_t reserved1;
uint16_t reserved2;
uint32_t offset;
} BMPFileHeader;
typedef struct {
uint32_t size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t image_size;
int32_t x_ppm;
int32_t y_ppm;
uint32_t colors_used;
uint32_t colors_important;
} BMPInfoHeader;
#pragma pack(pop)
/* ---- Splash display (writes embedded BMP to /dev/fb0) ---- */
static void show_splash(void)
{
/* Validate embedded BMP data */
/* splash_data.h defines: unsigned char splash_bmp[] and unsigned int splash_bmp_len */
extern unsigned char splash_bmp[];
extern unsigned int splash_bmp_len;
if (splash_bmp_len < sizeof(BMPFileHeader) + sizeof(BMPInfoHeader)) {
klog("splash: embedded data too small");
return;
}
BMPFileHeader *fh = (BMPFileHeader *)splash_bmp;
BMPInfoHeader *ih = (BMPInfoHeader *)(splash_bmp + sizeof(BMPFileHeader));
if (fh->type != 0x4D42 || (ih->bpp != 24 && ih->bpp != 32)) {
klog("splash: invalid BMP header");
return;
}
int32_t bmp_w = ih->width;
int32_t bmp_h = ih->height > 0 ? ih->height : -ih->height;
int bottom_up = ih->height > 0;
uint32_t src_bpp = ih->bpp / 8;
uint32_t src_row_padded = (bmp_w * src_bpp + 3) & ~3;
uint8_t *pixel_data = splash_bmp + fh->offset;
klog("splash: BMP parsed from embedded data");
/* Wait for fb0 (DRM probe might still be finishing) */
int fb_fd = -1;
int retries;
for (retries = 0; retries < 30; retries++) {
fb_fd = open("/dev/fb0", O_RDWR);
if (fb_fd >= 0) break;
usleep(100000); /* 100ms, max 3s */
}
if (fb_fd < 0) {
klog("splash: fb0 NOT FOUND after 3s");
return;
}
klog_num("splash: fb0 opened, retries=", retries);
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ||
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
klog("splash: ioctl failed");
close(fb_fd);
return;
}
uint32_t fb_w = vinfo.xres;
uint32_t fb_h = vinfo.yres;
uint32_t fb_bpp_bytes = vinfo.bits_per_pixel / 8;
uint32_t stride = finfo.line_length;
uint32_t fb_size = stride * fb_h;
klog_num("splash: fb width=", (int)fb_w);
klog_num("splash: fb height=", (int)fb_h);
klog_num("splash: fb bpp=", (int)vinfo.bits_per_pixel);
/* Write directly to fb0 — row by row to avoid large malloc */
/* First: clear the framebuffer (black) */
{
uint8_t zero[2560]; /* enough for 640px * 4bpp */
memset(zero, 0, sizeof(zero));
lseek(fb_fd, 0, SEEK_SET);
for (uint32_t y = 0; y < fb_h; y++)
write(fb_fd, zero, stride < sizeof(zero) ? stride : sizeof(zero));
}
/* Then: write BMP pixels */
uint32_t copy_w = (uint32_t)bmp_w < fb_w ? (uint32_t)bmp_w : fb_w;
uint32_t copy_h = (uint32_t)bmp_h < fb_h ? (uint32_t)bmp_h : fb_h;
uint8_t row_buf[2560]; /* enough for 640px * 4bpp */
for (uint32_t y = 0; y < copy_h; y++) {
uint32_t src_y = bottom_up ? (bmp_h - 1 - y) : y;
uint8_t *src_row = pixel_data + src_y * src_row_padded;
memset(row_buf, 0, stride < sizeof(row_buf) ? stride : sizeof(row_buf));
for (uint32_t x = 0; x < copy_w; x++) {
uint8_t b = src_row[x * src_bpp + 0];
uint8_t g = src_row[x * src_bpp + 1];
uint8_t r = src_row[x * src_bpp + 2];
if (fb_bpp_bytes == 4) {
row_buf[x * 4 + 0] = b;
row_buf[x * 4 + 1] = g;
row_buf[x * 4 + 2] = r;
row_buf[x * 4 + 3] = 0xFF;
} else if (fb_bpp_bytes == 2) {
uint16_t c = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
row_buf[x * 2 + 0] = c & 0xFF;
row_buf[x * 2 + 1] = (c >> 8) & 0xFF;
}
}
lseek(fb_fd, y * stride, SEEK_SET);
write(fb_fd, row_buf, stride < sizeof(row_buf) ? stride : sizeof(row_buf));
}
klog("splash: written to fb0");
close(fb_fd);
}
/* ---- Main: initramfs /init ---- */
int main(int argc, char *argv[])
{
/* 1. Mount devtmpfs on /dev (kernel creates device nodes here) */
mkdir("/dev", 0755);
mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
klog("=== INITRAMFS STARTED ===");
/* 2. Show splash from embedded data — no file I/O needed */
show_splash();
/* 3. Parse root= and rw from kernel cmdline */
mkdir("/proc", 0755);
mount("proc", "/proc", "proc", 0, NULL);
char cmdline[4096];
memset(cmdline, 0, sizeof(cmdline));
int fd = open("/proc/cmdline", O_RDONLY);
if (fd >= 0) {
read(fd, cmdline, sizeof(cmdline) - 1);
close(fd);
}
umount("/proc");
/* Extract root= device path */
char rootdev[256] = "/dev/mmcblk1p2"; /* default: original R36S */
char *p = strstr(cmdline, "root=");
if (p) {
p += 5;
int i = 0;
while (*p && *p != ' ' && i < 255)
rootdev[i++] = *p++;
rootdev[i] = 0;
}
/* Check rw flag */
unsigned long mflags = MS_NOATIME;
if (strstr(cmdline, " rw"))
mflags |= 0; /* rw is default without MS_RDONLY */
else
mflags |= MS_RDONLY;
klog(rootdev);
/* 4. Mount real root (retry — MMC might still be probing) */
mkdir("/newroot", 0755);
int mounted = 0;
int mount_retries;
for (mount_retries = 0; mount_retries < 50; mount_retries++) {
if (mount(rootdev, "/newroot", "ext4", mflags, NULL) == 0) {
mounted = 1;
break;
}
usleep(100000); /* 100ms, max 5s total */
}
if (!mounted) {
klog("FATAL: could not mount root!");
for (;;) sleep(60);
}
klog_num("root mounted, retries=", mount_retries);
/* 5. Write diagnostic log to root filesystem */
klog("switch_root");
flush_log("/newroot/var/log/archr-init.log");
/* 6. Move /dev to new root */
mount("/dev", "/newroot/dev", NULL, MS_MOVE, NULL);
/* 7. switch_root: pivot to real rootfs and exec systemd */
if (kmsg_fd >= 0) close(kmsg_fd);
chdir("/newroot");
mount(".", "/", NULL, MS_MOVE, NULL);
chroot(".");
chdir("/");
execl("/sbin/init", "/sbin/init", NULL);
/* Should never reach here */
return 1;
}
+2 -2
View File
@@ -50,8 +50,8 @@ _bt "after_amixer"
# === BACKGROUND: Everything else runs parallel with ES SDL init (~2s window) ===
(
# Framebuffer blank (hides login text, ES takes over via KMSDRM anyway)
dd if=/dev/zero of=/dev/fb0 bs=614400 count=1 2>/dev/null
# NOTE: fb0 blank removed — archr-splash.service writes splash to fb0,
# which persists until ES takes DRM master via KMSDRM.
# Permissions + governors (single sudo)
sudo sh -c '/usr/local/bin/perfmax; chmod 666 /dev/tty1 /dev/dri/* /sys/class/backlight/backlight/brightness' 2>/dev/null

Some files were not shown because too many files have changed in this diff Show More