Patrick Lidstone
Self-hosted

Development log

Bringing the panel back, and five registers that lied

· Path OS

The machine wakes. The screen stays black, which from the keyboard is indistinguishable from the machine not having woken at all - so the first job was not the display, it was telling those two apart.

A blank screen after a resume has two causes: the pipeline is off, or the pipeline is running and the panel is not lit. Those need different fixes, so the display pipeline is now measured across the sleep and the registers are printed at boot and again at the failure, which makes the comparison a read rather than an argument.

Printing them was its own small comedy. Eleven registers do not fit on one line. Neither do twenty-two, and fourteen of those went off the end before anybody noticed.

The documented sequence

Intel's Kaby Lake documentation says exactly what a display bring-up is meant to look like: seventeen steps, in seven stages. The reference is now kept in the tree rather than as a link, because a link to a vendor document is a dependency on somebody else's content management system.

The stages, in order:

  1. Power wells, enabled in the documented order, each with a bounded wait on its state bit before the next. PW1 and PW2 survive the sleep and the DDI well does not, so only the missing ones are requested.
  2. CDCLK, through the documented change sequence rather than a bare register write. It comes back at a different frequency, so it has to be reprogrammed properly.
  3. DPLL: DPLL_CTRL1 and CTRL2, then enable, then wait for lock in DPLL_STATUS.
  4. The transcoder: timings first, then TRANS_DDI_FUNC_CTL, then enable, then poll the state bit.
  5. DDI and link training, through the DP_TP_CTL pattern sequence.
  6. The plane: control, stride, size and offset, then PLANE_SURF last, because that write is what arms it.
  7. Panel power, then backlight, after the stream is valid.

That last ordering is the one I had wrong. Lighting a panel before the stream is valid gets you a lit panel showing nothing, which looks like a different fault entirely.

Five registers that lied

Every one of these was found by reading the hardware rather than the code, and each one made the next visible.

The proof-of-life check read the wrong register, so a pipeline that was running reported itself dead. The mode was being measured from the wrong transcoder, which gave a plausible answer that belonged to a different output. The data buffer register was the second slice, which this part has not got - so it read as zero, consistently, and zero is a legal value.

The port was mapped to a PLL that had been switched off. And a port whose buffer is off does not carry AUX either, which is the one that took longest: the panel will not answer a question while the port is sending it a training pattern, and the AUX probe was running before there was a device to probe at all.

The fix for that last one is to ask the panel who it is while the display still works, on the way down, rather than trying to interrogate it on the way back up when the link is the thing that is broken. There is also a bit whose entire purpose is to assert VDD so that AUX works, which is the sort of thing that is obvious once you have read the right page.

The display comes back.

What is not built

Link training still rests on the documented pattern sequence rather than on real DPCD negotiation with the panel. It works on this panel. A panel that needed a different voltage swing or a retry would expose that, and I have not tested one.

This is one panel on one machine. The X220's display path is similar but not the same, and nothing here has been run on it since the change.