From 859bab2c0ede46913690e9bcf4994b614196e03c Mon Sep 17 00:00:00 2001 From: Douglas Teles Date: Mon, 25 May 2026 18:07:12 -0300 Subject: [PATCH] Add support for GamePark GP32 emulator and update GPU driver installation path --- config/emulators/gp32.conf | 9 ++ .../RK3326/SUPPORTED_EMULATORS_AND_CORES.md | 1 + .../gpudriver/autostart/003-gpudriver | 4 +- .../packages/graphics/gpudriver/package.mk | 20 ++- .../graphics/gpudriver/sources/bin/gpudriver | 136 +++++++++++++++++- .../ArchR/packages/graphics/mesa/package.mk | 2 +- .../packages/virtual/emulators/package.mk | 4 + 7 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 config/emulators/gp32.conf diff --git a/config/emulators/gp32.conf b/config/emulators/gp32.conf new file mode 100644 index 0000000000..cc2d731920 --- /dev/null +++ b/config/emulators/gp32.conf @@ -0,0 +1,9 @@ +SYSTEM_NAME="gp32" +SYSTEM_FULLNAME="GP32" +SYSTEM_MANUFACTURER="GamePark" +SYSTEM_HARDWARE="portable" +SYSTEM_PATH="/storage/roms/gp32" +SYSTEM_EXTENSION=".smc .zip .7z" +SYSTEM_PLATFORM="gp32" +SYSTEM_THEME="gp32" +SYSTEM_WIKI_PATH="gp32" diff --git a/documentation/PER_DEVICE_DOCUMENTATION/RK3326/SUPPORTED_EMULATORS_AND_CORES.md b/documentation/PER_DEVICE_DOCUMENTATION/RK3326/SUPPORTED_EMULATORS_AND_CORES.md index c56d945e0e..635db2f466 100644 --- a/documentation/PER_DEVICE_DOCUMENTATION/RK3326/SUPPORTED_EMULATORS_AND_CORES.md +++ b/documentation/PER_DEVICE_DOCUMENTATION/RK3326/SUPPORTED_EMULATORS_AND_CORES.md @@ -40,6 +40,7 @@ |Elektronika|Elektronika BK (bk)|1984|`bk`|.bin .img .dsk|**retroarch:** bk (default)
| |EPOCH/YENO|Super Cassette Vision (scv)|1984|`scv`|.cart .bin .rom .0 .zip|**retroarch:** emuscv (default)
| |Fairchild|Fairchild Channel F (channelf)|1976|`channelf`|.bin .chf .zip .7z|**retroarch:** freechaf (default)
| +|GamePark|GP32 (gp32)|1996|`gp32`|.smc .zip .7z|**retroarch:** mame (default)
| |id Software|Doom (doom)|1993|`doom`|.doom|**gzdoom:** gzdoom-sa (default)
| |id Software|iDtech (idtech)|1991|`idtech`|.sh|**retroarch:** idtech
| |Infocom|Z-machine (zmachine)|1979|`zmachine`|.dat .z1 .z2 .z3 .z4 .z5 .z6 .zip|**retroarch:** mojozork (default)
| diff --git a/projects/ArchR/packages/graphics/gpudriver/autostart/003-gpudriver b/projects/ArchR/packages/graphics/gpudriver/autostart/003-gpudriver index fdcf196e55..a2e596203c 100755 --- a/projects/ArchR/packages/graphics/gpudriver/autostart/003-gpudriver +++ b/projects/ArchR/packages/graphics/gpudriver/autostart/003-gpudriver @@ -2,4 +2,6 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2024 ArchR (https://github.com/archr-linux/Arch-R) -/usr/bin/gpudriver --start +# Binary lives under /usr/lib/archr/ instead of /usr/bin/ so the ES menu +# GPU DRIVER selector stays hidden while the panfrost path is unstable. +/usr/lib/archr/gpudriver --start diff --git a/projects/ArchR/packages/graphics/gpudriver/package.mk b/projects/ArchR/packages/graphics/gpudriver/package.mk index 12d9aac41c..0d373702a5 100644 --- a/projects/ArchR/packages/graphics/gpudriver/package.mk +++ b/projects/ArchR/packages/graphics/gpudriver/package.mk @@ -11,9 +11,17 @@ PKG_TOOLCHAIN="manual" PKG_LONGDESC="GPU driver util for switching between panfrost / panthor and libmali / libmali-vulkan" post_makeinstall_target() { - mkdir -p "${INSTALL}/usr/bin/" - cp -v "${PKG_BUILD}/bin/gpudriver" "${INSTALL}/usr/bin/" - + # Install OUTSIDE /usr/bin while the panfrost path is still unreliable + # on RK3326 clones. EmulationStation surfaces the GPU DRIVER selector + # only when `/usr/bin/gpudriver` exists (see es-app GuiMenu.cpp), so + # placing it under /usr/lib/archr/ hides the picker without removing + # any boot-time functionality — the autostart hook (003-gpudriver) + # calls this binary by full path. Move back to /usr/bin/gpudriver + # once panfrost on the Mali-G31 path stops hanging the kernel. + mkdir -p "${INSTALL}/usr/lib/archr/" + cp -v "${PKG_BUILD}/bin/gpudriver" "${INSTALL}/usr/lib/archr/" + GPUDRIVER_BIN="${INSTALL}/usr/lib/archr/gpudriver" + # set the correct mesa pan kernel driver module based on device case ${DEVICE} in RK3588) @@ -39,11 +47,11 @@ post_makeinstall_target() { esac sed -e "s/@PAN@/${PAN}/g" \ - -i ${INSTALL}/usr/bin/gpudriver + -i "${GPUDRIVER_BIN}" sed -e "s/@DTB_OVERLAY_LOAD@/${DTB_OVERLAY_LOAD}/g" \ - -i ${INSTALL}/usr/bin/gpudriver + -i "${GPUDRIVER_BIN}" sed -e "s/@DTB_OVERLAY_UNLOAD@/${DTB_OVERLAY_UNLOAD}/g" \ - -i ${INSTALL}/usr/bin/gpudriver + -i "${GPUDRIVER_BIN}" } \ No newline at end of file diff --git a/projects/ArchR/packages/graphics/gpudriver/sources/bin/gpudriver b/projects/ArchR/packages/graphics/gpudriver/sources/bin/gpudriver index 975f88e958..cae5d54d82 100755 --- a/projects/ArchR/packages/graphics/gpudriver/sources/bin/gpudriver +++ b/projects/ArchR/packages/graphics/gpudriver/sources/bin/gpudriver @@ -25,7 +25,14 @@ log_event() { local msg="$1" mkdir -p "$(dirname "${GPUDRIVER_LOG}")" 2>/dev/null echo "$(date '+%Y-%m-%d %H:%M:%S') gpudriver: ${msg}" >>"${GPUDRIVER_LOG}" 2>/dev/null - logger -t gpudriver "${msg}" 2>/dev/null + # Intentionally do NOT call `logger` here. The parallel autostart Phase B + # bursts hundreds of log messages at once; the journald socket fills, and + # `logger` (a synchronous binary) blocks waiting for the daemon to drain. + # That deadlock pinned gpudriver between "calling load_driver panfrost" + # and the next log step on R36S 20260515 builds — the script never + # returned, the autostart wait never finished, and the watchdog reset + # the board. The on-disk echo above is enough for our post-mortem + # diagnostic needs. } # Verify the GPU node ended up bound to the requested kernel driver AND @@ -102,7 +109,13 @@ load_driver() { case ${DRIVER_TO_LOAD} in "libmali") - modprobe -r @PAN@ 2>/dev/null + # Symmetric safety: only rmmod @PAN@ if loaded. In-tree panfrost + # is safer to unload than mali_kbase but skip anyway — a reboot + # gives a cleaner switch and matches the user's expectation that + # changing GPU driver requires a restart. + if lsmod 2>/dev/null | grep -q "^@PAN@ "; then + log_event "libmali: @PAN@ loaded — switch needs reboot to take effect" + fi modprobe mali_kbase # Bind-mount mali GLES libraries over mesa if not already done. @@ -121,8 +134,75 @@ load_driver() { done ;; "panfrost") - modprobe -r mali_kbase 2>/dev/null - modprobe @PAN@ + # Snapshot ANY kernel messages before we touch the driver. If the + # system is already in a degraded state by the time gpudriver + # runs (e.g. an earlier autostart script tickled something), we + # want to see it in the post-mortem rather than blaming the + # subsequent modprobe. + log_event "panfrost: step 0a - capturing pre-state dmesg" + dmesg -T 2>/dev/null | tail -100 >>"${GPUDRIVER_LOG}.dmesg-pre" 2>/dev/null + log_event "panfrost: step 0b - dmesg pre-state captured" + + # mali_kbase is the ARM vendor out-of-tree blob. Its driver-exit + # path double-frees the GPU regulator and clock at unbind time + # (observed kernel Oops in __clk_put at POISON_LIST_END + + # _regulator_put WARN, cascading into further oopses until the + # board watchdog resets — confirmed on R36S with kernel 6.12.79). + # Removing it in-place is therefore unsafe: skip the rmmod + # entirely if the module is loaded and let the user reboot to + # land in a fresh kernel where the module never came up. If the + # module is NOT loaded we can proceed; this is the normal case + # on a fresh boot where gpu.driver=panfrost. + if lsmod 2>/dev/null | grep -q "^mali_kbase "; then + log_event "panfrost: step 1 - mali_kbase IS LOADED, skipping rmmod (would crash kernel) — reboot required for switch to take effect" + else + log_event "panfrost: step 1 - mali_kbase not loaded, no rmmod needed" + fi + log_event "panfrost: step 2 - rmmod check done" + + # Snapshot the last dmesg line so we can quote only what the + # panfrost probe added. + PRE_DMESG_COUNT=$(dmesg 2>/dev/null | wc -l) + log_event "panfrost: step 3 - dmesg snapshot taken (count=${PRE_DMESG_COUNT})" + + # Launch modprobe asynchronously. `timeout` would normally cap + # this, but the panfrost probe on certain RK3326 clones blocks + # the modprobe process inside an uninterruptible kernel syscall + # (D state) — neither SIGTERM from `timeout` nor SIGKILL from a + # subsequent kill can release it. The script must never block + # waiting for modprobe; instead we poll for the platform bind to + # appear, give up after 30s, and let gpu_is_bound conclude with + # a failure that triggers the libmali fallback. + modprobe @PAN@ 2>/dev/null & + MODPROBE_PID=$! + log_event "panfrost: step 4 - modprobe launched pid=${MODPROBE_PID}" + + _iter=0 + for _wait in $(seq 1 30); do + _iter=$_wait + for g in /sys/bus/platform/drivers/panfrost/[a-f0-9]*.gpu; do + [ -e "$g" ] && break 2 + done + kill -0 ${MODPROBE_PID} 2>/dev/null || break + sleep 1 + done + log_event "panfrost: step 5 - poll loop exited at iter=${_iter}" + + if ls /sys/bus/platform/drivers/panfrost/[a-f0-9]*.gpu >/dev/null 2>&1; then + log_event "panfrost: step 6a - platform bind observed" + else + if kill -0 ${MODPROBE_PID} 2>/dev/null; then + log_event "panfrost: step 6b - modprobe still running, probe stuck" + else + log_event "panfrost: step 6c - modprobe exited without bind" + fi + fi + + # Drop the kernel messages emitted during the probe to the log so + # the failure mode is recoverable without a serial console. + log_event "panfrost: step 7 - capturing dmesg delta..." + dmesg 2>/dev/null | tail -n +$((PRE_DMESG_COUNT + 1)) | head -40 >>"${GPUDRIVER_LOG}" 2>/dev/null + log_event "panfrost: step 8 - dmesg captured" # Reverse every bind the libmali path did. Order matters: undo the # libEGL/libGLESv2/etc. binds from /usr/lib/mali first, then the @@ -167,7 +247,37 @@ case "$1" in "--start") get_current_driver log_event "boot: selected driver=${CONFDRIVER}" + + # Boot-loop protection. Some hardware variants kernel-panic on + # `modprobe panfrost` (observed on RK3326 clones), which the watchdog + # then resets — so the system never reaches gpu_is_bound to record + # the failure, and the next boot tries panfrost again, ad infinitum. + # We drop a sentinel on /storage before the modprobe and only clear + # it once we know the driver bound successfully. On the next boot + # we look for the sentinel: if present, the previous attempt with + # this driver crashed before recovery — silently force libmali and + # rewrite the setting so the user can pick again from a working UI. + SENTINEL="/storage/.config/gpudriver.attempting" + if [ -f "${SENTINEL}" ]; then + PREV="$(cat "${SENTINEL}" 2>/dev/null)" + log_event "previous boot crashed while loading ${PREV} — forcing libmali" + rm -f "${SENTINEL}" + if [ "${CONFDRIVER}" = "${PREV}" ] && [ "${PREV}" != "libmali" ]; then + CONFDRIVER="libmali" + set_setting ${GPU_DRIVER_SETTING_KEY} libmali + fi + fi + + # Use dd with oflag=sync so the sentinel is on the SD (not in page + # cache) BEFORE we touch the GPU driver. A subsequent kernel hang + # or watchdog reset would otherwise drop the sentinel and the boot + # after that would try panfrost again, looping. + echo "${CONFDRIVER}" | dd of="${SENTINEL}" oflag=sync 2>/dev/null + log_event "sentinel persisted: ${CONFDRIVER}" + + log_event "calling load_driver ${CONFDRIVER}" load_driver ${CONFDRIVER} + log_event "load_driver returned" # If the requested driver didn't actually bind, fall back to the # other one so the user gets a graphical system either way. Mali-G31 # on RK3326 is normally driven by libmali; if mali_kbase decides the @@ -182,17 +292,35 @@ case "$1" in load_driver "${ALT}" 2>/dev/null if gpu_is_bound "${ALT}"; then log_event "fallback to ${ALT} succeeded" + # Persist the working driver as the new default so the user is + # not asked to confirm again on next reboot. + set_setting ${GPU_DRIVER_SETTING_KEY} "${ALT}" else log_event "fallback to ${ALT} ALSO FAILED — system will run software-rendered" fi fi + + # Driver bound (or fallback ran). Clear the sentinel so the next boot + # does NOT think the current boot crashed. + rm -f "${SENTINEL}" 2>/dev/null + sync 2>/dev/null ;; "libmali") set_setting ${GPU_DRIVER_SETTING_KEY} $1 + # Force the setting onto disk before we return control to the UI, + # which may immediately trigger a reboot. + sync @DTB_OVERLAY_UNLOAD@ ;; "panfrost") set_setting ${GPU_DRIVER_SETTING_KEY} $1 + # Force the setting onto disk before we return control to the UI, + # which may immediately trigger a reboot ("Reboot now" in the popup + # is dispatched synchronously; ext4 might still have the new value + # in the page cache, not on the SD). Without this sync the next + # boot could still read gpu.driver=libmali and the user perceives + # the switch as silently broken. + sync @DTB_OVERLAY_LOAD@ ;; "") diff --git a/projects/ArchR/packages/graphics/mesa/package.mk b/projects/ArchR/packages/graphics/mesa/package.mk index 971182e440..099566e9f8 100644 --- a/projects/ArchR/packages/graphics/mesa/package.mk +++ b/projects/ArchR/packages/graphics/mesa/package.mk @@ -12,7 +12,7 @@ PKG_DEPENDS_TARGET="toolchain expat libdrm Mako:host pyyaml:host" PKG_LONGDESC="Mesa is a 3-D graphics library with an API." PKG_TOOLCHAIN="meson" PKG_PATCH_DIRS+=" ${DEVICE}" -PKG_VERSION="26.0.5" +PKG_VERSION="26.1.1" PKG_URL="https://gitlab.freedesktop.org/mesa/mesa/-/archive/mesa-${PKG_VERSION}/mesa-mesa-${PKG_VERSION}.tar.gz" if listcontains "${GRAPHIC_DRIVERS}" "panfrost"; then diff --git a/projects/ArchR/packages/virtual/emulators/package.mk b/projects/ArchR/packages/virtual/emulators/package.mk index c5e5a83151..d038df9671 100644 --- a/projects/ArchR/packages/virtual/emulators/package.mk +++ b/projects/ArchR/packages/virtual/emulators/package.mk @@ -1384,6 +1384,10 @@ makeinstall_target() { add_emu_core palm retroarch mu true add_es_system palm + ### GamePark GP32 + add_emu_core gp32 retroarch mame true + add_es_system gp32 + ### PC Ports case ${TARGET_ARCH} in aarch64|arm)