Bringing Up the PowerVR SGX544 MP2 GPU on Mainline Linux 7.2 (Allwinner A31s)
When I brought up Mainline Linux 7.2 and Alpine Linux 3.20 on the Exper Easypad 8 (Model T8E) tablet (Allwinner A31s / sun6i), nearly every major subsystem worked through upstream drivers: sun4i-drm drove the 1024×768 LVDS panel and 1080p60 HDMI out, cedrus handled hardware VP8/H.264 video decoding, and brcmfmac + goodix handled Wi-Fi and capacitive touch.
The one glaring gap was 3D graphics. The Allwinner A31s integrates a dual-core Imagination PowerVR SGX544 MP2 (Revision 1.1.5, mapped at 0x01c40000, IRQ SPI 97, powered by AXP221 dcdc2 at 1.2 V). While mainline Linux has the Device Tree binding (allwinner,sun6i-a31-gpu), there is no upstream DRM/Mesa shader driver for SGX544 MP2.
This post documents how I debugged the early register bus lockups on the A31s, sequenced the SoC power/clock domains, ported the pvrsrvkm (DDK 1.17) kernel module to Mainline Linux 7.2, and brought up hardware-accelerated DRM/KMS GLES2 (glmark2 score 211) and Weston 10 Wayland.
1. The First Trap: Why Reading Offset 0x0020 Hangs the System Bus
On single-core PowerVR SGX530/SGX540 GPUs, the core revision register (EUR_CR_CORE_REVISION) sits at offset 0x0014 or 0x0020 from the base MMIO address (0x01c40000).
When I first powered up dcdc2, ungated the GPU clocks, and tried to read 0x01c40020, the entire tablet froze hard—no kernel panic, no serial output, just an immediate AXI/AHB bus lockup requiring a hard PMIC reset.
Broadcast Bank vs. MP Master Bank Layout
The SGX544 in the Allwinner A31/A31s is an MP2 (Multi-Processor, 2-core) variant with a Hydra (hyd) meta-controller. Its 64 KB MMIO window (0x01c40000–0x01c4ffff) is partitioned into four 16 KB banks:
| Offset Range | Bank Role | Read / Write Behavior |
|---|---|---|
0x0000 – 0x3fff |
Broadcast Bank | Writes broadcast to all enabled SGX cores; reads hang the bus if cores are clock-gated |
0x4000 – 0x7fff |
MP Master / Hydra Bank | Always accessible once the Hydra clock and bus reset are released (0x4010 = CORE_ID, 0x4014 = CORE_REVISION) |
0x8000 – 0xbfff |
Core 0 Bank | Accessible once Core 0 is ungated via the MP Master bank |
0xc000 – 0xffff |
Core 1 Bank | Accessible once Core 1 is ungated via the MP Master bank |
Reading from the broadcast bank (0x0000–0x3fff) before the MP master bank (0x4000) has enabled the slave cores stalls the bus indefinitely. Once I switched the probe check to read the MP Master bank directly:
0x01c44010(EUR_CR_MASTER_CORE_ID) returned0x011912010x01c44014(EUR_CR_MASTER_CORE_REVISION) returned0x00010105(SGX544 MP2 rev 1.1.5)
2. Allwinner A31s Power, PRCM, and Clock Sequencing
Before touching any register in 0x01c44000, the Allwinner A31s (sun6i) platform layer has to bring up the GPU power domain in a strict order:
- Regulator (
dcdc2): Enable AXP221dcdc2at 1.20 V (1200000 uV) and wait for voltage stabilization. - PRCM Power-Off Gating (
0x01f01400 + 0x118): Clear bit 0 in the PRCM GPU power-off gating register so the isolation clamps between the GPU island and the system bus are removed. - Clocks (
CCU): Configure PLL8 (or PLL9) and ungate the four GPU clock branches:ahb_gpu(bus interface)gpu_core(shader cores)gpu_mem(memory interface)gpu_hyd(Hydra multi-core interconnect)
- Reset Control: Deassert
rst_gpuvia the CCU reset controller.
With this sequence implemented in the kernel platform glue (sunxi_init.c), cold-boot initialization succeeds every time without bus stalls.
3. Porting pvrsrvkm (DDK 1.17) to Mainline Linux 7.2
To talk to the closed-source userspace GLES2/EGL blobs (libsrv_um.so, libIMGegl.so, libGLESv2.so, and pvrsrvctl), the kernel must provide the matching pvrsrvkm.ko driver from Imagination's DDK 1.17 (eurasia_km, build 4948957).
Porting eurasia_km from a 3.4/4.x kernel target to Mainline Linux 7.2 required updating several kernel internal APIs:
mmap/vm_flags_t: Replaced directvma->vm_flags |= ...assignments withvm_flags_set(vma, ...)introduced in Linux 6.3+.get_user_pages& Page Pinning: Updated arguments and removed deprecatedFOLL_WRITE/mmap_sem(mmap_lock) wrappers.- Timer & Workqueue APIs: Converted legacy
init_timercalls totimer_setup/from_timer. - DMA Mapping & Cache Maintenance: Replaced removed ARM32
dmac_map_areasymbols with standard DMA-API cache sync calls (dma_sync_single_for_cpu/dma_sync_single_for_device). - DRM Platform Integration: Registered the
pvrsrvkmplatform device against theallwinner,sun6i-a31-gpuDevice Tree node and wired up SPI interrupt 97 (GIC_SPI 97).
On cold boot, the OpenRC pvr init service loads pvrsrvkm.ko at ~4.96 s and runs pvrsrvctl --start --no-module at ~7.69 s, loading the SGX microkernel into the Hydra processor.
4. Bridging DDK 1.17 Userspace to Modern Mesa GBM & KMS (sun4i-drm)
Having /dev/pvrsrvkm working is only half the battle: the DDK 1.17 userspace blobs were built for glibc and expect a specific libpvr_dri_support.so / DRI2 interface, while our rootfs runs Alpine Linux 3.20 paired with mainline sun4i-drm (/dev/dri/card0).
- glibc Runtime Compatibility: Installed
gcompat/ glibc loader slices alongside a patched Mesa GBM (libgbm.so.1) andlibEGL.so.1that loads thepvrDRI driver (pvr_dri.so) backed bysun4i-drmdumb buffers. - Solving TA Parameter Buffer Exhaustion (
/etc/powervr.ini): When running complex geometry scenes inglmark2-es2-drm(such asideasandjellyfish), the Tile Accelerator (TA) initially ran out of parameter buffer memory mid-frame. Tuning/etc/powervr.iniresolved this completely:
[default]
ParamBufferSize=33554432
MaxParamBufferSize=67108864
5. Measured Hardware Performance on the 1024×768 LVDS Panel
All numbers below were measured on the physical Exper Easypad 8 (T8E) running Mainline Linux 7.2 at 1024×768 (LVDS-1 @ 54.87 Hz):
Custom kms-gles Stress & Soak Benchmark
- Single Full-Screen Shader Pass: 55.0 fps (vsync-locked to the 54.87 Hz panel refresh rate).
- 20 Blended Full-Screen Layers (~430 Mpixel/s fill-rate load): Sustained 27.4 fps constant over a 180-second soak test:
- 4,940 frames rendered
- ~32,000 SGX hardware interrupts serviced on SPI 97
- 0 hardware lockups (
SGXOSTimerrecoveries = 0)
glmark2-es2-drm Full Suite
Running glmark2-es2-drm directly on /dev/dri/card0 at native 1024×768 completed every default benchmark scene (build, texture, shading, bump, effect2d, pulsar, desktop, buffer, ideas, jellyfish, terrain, shadow, refract, conditionals, function, loop) with an overall glmark2 Score of 211.
Weston 10.0.1 Wayland Compositor (gles-unpack-shim)
When starting Weston 10.0.1 (weston --backend=drm-backend.so) on the SGX544 GLES2 driver, Weston's GL renderer refuses to initialize SHM client texture uploads if the driver does not advertise GL_EXT_unpack_subimage.
To solve this without recompiling Weston, I wrote a lightweight LD_PRELOAD library (gles-unpack-shim.so) that:
- Appends
GL_EXT_unpack_subimagetoglGetString(GL_EXTENSIONS). - Intercepts
glPixelStorei(GL_UNPACK_ROW_LENGTH / GL_UNPACK_SKIP_PIXELS / GL_UNPACK_SKIP_ROWS)and repacks sub-rect rows in CPU memory when uploadingglTexImage2D/glTexSubImage2Dwith non-zero unpack strides.
With gles-unpack-shim.so preloaded, Weston 10 runs smoothly on the tablet with full Goodix GT911 5-point multi-touch input, and weston-simple-egl renders at a locked 55 fps.
Summary & Device Page
You can view the complete hardware table, Device Tree pinout, and build instructions on the Exper Easypad 8 (Model T8E) device page, or check out the repository at Mechres/exper-easypad8-t8e-linux.