Display Hardware Handling

Mode Setting Infrastructure
Frontbuffer Tracking
Display FIFO Underrun Reporting
Plane Configuration
Atomic Plane Helpers
Output Probing
High Definition Audio
Panel Self Refresh PSR (PSR/SRD)
Frame Buffer Compression (FBC)
Display Refresh Rate Switching (DRRS)
DPIO

This section covers everything related to the display hardware including the mode setting infrastructure, plane, sprite and cursor handling and display, output probing and related topics.

Mode Setting Infrastructure

The i915 driver is thus far the only DRM driver which doesn't use the common DRM helper code to implement mode setting sequences. Thus it has its own tailor-made infrastructure for executing a display configuration change.

Frontbuffer Tracking

intel_mark_fb_busy — mark given planes as busy
intel_fb_obj_invalidate — invalidate frontbuffer object
intel_frontbuffer_flush — flush frontbuffer
intel_fb_obj_flush — flush frontbuffer object
intel_frontbuffer_flip_prepare — prepare asynchronous frontbuffer flip
intel_frontbuffer_flip_complete — complete asynchronous frontbuffer flip
intel_frontbuffer_flip — synchronous frontbuffer flip
i915_gem_track_fb — update frontbuffer tracking

Many features require us to track changes to the currently active frontbuffer, especially rendering targeted at the frontbuffer.

To be able to do so GEM tracks frontbuffers using a bitmask for all possible frontbuffer slots through i915_gem_track_fb. The function in this file are then called when the contents of the frontbuffer are invalidated, when frontbuffer rendering has stopped again to flush out all the changes and when the frontbuffer is exchanged with a flip. Subsystems interested in frontbuffer changes (e.g. PSR, FBC, DRRS) should directly put their callbacks into the relevant places and filter for the frontbuffer slots that they are interested int.

On a high level there are two types of powersaving features. The first one work like a special cache (FBC and PSR) and are interested when they should stop caching and when to restart caching. This is done by placing callbacks into the invalidate and the flush functions: At invalidate the caching must be stopped and at flush time it can be restarted. And maybe they need to know when the frontbuffer changes (e.g. when the hw doesn't initiate an invalidate and flush on its own) which can be achieved with placing callbacks into the flip functions.

The other type of display power saving feature only cares about busyness (e.g. DRRS). In that case all three (invalidate, flush and flip) indicate busyness. There is no direct way to detect idleness. Instead an idle timer work delayed work should be started from the flush and flip functions and cancelled as soon as busyness is detected.

Note that there's also an older frontbuffer activity tracking scheme which just tracks general activity. This is done by the various mark_busy and mark_idle functions. For display power management features using these functions is deprecated and should be avoided.

Display FIFO Underrun Reporting

i9xx_check_fifo_underruns — check for fifo underruns
intel_set_cpu_fifo_underrun_reporting — set cpu fifo underrrun reporting state
intel_set_pch_fifo_underrun_reporting — set PCH fifo underrun reporting state
intel_cpu_fifo_underrun_irq_handler — handle CPU fifo underrun interrupt
intel_pch_fifo_underrun_irq_handler — handle PCH fifo underrun interrupt

The i915 driver checks for display fifo underruns using the interrupt signals provided by the hardware. This is enabled by default and fairly useful to debug display issues, especially watermark settings.

If an underrun is detected this is logged into dmesg. To avoid flooding logs and occupying the cpu underrun interrupts are disabled after the first occurrence until the next modeset on a given pipe.

Note that underrun detection on gmch platforms is a bit more ugly since there is no interrupt (despite that the signalling bit is in the PIPESTAT pipe interrupt register). Also on some other platforms underrun interrupts are shared, which means that if we detect an underrun we need to disable underrun reporting on all pipes.

The code also supports underrun detection on the PCH transcoder.

Plane Configuration

This section covers plane configuration and composition with the primary plane, sprites, cursors and overlays. This includes the infrastructure to do atomic vsync'ed updates of all this state and also tightly coupled topics like watermark setup and computation, framebuffer compression and panel self refresh.

Atomic Plane Helpers

intel_create_plane_state — create plane state object
intel_plane_duplicate_state — duplicate plane state
intel_plane_destroy_state — destroy plane state
intel_plane_atomic_get_property — fetch plane property value
intel_plane_atomic_set_property — set plane property value

The functions here are used by the atomic plane helper functions to implement legacy plane updates (i.e., drm_plane->update_plane and drm_plane->disable_plane). This allows plane updates to use the atomic state infrastructure and perform plane updates as separate prepare/check/commit/cleanup steps.

Output Probing

This section covers output probing and related infrastructure like the hotplug interrupt storm detection and mitigation code. Note that the i915 driver still uses most of the common DRM helper code for output probing, so those sections fully apply.

High Definition Audio

intel_audio_codec_enable — Enable the audio codec for HD audio
intel_audio_codec_disable — Disable the audio codec for HD audio
intel_init_audio — Set up chip specific audio functions
i915_audio_component_init — initialize and register the audio component
i915_audio_component_cleanup — deregister the audio component

The graphics and audio drivers together support High Definition Audio over HDMI and Display Port. The audio programming sequences are divided into audio codec and controller enable and disable sequences. The graphics driver handles the audio codec sequences, while the audio driver handles the audio controller sequences.

The disable sequences must be performed before disabling the transcoder or port. The enable sequences may only be performed after enabling the transcoder and port, and after completed link training.

The codec and controller sequences could be done either parallel or serial, but generally the ELDV/PD change in the codec sequence indicates to the audio driver that the controller sequence should start. Indeed, most of the co-operation between the graphics and audio drivers is handled via audio related registers. (The notable exception is the power management, not covered here.)

Panel Self Refresh PSR (PSR/SRD)

intel_psr_enable — Enable PSR
intel_psr_disable — Disable PSR
intel_psr_invalidate — Invalidade PSR
intel_psr_flush — Flush PSR
intel_psr_init — Init basic PSR work and mutex.

Since Haswell Display controller supports Panel Self-Refresh on display panels witch have a remote frame buffer (RFB) implemented according to PSR spec in eDP1.3. PSR feature allows the display to go to lower standby states when system is idle but display is on as it eliminates display refresh request to DDR memory completely as long as the frame buffer for that display is unchanged.

Panel Self Refresh must be supported by both Hardware (source) and Panel (sink).

PSR saves power by caching the framebuffer in the panel RFB, which allows us to power down the link and memory controller. For DSI panels the same idea is called manual mode.

The implementation uses the hardware-based PSR support which automatically enters/exits self-refresh mode. The hardware takes care of sending the required DP aux message and could even retrain the link (that part isn't enabled yet though). The hardware also keeps track of any frontbuffer changes to know when to exit self-refresh mode again. Unfortunately that part doesn't work too well, hence why the i915 PSR support uses the software frontbuffer tracking to make sure it doesn't miss a screen update. For this integration intel_psr_invalidate and intel_psr_flush get called by the frontbuffer tracking code. Note that because of locking issues the self-refresh re-enable code is done from a work queue, which must be correctly synchronized/cancelled when shutting down the pipe."

Frame Buffer Compression (FBC)

intel_fbc_enabled — Is FBC enabled?
intel_fbc_disable — disable FBC
intel_fbc_update — enable/disable FBC as needed
intel_fbc_init — Initialize FBC

FBC tries to save memory bandwidth (and so power consumption) by compressing the amount of memory used by the display. It is total transparent to user space and completely handled in the kernel.

The benefits of FBC are mostly visible with solid backgrounds and variation-less patterns. It comes from keeping the memory footprint small and having fewer memory pages opened and accessed for refreshing the display.

i915 is responsible to reserve stolen memory for FBC and configure its offset on proper registers. The hardware takes care of all compress/decompress. However there are many known cases where we have to forcibly disable it to allow proper screen updates.

Display Refresh Rate Switching (DRRS)

intel_dp_set_drrs_state — program registers for RR switch to take effect
intel_edp_drrs_enable — init drrs struct if supported
intel_edp_drrs_disable — Disable DRRS
intel_edp_drrs_invalidate — Invalidate DRRS
intel_edp_drrs_flush — Flush DRRS
intel_dp_drrs_init — Init basic DRRS work and mutex.

Display Refresh Rate Switching (DRRS) is a power conservation feature which enables swtching between low and high refresh rates, dynamically, based on the usage scenario. This feature is applicable for internal panels.

Indication that the panel supports DRRS is given by the panel EDID, which would list multiple refresh rates for one resolution.

DRRS is of 2 types - static and seamless. Static DRRS involves changing refresh rate (RR) by doing a full modeset (may appear as a blink on screen) and is used in dock-undock scenario. Seamless DRRS involves changing RR without any visual effect to the user and can be used during normal system usage. This is done by programming certain registers.

Support for static/seamless DRRS may be indicated in the VBT based on inputs from the panel spec.

DRRS saves power by switching to low RR based on usage scenarios.

eDP DRRS:- The implementation is based on frontbuffer tracking implementation. When there is a disturbance on the screen triggered by user activity or a periodic system activity, DRRS is disabled (RR is changed to high RR). When there is no movement on screen, after a timeout of 1 second, a switch to low RR is made. For integration with frontbuffer tracking code, intel_edp_drrs_invalidate and intel_edp_drrs_flush are called.

DRRS can be further extended to support other internal panels and also the scenario of video playback wherein RR is set based on the rate requested by userspace.

DPIO

VLV and CHV have slightly peculiar display PHYs for driving DP/HDMI ports. DPIO is the name given to such a display PHY. These PHYs don't follow the standard programming model using direct MMIO registers, and instead their registers must be accessed trough IOSF sideband. VLV has one such PHY for driving ports B and C, and CHV adds another PHY for driving port D. Each PHY responds to specific IOSF-SB port.

Each display PHY is made up of one or two channels. Each channel houses a common lane part which contains the PLL and other common logic. CH0 common lane also contains the IOSF-SB logic for the Common Register Interface (CRI) ie. the DPIO registers. CRI clock must be running when any DPIO registers are accessed.

In addition to having their own registers, the PHYs are also controlled through some dedicated signals from the display controller. These include PLL reference clock enable, PLL enable, and CRI clock selection, for example.

Eeach channel also has two splines (also called data lanes), and each spline is made up of one Physical Access Coding Sub-Layer (PCS) block and two TX lanes. So each channel has two PCS blocks and four TX lanes. The TX lanes are used as DP lanes or TMDS data/clock pairs depending on the output type.

Additionally the PHY also contains an AUX lane with AUX blocks for each channel. This is used for DP AUX communication, but this fact isn't really relevant for the driver since AUX is controlled from the display controller side. No DPIO registers need to be accessed during AUX communication,

Generally the common lane corresponds to the pipe and the spline (PCS/TX) corresponds to the port.

For dual channel PHY (VLV/CHV):

pipe A == CMN/PLL/REF CH0

pipe B == CMN/PLL/REF CH1

port B == PCS/TX CH0

port C == PCS/TX CH1

This is especially important when we cross the streams ie. drive port B with pipe B, or port C with pipe A.

For single channel PHY (CHV):

pipe C == CMN/PLL/REF CH0

port D == PCS/TX CH0

Note: digital port B is DDI0, digital port C is DDI1, digital port D is DDI2

Table 4.1. Dual channel PHY (VLV/CHV)

CH0CH1
CMN/PLL/REFCMN/PLL/REF
PCS01PCS23PCS01PCS23
TX0TX1TX2TX3TX0TX1TX2TX3
DDI0DDI1

Table 4.2. Single channel PHY (CHV)

CH0
CMN/PLL/REF
PCS01PCS23
TX0TX1TX2TX3
DDI2