megi's PinePhone Development Log RSS


2023–04–16: Pinephone DRM driver issues

I did quite a lot of testing on the DRM driver to find the root of the issue mentioned in the previous post.

In general, display updates happen in a cycle with a constant frequency. When you decide to update the contents of the screen, you want it to happen during the vertical blanking part of the cycle to avoid image tearing and other display artifacts.

With DRM atomic API this can be handled by application making a so called atomic commit, which writes a new display state to the hardware which the hardware is then supposed to apply during the upcomming blanking part of the display output cycle. When that update happens, the driver should signal to userspace application (via a flip event) that the previously commited state is being scanned out and it can make a new commit for the next cycle if it wishes to do so.

This doesn't work well with the sun4i-drm driver, because it sends the flip event too soon, before the hardware switched to previously commited state. If the userspace application manages to commit new state within ~150us of the flip event, it's likely that parts or the whole of the new state will get scanned out immediately, instead of in the next cycle as expected.

Blanking cycle on Pinephone lasts about 400us with 45us long vsync pulse roughly in the middle. In my observation it seems likely that HW signals VSYNC interrupt at the start or end of the VSYNC pulse and flips the double buffered HW registers at the end of the blanking cycle, leaving some 150us of time in between for a quick attomic commit to still mess up the settings for the upcoming scan out.

(Interrupts are very fast. I've measured just 20us delay between VSYNC interrupt, flip event delivery to userspace application and the next atomic commit by the application.)

The problem here is that this violates the API contract. Additionally, unpredictable timing of atomic commit may lead to sometimes scanning out some mix of current and previous atomic states, because writing to display engine's MMIO registers takes time, and if blanking period ends before all the registers are updated, you get corrupted output on the screen.

There's no fix, only workaround for now is to not do DRM atomic commits from the flip event handler immediately and to add a 200us delay to the event handler.

It can also be fixed by putting this delay into the driver's interrupt handler for VSYNC interrupt, to delay the generation of the flip event enough so that userspace doesn't get an opportunity to commit too early.

Required delay depends on currently configured LCD panel mode. Safest value can be calculated as 1/(refresh rate)/vtotal*(vtotal-vactive).