ARCH R

Referência técnica

Kernel, Mesa, U-Boot, DTS, pipeline de build

Pipeline de build

make docker-RK3326 executa todo o sistema de stages no estilo LibreELEC dentro do Docker. O build atual instala 543 pacotes na imagem.

toolchain    cross-gcc / glibc / binutils (stage do host)
linux        kernel 6.12 LTS + DTS do RK3326 + patches do ArchR
mali-bifrost mali_kbase out-of-tree + patch de PM unbalance do ArchR
mesa         Panfrost (GLES 3.1, +speed +lto)
zlib (-ng)   zlib-ng 2.2.4 em modo --zlib-compat (libz.so.1)
retroarch    1.x + conjunto de cores libretro
emulators    Flycast, PPSSPP, melonDS, DraStic, Yabasanshiro, Mupen64Plus standalone
es           EmulationStation (archr-linux/emulationstation-next)
image        FAT32 BOOT (256 MB) + ext4 ROOT (4608 MB) + ext4 STORAGE

Versões atuais: gcc 14.2.0, Linux 6.12.94, Mesa 26.1.3, systemd 255.8, U-Boot v2025.10, pacman 7.0.0.

Saída em target/<Ver of="imageBase" />-{original,clone}.img.gz.


Kernel

Source       Linux 6.12 LTS (kernel.org, patches do ArchR e da Rockchip)
Toolchain    gcc do stage de toolchain do ArchR
Config       projects/ArchR/devices/RK3326/linux/linux.aarch64.conf
HZ           300
PREEMPT      CONFIG_PREEMPT=y (A/B com PREEMPT_VOLUNTARY pendente de bench)
DEBUG        todos os sanitizers / KASAN / KMEMLEAK / FTRACE desligados no release
DEBUG_FS     y (intencional, necessário para debugfs do CMA e introspecção de PSI)
CMA          96 MB (subiu de 64 MB após auditoria; veja /docs/features)
ZRAM         lzo-rle por padrão (zstd opcional via memory-manager)
ZSWAP        desabilitado (zswap.enabled=0 na cmdline)

DTS

Origem: rk3326-gameconsole-r36s.dts (placa) + rk3326-gameconsole-r3xs.dtsi (família de placas) + px30.dtsi (SoC) + 000-rk3326-dts.patch (overrides do ArchR).

NóO que mudamosPor quê
cpu0_opp_tableAdicionada OPP turbo de 1512 MHz @ 1.4 V; mantida a escada completa 408–1416Acessível via "Enable CPU Overclock"
Regulador vdd_armregulator-max-microvolt 1.35 V → 1.45 VCaso contrário o kernel rejeita a OPP de 1512 silenciosamente
gpu_opp_tableRestauradas as OPPs inferiores de 200/300/400 MHz; adicionadas as superiores de 600/650 MHzOPPs baixas são necessárias para o boot; 650 MHz é o turbo diário a 1.150 V
dmc / dfiDefinidos explicitamente para que o devfreq possa ser controladoO px30.dtsi upstream os mantém desabilitados
gpuAdicionados clock-names="bus", resets, power_policy="coarse_demand", power_modelsNecessário para panfrost/mali_kbase modernos
Alias ethernet0AdicionadoNomeação futura para hot-plug de USB-Ethernet
Power modelmali-simple-power-model + mali-g31-power-modelDVFS com consciência térmica

Patches de kernel

Patches de kernel específicos do ArchR mais relevantes (projects/ArchR/packages/linux-drivers/mali-bifrost/patches/6.12-LTS/ e projects/ArchR/packages/linux/patches/6.12-LTS/):

  • mali-bifrost/002-fix-unbalanced-regulator-clk-pm.patch: elimina os avisos unbalanced disables for vdd_logic quando vdd_logic é compartilhado com rockchip-pm-domain. Adiciona um flag gpu_power_held que acompanha o estado de enable do próprio driver.
  • linux/0005-drm-panfrost-Add-SYSTEM_TIMESTAMP*.patch: requerido pelo Mesa atual para queries GL_TIMESTAMP e VK_KHR_calibrated_timestamps.
  • linux/0006-drm-panfrost-Add-cycle-counter-job-requirement.patch: encanamento para VK_KHR_shader_clock.
  • linux/0007-0010-drm-panfrost-Add-BO-labelling*.patch: auxílio de debug; o Mesa chama o novo IOCTL ainda que os labels sejam apenas para debug.

Mesa

Compilado com +speed +lto em packages/graphics/mesa/package.mk. Flags do configure:

-Dgallium-drivers=panfrost   -Dvulkan-drivers=
-Dgles1=disabled             -Dgles2=enabled
-Dglvnd=disabled             -Dplatforms=wl
-Dglx=disabled               -Dshader-cache=enabled
-Dopengl=true                -Dgbm=enabled
-Degl=enabled                -Dlibunwind=disabled
-Dbuild-tests=false          -Ddraw-use-llvm=false

-Dgallium-drivers=panfrost apenas, sem fallback de software no release (o overhead do LLVMpipe seria maior que o hardware no G31). -Dvulkan-drivers= vazio porque o PanVK não é conformante em Bifrost v9.

Variáveis de runtime

Exportadas globalmente em /etc/profile.d/041-panfrost:

PAN_MESA_DEBUG=forcepack             # dica de format-pack específica do G31
MESA_NO_ERROR=1
MESA_SHADER_CACHE_DIR=/storage/.cache/mesa_shader_cache
MESA_SHADER_CACHE_MAX_SIZE=128MB

Whitelist MESA_GLTHREAD=true por emulador, apenas Flycast e PPSSPP standalone (veja GPU driver e o docs/mesa-glthread-matrix.md no repo).


libmali (alternativo)

mali_kbase out-of-tree r52p0-00eac0 com o patch de PM do regulador/clk. Trocado no boot via /usr/bin/gpudriver --start, que lê /storage/.config/system/configs/system.cfg → gpu.driver. Fallback automático se algum dos drivers falhar em se ligar ao nó da GPU.


U-Boot

OriginalClone
Pacoteu-boot-legacyu-boot
Origemárvore BSP da Hardkernel (archr-linux/hardkernel-uboot)U-Boot mainline v2025.10, mais um patch para o clone K36 com eMMC
Defconfigarchr_rk3326_defconfigrk3326-handheld_defconfig
Seleção de placao hwrev no canal 0 do SARADC escolhe o DTB dentro de /dtbs/igual, através do boot.scr

As duas variantes trazem boot.scr e extlinux/extlinux.conf, e as duas carregam o overlay de painel a partir de FDTOVERLAYS /overlays/mipi-panel.dtbo. Os dois loaders não são intercambiáveis: um clone não dá boot com o build do BSP. O ArchR entrega os dois e o build escolhe pela variante (make docker-RK3326 produz as duas imagens).


Layout da imagem

MBR (msdos), 3 partições primárias, a primeira começa no setor 32768
├── 1   FAT32  ARCHR       256 MB    clusters de 16 KB, kernel, DTBs, overlays/, U-Boot
├── 2   ext4   ARCHR_ROOT  4608 MB   sistema, montado read-only em runtime
└── 3   ext4   STORAGE     resto     gravável: configs, ROMs, save states, screenshots

Os tamanhos das partições vêm de distributions/ArchR/options (BOOT_SIZE, ROOT_SIZE, SYSTEM_PART_START) e os rótulos de DISTRO_BOOTLABEL, DISTRO_ROOTLABEL e DISTRO_DISKLABEL. A terceira partição sai da fábrica com 32 MB e cresce para o resto do cartão no primeiro boot.

O mkimage formata a partição de boot com mkfs.vfat -F 32 -S 512 -s 32, ou seja, clusters de 16 KB, e depois confere com fsck.fat -n, só leitura. Nada no build nem no dispositivo repara esse filesystem automaticamente.


Fluxo de boot

0.0   POR / SPL (na ROM)
0.x   U-Boot lê SARADC ch0 → ID da placa
0.5   carrega DTB da placa + overlay do painel a partir de /flash/
0.7   splash do initramfs (BMP via xxd, /init estático em aarch64)
~7    entrega ao kernel
~9    target do systemd
~12   archr-autostart (quirks + governor + display + bluetooth + checagem de ssh)
~17   EmulationStation
~19   pronto para jogar

O trace é escrito em /storage/.boot_last_step antes de cada script de autostart rodar, e apagado em caso de sucesso. Se o boot anterior travou, o arquivo /storage/.boot_last_hang nomeia o script que travou. Inclua isso em relatos de bug.


Painéis de display

O ArchR não distribui overlays de painel prontos. São combinações demais de placa e painel para enumerar, então o overlay é montado por aparelho a partir do DTB do cartão original do próprio console.

A imagem carrega um diretório overlays/ vazio na partição de boot, com um README em seis idiomas apontando para o gerador (projects/ArchR/devices/RK3326/packages/u-boot/config/overlays/README.txt). O extlinux.conf carrega exatamente um arquivo de lá:

FDTOVERLAYS /overlays/mipi-panel.dtbo

O gerador existe em dois lugares, os dois rodando o mesmo archr_dtbo.py:

  • a versão no navegador em /overlay-generator, que roda o script sobre um runtime Python em WebAssembly
  • o archr-dtbo-offline.zip, o mesmo script como ferramenta de terminal, com a biblioteca fdt e os DTBs base junto

O aparelho também carrega uma cópia em /usr/libexec/generic-dsi/archr_dtbo.py, instalada pelo pacote generic-dsi.

A option string codifica o console e as flags da placa. Por exemplo: SDORIG para um R36S original, SDCLONE para um clone e SDORIG-NAm para uma placa Soysauce.


Armadilhas

Casos extremos que apareceram durante o desenvolvimento. Nenhum se aplica a uma gravação normal de release. Só importam se você está mexendo no build.

Contagens de cabeçalho de hunk em patches DTS importam. Uma contagem @@ -X,Y +A,B @@ errada faz o patch abortar silenciosamente o resto dos hunks, deixando "lixo" recuperado. Valide com patch --dry-run --verbose sobre uma fonte limpa após cada edição de DTS.

OPPs de turbo-mode se escondem atrás de cpufreq/boost. Setar scaling_max_freq=1512000 diretamente não faz nada se boost=0. A frequência não aparece em scaling_available_frequencies até você escrever 1 em cpufreq/boost. O set_cpu_max_freq highest do ArchR lê tanto scaling_available_frequencies quanto scaling_boost_frequencies.

O regulator-max do vdd_arm controla a disponibilidade de OPPs silenciosamente. Se uma OPP solicita uma tensão acima de regulator-max-microvolt, o kernel descarta a OPP sem nada no dmesg, e policy_has_boost_freq() retorna false → o sysfs cpufreq/boost nunca é criado.

Os avisos de FAT depois de um resize são esperados. O fs-resize roda fatlabel -i -r para dar um ID de volume novo à partição de boot, e o fatlabel reclama duas vezes no processo: a contagem de clusters está abaixo do mínimo do FAT32 e o setor de boot primário difere do backup. Os dois são de propósito. A partição de boot de 256 MB usa a mesma geometria FAT32 fora da spec que o resto do ecossistema RK3326, porque os U-Boots dos fabricantes só são testados contra essa geometria, e a diferença no setor de boot é a flag de dirty do vfat do kernel, escrita só no setor primário enquanto /flash está montado para escrita. O fs-resize escreve essa mesma nota em /flash/fs-resize.log.

Não "conserte" o filesystem de boot com fsck.fat -a -w. Reescrever a geometria para algo dentro da spec é justamente o que quebra o boot nos loaders dos fabricantes. Tanto o mkimage quanto o lado do dispositivo conferem o filesystem só em leitura, com fsck.fat -n.

O diretório raiz do shader cache do Mesa precisa existir. O Mesa não vai fazer mkdir em MESA_SHADER_CACHE_DIR por conta própria; apenas cai silenciosamente para modo sem cache. O runemu.sh cria /storage/.cache/mesa_shader_cache se estiver faltando.

panfrost_devfreq precisa de OPPs baixas de GPU para inicializar. Remover as OPPs de 200/300/400 MHz (para forçar um piso mais alto) bloqueia a inicialização da GPU no boot. O driver espera que a menor OPP publicada seja alcançável. Mantenha a escada; force um piso alto em runtime com set_gpu_min_freq highest.

PREEMPT vs PREEMPT_VOLUNTARY ainda não foi bencheado. A configuração do kernel define CONFIG_PREEMPT=y. Se o PREEMPT_VOLUNTARY se sairia melhor no A35 é uma questão em aberto, à espera de um A/B com o bench no dispositivo.

O unbalance do regulador no mali_kbase é um patch de kernel, não um quirk. Sem o 002-fix-unbalanced-regulator-clk-pm.patch, cada transição de PM emite unbalanced disables for vdd_logic e Enabling unprepared clk_gpu, audível como estalo no Mario 64.

On this page