The night started with a sudo reboot to test a one-line rc.conf change. The phone never came back. After ~12 hours of debugging — three different kernels, every level of cache flushed, two complete SD reflashes — it turned out the SD slot or the SD card itself was the variable. Migrating FreeBSD to the phone’s internal eMMC made everything work again, and we wound up rebuilding the full desktop environment on top of the Apr-8 baseline image. By the end we had a one-command install path so the next migration can’t burn another night.
Tested the WiFi-DHCP rc.conf fix from 4e6ffe4 overlay/rc.conf: switch wlan0 to background DHCP with a sudo reboot. Phone went silent. U-Boot reached the FreeBSD loader’s “Autoboot in 1 seconds” prompt every time, then the kernel handoff produced no display output and SSH never came up.
Ruled out, in order:
- Stale
linker.hintsand modules — fullmake installkernel DESTDIR=/mntrebuild produced 723 fresh modules with matching SHAs, no help. - The
rk_power_domaindriver from227e58brk_power_domain: sysctl-only RK3399 PMU power-domain controller — disabled it and rebuilt; same hang. console="comconsole,efi"interaction with the CRU hack — switched toconsole="efi"only, same hang on screen.- Filesystem corruption —
fsckon the SD reported clean; UFS clean flag was set after unmount. rc.confcontent — the only userspace change between “boot worked” and “boot didn’t work” was the WiFi DHCP one-liner; not load-bearing for the kernel.
Same kernel binary that booted at 04:43 ran for 5 hours, was sudo reboot’d, never booted again. Same disk content, two binaries, neither boots from this SD post-shutdown.
The dd if=/dev/da1 ... | gzip forensic backup of the bad SD landed at forensics/sd-2026-05-03-stuck.img.gz (32 GB compressed of 60 GB raw) before any further attempts.
Per-the-handoff: ruled the phone fine by booting postmarketOS from the eMMC. Linux came up immediately. Phone hardware is healthy; SD card or slot is the variable.
Decision: migrate FreeBSD to the eMMC. dd-of-e (unknown commit) isn’t a thing — this is all dd work outside the repo:
- Backed up the eMMC’s pmOS install:
sudo dd if=/dev/sde of=forensics/emmc-pmos-2026-05-03.img bs=4M— 123 GB raw, 3.3 hours over USB. (The first attempt with| gzip -1got OOM-killed because gzip + 4M block size buffered too much; uncompressedddworked fine.) - Wrote
freebsd-ppp.img(the Apr-8 baseline, 26 GB) onto/dev/sde. eMMC GPT showed[CORRUPT]because the image’s secondary GPT lives at sector 26 GB but the eMMC is 115 GB;gpart recoveron first boot fixes it. - Pulled the SD card out of the phone so U-Boot’s SD-first boot order would fall through to eMMC.
- Phone booted FreeBSD from eMMC immediately on first try.
That alone would have been the win for the night. The phone hadn’t booted from SD all night; eMMC worked first try.
The Apr-8 baseline image is #0 from 2026-04-08 23:37. Our session work — magnetometer reset-gpio, rk_tsadc trim, sgm3140 dtbo, fusb302 prepared-sink contract — needed to be re-layered. Did it incrementally:
- Deploy our
#145kernel (shaa69a60918d…, nork_power_domain) viaKERNEL_DEPLOY_REBOOT=1 mise run kernel:deploy:phone. First deploy didn’t take because of atee+ immediatesudo rebootrace — a manualsyncbefore the reboot fixed it. (Filed as a deploy-script TODO; the script’smvfollowed byrebootdoesn’t fsync.) - Push our dtb + sgm3140 dtbo via
cat | sudo tee— 32bf3535… for the dtb, sgm3140 overlay 0x747 bytes. - Update
/boot/loader.confwithfdt_overlays="sgm3140"(droppedbcm-hostwakesince the dtbo isn’t built; cosmetic for now) and the then-currenthw.rk_tsadc.trim_offset_mc=-30000workaround. That trim line was removed on 2026-05-05 after the TSADC q-select fix. - Push
bwfm_sdio.komatching our kernel viamise run module:deploy:phone bwfm_sdio. rsyncthe overlay tree —/boot/firmware/brcm/*(WiFi/BT firmware),/usr/local/sbin/bt_*(Bluetooth scripts),/usr/local/etc/rc.d/bwfm_sdio(rc.d hook).- Reboot.
Verified live: dev.rk_tsadc.0.cpu_temp: 31875 (sensible), dev.magnetometer.0.chip_variant: af8133j, dev.fusb302.0.vbus_present: 1, /dev/led/flash and /dev/led/torch both present.
Apr-8 image had Sway + xorg + 576 packages but no Hyprland, no firefox, no svkbd, no omfreebdy theme stack. Cloned omfreebdy onto the phone via rsync from MediaVolume and ran OMFREEBDY_PROFILE=wayland ./install.sh.
Hit a chain of papercuts:
/etc/resolv.confwas a dangling symlink to/tmp/bsdinstall_etc/resolv.conf(left over frombsdinstall).pkg updatefailedName could not be resolved. Fixed:rm+ write a real file withnameserver 1.1.1.1.pkg+https://pkg.FreeBSD.org/FreeBSD:15:aarch64/kmods_latestdoesn’t exist as a SRV mirror.pkg updateerrored on theFreeBSD-ports-kmodsrepo. Fixed: dropped a/usr/local/etc/pkg/repos/no-kmods.confdisabling that repo.miseisn’t in FreeBSD pkg. omfreebdy’siso/packages/base.txtlists it;pkg install -yaborts the whole transaction on the unresolvable name. Fixed: filteredmiseout of the package list at install time.- First pkg install hung mid-way with
pkg install -y libreofficerunning and another pkg holding the database lock from a SIGKILL’d parent ssh session.kill -9on the orphan, retry, ~99 packages installed (1149 total). install.shaborted in the middle of optional builds becausecliampGo build needslibrespot/flacwhich has no FreeBSD-tagged source files. Worked around by sourcinginstall.shwithOMFREEBDY_SOURCED=1and running the post-package phases manually (setup_repo,setup_directories,install_configs, etc.).
After that: ~/.config/{hypr,foot,fuzzel,ghostty,mako,omfreebdy,picom,rofi,starship.toml,...} all in place, sudoers configs (omfreebdy-phone, omfreebdy-wifi, wheel), services enabled (dbus, seatd, avahi, powerd, bwfm_sdio).
omfreebdy’s pkg list doesn’t include the suckless / sourcehut things the phone Sway env needs:
svkbd — built from https://dl.suckless.org/tools/svkbd-0.4.2.tar.gz. Quirks:
fetchfailed cert verification ondl.suckless.org; switched tocurl -kL.- FreeBSD’s mini-memstick image lacks
libgcc.aandlibc_nonshared.a; built empty stubs viaclang -c /dev/null+llvm-ar rcs. config.mkpaths needed/usr/X11R6→/usr/local.- Missing
-lfontconfig -lfreetypeon the link line; added withsed. - Built with
PATH=/usr/local/llvm19/bin:$PATH CPPFLAGS=-I/usr/local/include/freetype2 make CC=clang LAYOUT=mobile-intl.
lisgd — gesture daemon for swipe-to-show-keyboard. Quirks:
git.sr.ht/~mil/lisgd/archive/v0.4.0.tar.gzreturns HTML (1.5 KB). The right URL isarchive/0.4.0.tar.gz(novprefix); that returns the actual gzip archive.master.tar.gzworks too but has Linux-only deps not in 0.4.0.- Source uses
<sys/prctl.h>andCLOCK_MONOTONIC_RAW, neither on FreeBSD. Patched: stub outprctl(PR_SET_PDEATHSIG, ...),s/CLOCK_MONOTONIC_RAW/CLOCK_MONOTONIC/g. - Makefile uses GNU
ifndef/endif; FreeBSDbmakerejects it. Build withgmake.
End state: /usr/local/bin/{sway,svkbd-mobile-intl,lisgd,Hyprland,foot,fuzzel,waybar,mako,starship,...} all present. ~/bin/start-sway script for launching the phone-flavoured sway env.
After full install + reboot, phone could ping but not ssh. Confirmed via the serial console (printf 'root\n' > /dev/ttyUSB1, then commands) — sshd was running, listening on *:22, but every TCP SYN dropped before reaching it.
Found pf enabled with the Apr-8 baseline pf.conf:
pass out all flags S/SA keep state
block drop in all
pass in inet proto icmp all keep state
pass in quick on egress proto tcp all flags A/A keep stateue0 (USB-Ethernet) isn’t in the egress group, so nothing matched. ICMP had its own rule, hence ping working. Disabled pf (sysrc pf_enable=NO).
Also caught the CRU BLOCKED write infinite loop on warm reboot. powerd was making PLL writes that our rk_cru_write_allowed() filter blocks unconditionally for addresses < 0x100, then retrying forever. Disabled powerd (sysrc powerd_enable=NO). Warm reboot now completes in ~30 s without any spam.
Both of these landed in the omfreebdy “phone” profile — see below.
Codified all the night’s quirks as OMFREEBDY_PROFILE=phone in the omfreebdy repo (ab825a8):
iso/packages/phone.txt—llvm19,gmake,pkgconf,libXft,libXinerama,libinput,freetype2,fontconfig. Pulled in alongsidebase.txt+wayland.txt.phone_preflight()— replaces dangling/etc/resolv.conf, dropsno-kmods.confto disable the brokenFreeBSD-ports-kmodsrepo. Idempotent.install_packagesmise filter — stripsmisefrom the package list at install time (chosen over editingbase.txtso non-phone profiles aren’t affected).phone_build_native()— creates/usr/lib/{libgcc,libc_nonshared}.astubs, fetches and buildssvkbd-mobile-intl(with all the sed patches), fetches and buildslisgd(withprctlandCLOCK_MONOTONIC_RAWpatches). All steps skip cleanly if the binary already exists.enable_servicesoverrides for phone —pf_enable=NO(ue0 isn’t in egress),powerd_enable=NO(CRU filter incompatibility, see below).
Next migration (to a fresh PinePhone Pro from baseline) is now OMFREEBDY_PROFILE=phone ./install.sh. None of tonight’s papercuts re-bite.
Reboot loop on eMMC is stable with powerd off:
uname -a→ kernel#145froma69a60918d…(post-rk_power_domain-disable kernel)uptimeshows clean 1-minute boot to multi-userdev.rk_tsadc.0.cpu_temp: 36666(idle, trim applied)- ssh, getty on serial, all userland services — all work
- WiFi firmware still doesn’t load post-eMMC-flash (
fn2 I/O ready timeout, same blob bytes that worked yesterday on SD); separate investigation - The CRU filter’s coarseness is now the gating issue for re-enabling powerd / panfrost cpufreq — design plan in project_cru_granular_whitelist_plan (next session)
Forensic artifacts retained:
forensics/sd-2026-05-03-stuck.img.gz— 32 GB compressed dump of the SD that wouldn’t boot from any kernel after the warm reboot.forensics/emmc-pmos-2026-05-03.img— 123 GB raw dump of the postmarketOS install before we wrote FreeBSD over it.
Three follow-ups in the afternoon pulled the open list down by three.
WiFi: fn2 enable timeout — 4f93cc4 bwfm: extend fn2-enable timeout to 5 s, log mbdata on timeout
The fn2 I/O ready timeout, IOR=0x02 message was the visible failure
since the eMMC migration. The morning’s hypothesis ranking blamed the
chip (sticky pmOS firmware state, missing clk32k, NVRAM mismatch). A
debug.bwfm_dump_state=1 dump told a different story:
state[sysctl]: clk=AVAIL fn2=0 init=0 sr=0 tx_seq=0 tx_max=0 credits=0
txq=0 last_int=0x00800000 mb=0x00040002 host=0x00040002Decoding mb and host (both reads of SDPCMD_TOHOSTMAILBOXDATA):
- bit 1 (
SDPCMD_TOHOSTMAILBOXDATA_DEVREADY) = 1 → firmware booted and announced ready - upper 16 bits =
0x0004→ SDPCM protocol version 4 (matches ourSDPCM_PROT_VERSION)
So the chip was alive and on protocol — the failure was downstream.
The loop in bwfm_sdio.c:2266 waits 500 ms for IOR.fn2 to come up
after the host writes IOE |= 0x04. Linux’s brcmf_sdio_bus_init
waits up to 5 s. On a cold boot from eMMC the chip’s fn2 fabric
routinely takes >500 ms, so the host gives up, prints PROCEEDING anyway, and every later fn2 transaction times out. 4f93cc4 bwfm: extend fn2-enable timeout to 5 s, log mbdata on timeout raises the cap to 5 s and adds a device_printf of
mbdata + intstatus on timeout so the next regression doesn’t need
the sysctl tour. Post-fix:
bwfm_sdio0: CLM version: API: 12.2
wlan0: Ethernet address: 90:e8:68:72:f8:df
state[sysctl]: clk=AVAIL fn2=1 init=1 sr=0 tx_seq=37 tx_max=77 credits=40wpa_supplicant associates to a WPA2 AP, DHCP returns 192.168.1.142,
ping 1.1.1.1 is 24 ms. Sustained throughput is still gated by
SDIO function-1 IRQ delivery — irqmode=irq-armed-poll-fallback,
~40 KB/s on a 5.7 MiB pull — but that’s a separate thread, tracked
under component-bcm43455.
rk_cru per-PLL whitelist — 13e94af rk_cru: per-PLL whitelist for RK3399 PLL register window
Coarse addr < 0x100 → block retired in favor of per-PLL windows:
| Offset | PLL | Allow? |
|---|---|---|
0x00-0x17 | LPLL (CRU) / PPLL (PMUCRU) | yes |
0x20-0x37 | BPLL | yes |
0x40-0x57 | DPLL | NO |
0x60-0x77 | CPLL | NO |
0x80-0x97 | GPLL | yes |
0xA0-0xB7 | NPLL | yes |
0xC0-0xD7 | VPLL | NO |
vop_lit_dclk_src muxes between VPLL and CPLL, so both stay frozen;
DPLL is DRAM, never touch. Everything else is writable.
Verified live on kernel #150:
$ sysctl dev.cpu.0.freq_levels
dev.cpu.0.freq_levels: 1416/-1 1200/-1 1008/-1 816/-1 600/-1 408/-1
$ sudo sysctl dev.cpu.0.freq=1416
dev.cpu.0.freq: 600 -> 1416
$ sudo service powerd onestart
$ sysctl dev.cpu.0.freq dev.cpu.4.freq
dev.cpu.0.freq: 1008
dev.cpu.4.freq: 1008No BLOCKED write lines after the freq change. Both clusters scale
together under load. Init-time CPLL writes at 0x60-0x6c (from
rk3399_cru’s clock-graph init for display rates) still log as
blocked during boot, which is intentional.
powerd back on by default
overlay/etc/rc.conf now ships powerd_enable="YES" and
powerd_flags="-a adaptive". Phone profile in the omfreebdy repo
will follow on the next install pass. Detail in
component-rk-cru.
The eMMC migration left sway unable to launch with WLR_BACKENDS=drm,libinput. wlroots’ first call into Mesa, eglQueryDevicesEXT(0, NULL, &num_devices), returned EGL_BAD_PARAMETER: "Missing num_devices pointer". Pixman fallback worked but the screenshot was a 720x1440 black PNG.
Tracing the EGL failure
Tried env permutations: MESA_LOADER_DRIVER_OVERRIDE=panfrost, WLR_DRM_DEVICES=/dev/dri/card0, EGL_PLATFORM=gbm, LD_PRELOAD=libEGL_mesa.so.0. None changed the error. Set MESA_LOADER_DEBUG=1 and the loader-side reported “MESA-LOADER: failed to retrieve device information” — Mesa was receiving 0 devices from libdrm.
Wrote a tiny test program:
#include <xf86drm.h>
int main() {
drmDevicePtr devs[16];
int n = drmGetDevices2(0, devs, 16);
printf("drmGetDevices2 returned %d\n", n);
return 0;
}drmGetDevices2 returned 0. So the kernel-side hw.dri.N.busid /
hw.dri.N.name sysctls (already set up by drm_sysctl_init() in our
overlay) were correct, but libdrm wasn’t reading them.
The libdrm patch was already in tree, just not deployed
ports/graphics/libdrm/files/patch-xf86drm.c (pinned in b3c2366 DRM sysctl + libdrm platform device support ) has three hunks:
drmParseSubsystemType— returnDRM_BUS_PLATFORMif busid begins withplatform:drmParseOFBusInfo— copy the part afterplatform:into the device’s fullnamedrmParseOFDeviceInfo— readhw.dri.N.name, strip trailing hex ("rockchip 0x7a"→"rockchip"), use as compatible string
Honor’s poudriere had a built aarch64-default pkg from 2026-04-06 that contained only the first two hunks — the third (the hw.dri.%d.name lookup) was missing from the deployed binary. Confirmed:
$ strings /usr/local/poudriere/data/packages/aarch64-default/.latest/All/libdrm-2.4.131,1.pkg | grep hw.dri
hw.dri.%d.modesetting
hw.dri.%d.busid
# (no hw.dri.%d.name — third hunk missing)Honor also has a manual cross-compile setup at /tmp/libdrm-build/ (meson + clang -target aarch64-unknown-freebsd15.0 against the poudriere jail’s sysroot). The binary it produces does have all three hunks. So the source tree was current, the deployed pkg was just stale.
Repackaging the aarch64 pkg without poudriere bulk
Honor doesn’t have qemu-user-static set up, so poudriere bulk -j aarch64 graphics/libdrm fails. Workaround:
# On honor
cd /tmp && rm -rf libdrm-aarch64-pkg && mkdir libdrm-aarch64-pkg && cd libdrm-aarch64-pkg
tar xf /usr/local/poudriere/data/packages/aarch64-default/.latest/All/libdrm-2.4.131,1.pkg
cp /tmp/libdrm-build/libdrm-2.4.131/build/libdrm.so.2.131.0 usr/local/lib/
strip usr/local/lib/libdrm.so.2.131.0
pkg create -M +MANIFEST -r . -o /tmp/
sudo cp /tmp/libdrm-2.4.131,1.pkg /usr/local/poudriere/data/packages/aarch64-default/.latest/All/
# Pipe to phone (file-based; pkg install would name-resolve and pull
# the OLD pkg from FreeBSD-ports)
cat .../libdrm-2.4.131,1.pkg | ssh pinephone 'cat > /tmp/libdrm.pkg && sudo pkg add -f /tmp/libdrm.pkg'Post-deploy:
$ strings /usr/local/lib/libdrm.so.2 | grep -E 'hw\.dri|platform:'
hw.dri.%d.busid
platform:
hw.dri.%d.name
hw.dri.%d.modesetting
$ /tmp/drm_test
drmGetDevices2 returned 2
dev 0: bustype=2 fullname=rk_drm0
node[0]: /dev/dri/card0
node[2]: /dev/dri/renderD128
dev 1: bustype=2 fullname=panfrost0
node[0]: /dev/dri/card1Sway launches but the panel stays black
With Mesa happy, sway launches with full GPU env, no EGL errors, swaybg + swaybar + sway running, DSI-1 active per swaymsg -t get_outputs at 720x1440 @60 Hz. Plane atomic_update fires with correct dst/src rects (verified by temporary device_printf instrumentation in rk_plane.c):
rk_vop0: plane_atomic_update: dst=(0,0)-(720,1440) 720x1440 src=(0,0)-(720,1440) 720x1440
rk_vop0: plane_atomic_update: writing YRGB_MST id=0 paddr=0xca800000 pitch=2880VOP registers post-commit are programmed correctly:
WIN0_CTRL0 = 0x3a0000a1 (EN bit set)
WIN0_VIR = 0x000002d0 (pitch = 720 words ✓)
WIN0_YRGB_MST = 0xca800000 (sway's framebuffer ✓)
WIN0_ACT_INFO = 0x059f02cf (720x1440 ✓)
WIN0_DSP_INFO = 0x059f02cf (720x1440 ✓)
WIN0_DSP_ST = 0x000e0056 (display start position ✓)But the screen remains black. Two specific signals say VOP isn’t actively scanning:
VOP_STATUS @0x2a4changes only once in 50,000 reads — the line counter isn’t advancing at frame rateDSI PHY_STATUS @0xb0 = 0x1529— all four data lanes instopstate, no high-speed video transmission
And every sway-allocated GBM buffer reads as zeros from /dev/mem:
$ /tmp/fb_read 0xca800000
addr=0xca800000 nonzero=0 (0/16384 words)Three live hypotheses:
- VOP DCLK is gated. Some interaction with the new CRU per-PLL whitelist, or a
clk_disablesomewhere in the atomic helpers, leaves VOP without a pixel clock. Without DCLK, VOP stops scanning, DSI lanes drop to stopstate. - dma_buf cache coherency. Panfrost renders to GBM buffers via CPU mappings; data lives in CPU caches. VOP DMA reads from physical DRAM and gets zeros. Need WC mappings or explicit
cpu_dcache_wbinv_rangeon PRIME export. - DSI panel state. Some sway commit path reset HX8394 without re-running its init sequence; panel is in low-power / display-off state.
Diagnostic plan for next session:
clk_get_freqondclk_vop1before/after sway commits — distinguishes (1) from (2/3).- Kill sway, manually reset VOP MST to U-Boot’s framebuffer address, see whether the kernel boot output reappears — distinguishes (3) from (1/2).
- Add explicit cache flush on PRIME-imported buffer attach, see whether sway content lands on screen — confirms (2).
The first continuation test was a diagnostic kernel from d7bd9b5 drm: instrument panfrost scanout imports . It added Panfrost allocation counters and a Rockchip PRIME-import log that reports when an imported dma-buf is not physically contiguous.
On kernel #153, Sway came up with the GPU path active and the diagnostic counters were clean:
dev.panfrost.0.counters:
gem_alloc_contig=18
gem_alloc_scattered=0
gem_alloc_contig_fail=0There were no rockchip_gem_prime_import_sg_table: non-contiguous PRIME import lines in dmesg. That falsifies the neat theory that Panfrost was exporting scattered pages while VOP scanned only the first physical page. The imported scanout buffers are contiguous on this boot.
The phone then reproduced the known DRM atomic wedge. The screen showed the kernel console and the familiar cascade:
WARNING !list_empty(&lock->head) failed at .../drm_modeset_lock.c:268
WARNING drm_modeset_is_locked(&crtc->mutex) failed at .../drm_atomic_helper.c:617
WARNING drm_modeset_is_locked(&dev->mode_config.connection_mutex) failed at .../drm_atomic_helper.c:667
WARNING drm_modeset_is_locked(&plane->mutex) failed at .../drm_atomic_helper.c:892
[drm] ERROR [CRTC:33:crtc-0] hw_done timed out
[drm] ERROR [CRTC:33:crtc-0] flip_done timed out
[drm] ERROR [CONNECTOR:35:DSI-1] hw_done timed out
[drm] ERROR [PLANE:31:plane-0] hw_done timed outThat moves the next fix back to the atomic commit path, not the GBM import path. a830a08 rk_vop: restore atomic vblank wait makes the local overlay match two pieces of the cross-driver audit: rk_drm_atomic_commit_tail() waits for vblanks before cleanup_planes, and rk_vop_intr() clears only the interrupt status bits it actually observed instead of writing ~0 to INTR_CLEAR0.
The driver-side event latch described in the audit is still open; the site previously implied it was already in tree, which was wrong.
Kernel #154 from a830a08 rk_vop: restore atomic vblank wait deployed cleanly to the phone:
phone 472f3624035a2a56c2bf3c15dba3c26ebfe63fc4f930856a6a0a1f7582c128f8 pinephone:/boot/kernel/kernelAfter boot, Sway still blanked the panel, but the failure shape changed from the photographed atomic wedge. There were no hw_done timed out or flip_done timed out messages. Instead, Sway was alive, asleep in select, holding /dev/dri/card0 and /dev/dri/renderD128, with an IPC socket under /var/run/xdg/jadams/, while the panel stayed black.
The serial console proved the machine was not hard-wedged. Killing the Sway session restored visible console output, so the immediate usability problem was the ttyv1 autostart path:
# /home/jadams/.profile on the phone
if [ ! -e "$HOME/.disable-autosway" ] && [ -z "$WAYLAND_DISPLAY" ] && [ "$(tty)" = "/dev/ttyv1" ]; then
exec ~/bin/start-sway
fiFor now /home/jadams/.disable-autosway exists on the phone, so rebooting lands at a serial/video console instead of relaunching Sway into a black screen. Remove that file, or run ~/bin/start-sway manually, only when testing the compositor path.
The remaining kernel-side signal on a console-only boot is:
WARNING cur_vblank != vblank->last failed at /usr/src/sys/dev/drm/core/drm_vblank.c:348That keeps the next display work focused on VOP vblank/event accounting rather than PRIME-import contiguity.
Kernel #157 from aced94d rk_vop: use crtc drm device for event lock fixed the VOP event-lock panic and brought Sway back on the eMMC install: DSI-1 active at 720×1440, Panfrost scanout buffers contiguous, no hw_done / flip_done timeout cascade, and VOP latch counters idle. The remaining breakage was userland drift from the old SD image.
The old SD card had ~/.local/bin/start-lisgd-sway.sh as a symlink to the restartable start-lisgd-sway wrapper. The eMMC overlay only had the older .sh script, hard-coded /dev/input/event2, discarded logs, and called /home/jadams/omfreebdy/bin/omfreebdy-menu, which does not exist on the eMMC install. The overlay now carries both names: start-lisgd-sway.sh forwards to start-lisgd-sway, and the real launcher repairs SWAYSOCK, XDG_RUNTIME_DIR, and WAYLAND_DISPLAY from /tmp/runtime-jadams/sway-ipc.*.sock when restarted over SSH.
Two more “already solved” phone UI details were restored:
-
7baa2ccports: add fuzzel 1.14.1 port (fixes touch tap coordinate scaling bug #686) was the fuzzel tap fix. The eMMC image hadfuzzel 1.13.1; the old solved state neededfuzzel 1.14.1for the touch tap coordinate scaling fix. Built 1.14.1 on the phone from the verified Codeberg distfile and installed/usr/local/bin/fuzzel(SHA256 = 7e45a0957fe34f27c4ba3e59bc90f28521c489ee843e5d98a6819cdb01403573).scripts/build-fuzzel-touch.shrecords the no-network build path so the omfreebdy phone profile can call it instead of rediscovering the version pin. -
e6f5455overlay: use solid color swaybg (gdk-pixbuf2 broken on aarch64) pointed at the right layer but the final cause was sharper: image-backedswaybg -i current-backgroundfailed because the eMMC image had gdk-pixbuf JPEG/PNG loaders installed but no/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache. Regenerating that cache made the same JPEG work.theme-setandpost-theme-setnow use image-backedswaybgwhen the cache exists and fall back toswaybg -c "$background" -m solid_coloronly when it does not.
Theme switching also needed explicit post-reload process repair. Sway reload does not reliably preserve a visible bar, and exec_always lisgd restarts race with the old daemon while layer-shell clients churn. The phone hook now daemonizes swaybg, replaces swaybar -b bar-0, and restarts start-lisgd-sway after every theme change. theme-set also registers that hook as an EXIT / signal trap as soon as the requested theme is validated, so killing theme-set halfway through no longer leaves the phone without gestures, bar, or background. Verified live by sending TERM after the GTK phase:
swaybg -i /home/jadams/.config/omfreebdy/current-background -m fill
swaybar -b bar-0
lisgd -d /dev/input/event2 -w 720 -h 1440 -m 400 ...
/bin/sh /home/jadams/.local/bin/swaybar-statusThe executable diff against the old SD userland was small: eMMC was missing only phone-system-menu.sh and start-lisgd-hyprland.sh from the old-SD ~/.local/bin set. Both are back in the overlay and deployed live.
May 5 follow-up: the apparent “missing apps” in fuzzel was not a package install failure. nautilus-47.6_1 was installed and /usr/local/share/applications/org.gnome.Nautilus.desktop existed; fuzzel was just cramped enough that the app list looked truncated, and the phone launch environment did not consistently carry FreeBSD’s XDG data paths. The overlay now exports XDG_DATA_DIRS=$HOME/.local/share:/usr/local/share:/usr/share from ~/.profile, ~/bin/start-sway, Sway’s $menu, and the lisgd-spawned app launcher paths. The fuzzel phone geometry is now width=34, lines=12, font size=14, and fields=name,generic,comment,categories,filename,keywords, so “Files” is visible and nautilus can match via org.gnome.Nautilus.desktop while still leaving side gutters for edge gestures.
One more sharp edge: the failed theme switch was not a DRM regression. theme-set and post-theme-set were calling bare daemon; when the phone PATH omitted /usr/sbin, the repair hook printed daemon: not found and never restarted swaybg, swaybar, or lisgd. The hook now prepends /usr/local/sbin:/usr/sbin:/sbin, stores DAEMON=/usr/sbin/daemon, and theme-set uses /usr/sbin/daemon directly for swaybg.
Final May 5 cleanup: full-width fuzzel blocked the right-edge close gesture, so the phone geometry was backed off from width=42 to width=34. lisgd also exposed one more parser trap: the restart wrapper was embedding DBUS_SESSION_BUS_ADDRESS=unix:path=...,guid=... inside each -g action string. lisgd uses commas as field separators, so the dbus address split the action and /bin/sh reported Syntax error: end of file unexpected (expecting "}"). The wrapper now lets lisgd inherit the dbus address at process level and only passes comma-free Wayland/Sway/XDG variables inside the action strings.
Open work after this session
- Sway phone userland packaging — the live eMMC install is repaired, but omfreebdy’s phone profile needs to absorb
fuzzel 1.14.1, the restartable lisgd launcher, the daemonized post-theme hook, XDG app-data exports, and the dbus-safe lisgd gesture strings so a fresh install gets the same behavior. rk_spiCTRLR1 refactor — pre-existing JEDEC RDID skew on the boot SPI flash; triedbef5863rk_spi: write CTRLR1 frame count before enable_chip , harmless but ineffective; reverted inc593dc3Revert "rk_spi: write CTRLR1 frame count before enable_chip" .- SDIO function-1 IRQ delivery — bwfm runs entirely on the 100 Hz poll fallback. ~40 KB/s ceiling. Bench predicate is
dev.rockchip_dwmmc.0.sdio_intrs > 0. Separate from today’s fn2 fix. rk_power_domainframework — replace the sysctl-only first cut withpwr_domain_if.m+ simplebus property parsing so peer drivers can request domains via DT.- VOP event/vblank parity — the driver-side event latch from
aced94drk_vop: use crtc drm device for event lock stops the modeset wedge, but kernel#157still tripscur_vblank != vblank->lastonce during Sway startup. - renderD128 wrong device assignment — libdrm’s
id -= 128for renderD128 maps tohw.dri.0(rk_drm0), not panfrost0. Cosmetic for sway but breaksavailable_nodesenumeration. Open.