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)
.