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) returned 0x01191201
  • 0x01c44014 (EUR_CR_MASTER_CORE_REVISION) returned 0x00010105 (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:

  1. Regulator (dcdc2): Enable AXP221 dcdc2 at 1.20 V (1200000 uV) and wait for voltage stabilization.
  2. 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.
  3. 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)
  4. Reset Control: Deassert rst_gpu via 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 direct vma->vm_flags |= ... assignments with vm_flags_set(vma, ...) introduced in Linux 6.3+.
  • get_user_pages & Page Pinning: Updated arguments and removed deprecated FOLL_WRITE / mmap_sem (mmap_lock) wrappers.
  • Timer & Workqueue APIs: Converted legacy init_timer calls to timer_setup / from_timer.
  • DMA Mapping & Cache Maintenance: Replaced removed ARM32 dmac_map_area symbols with standard DMA-API cache sync calls (dma_sync_single_for_cpu / dma_sync_single_for_device).
  • DRM Platform Integration: Registered the pvrsrvkm platform device against the allwinner,sun6i-a31-gpu Device 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).

  1. glibc Runtime Compatibility: Installed gcompat / glibc loader slices alongside a patched Mesa GBM (libgbm.so.1) and libEGL.so.1 that loads the pvr DRI driver (pvr_dri.so) backed by sun4i-drm dumb buffers.
  2. Solving TA Parameter Buffer Exhaustion (/etc/powervr.ini): When running complex geometry scenes in glmark2-es2-drm (such as ideas and jellyfish), the Tile Accelerator (TA) initially ran out of parameter buffer memory mid-frame. Tuning /etc/powervr.ini resolved 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 (SGXOSTimer recoveries = 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_subimage to glGetString(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 uploading glTexImage2D / glTexSubImage2D with 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.

Related Posts