Display Hardware Handling

Mode Setting Infrastructure
Frontbuffer Tracking
Display FIFO Underrun Reporting
Plane Configuration
Atomic Plane Helpers
Output Probing
Hotplug
High Definition Audio
Panel Self Refresh PSR (PSR/SRD)
Frame Buffer Compression (FBC)
Display Refresh Rate Switching (DRRS)
DPIO
CSR firmware support for DMC
Video BIOS Table (VBT)

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_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

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
intel_check_cpu_fifo_underruns — check for CPU fifo underruns immediately
intel_check_pch_fifo_underruns — check for PCH fifo underruns immediately

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.

Hotplug

intel_hpd_irq_storm_detect — gather stats and detect HPD irq storm on a pin
intel_hpd_irq_handler — main hotplug irq handler
intel_hpd_init — initializes and enables hpd support

Simply put, hotplug occurs when a display is connected to or disconnected from the system. However, there may be adapters and docking stations and Display Port short pulses and MST devices involved, complicating matters.

Hotplug in i915 is handled in many different levels of abstraction.

The platform dependent interrupt handling code in i915_irq.c enables, disables, and does preliminary handling of the interrupts. The interrupt handlers gather the hotplug detect (HPD) information from relevant registers into a platform independent mask of hotplug pins that have fired.

The platform independent interrupt handler intel_hpd_irq_handler in intel_hotplug.c does hotplug irq storm detection and mitigation, and passes further processing to appropriate bottom halves (Display Port specific and regular hotplug).

The Display Port work function i915_digport_work_func calls into intel_dp_hpd_pulse via hooks, which handles DP short pulses and DP MST long pulses, with failures and non-MST long pulses triggering regular hotplug processing on the connector.

The regular hotplug work function i915_hotplug_work_func calls connector detect hooks, and, if connector status changes, triggers sending of hotplug uevent to userspace via drm_kms_helper_hotplug_event.

Finally, the userspace is responsible for triggering a modeset upon receiving the hotplug uevent, disabling or enabling the crtc as needed.

The hotplug interrupt storm detection and mitigation code keeps track of the number of interrupts per hotplug pin per a period of time, and if the number of interrupts exceeds a certain threshold, the interrupt is disabled for a while before being re-enabled. The intention is to mitigate issues raising from broken hardware triggering massive amounts of interrupts and grinding the system to a halt.

Current implementation expects that hotplug interrupt storm will not be seen when display port sink is connected, hence on platforms whose DP callback is handled by i915_digport_work_func reenabling of hpd is not performed (it was never expected to be disabled in the first place ;) ) this is specific to DP sinks handled by this routine and any other display such as HDMI or DVI enabled on the same port will have proper logic since it will use i915_hotplug_work_func where this logic is handled.

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_hooks — Set up chip specific audio hooks
i915_audio_component_init — initialize and register the audio component
i915_audio_component_cleanup — deregister the audio component
struct i915_audio_component_ops — Ops implemented by i915 driver, called by hda driver
struct i915_audio_component_audio_ops — Ops implemented by hda driver, called by i915 driver
struct i915_audio_component — Used for direct communication between i915 and hda drivers

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. Therefore the audio enable/disable sequences are part of the modeset sequence.

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

The struct i915_audio_component is used to interact between the graphics and audio drivers. The struct i915_audio_component_ops *ops in it is defined in graphics driver and called in audio driver. The struct i915_audio_component_audio_ops *audio_ops is called from i915 driver.

Panel Self Refresh PSR (PSR/SRD)

intel_psr_enable — Enable PSR
intel_psr_disable — Disable PSR
intel_psr_single_frame_update — Single Frame Update
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_is_active — Is FBC active?
intel_fbc_choose_crtc — select a CRTC to enable FBC on
intel_fbc_enable
__intel_fbc_disable — disable FBC
intel_fbc_disable — disable FBC if it's associated with crtc
intel_fbc_global_disable — globally disable FBC
intel_fbc_init_pipe_state — initialize FBC's CRTC visibility tracking
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 — Disable Idleness DRRS
intel_edp_drrs_flush — Restart Idleness 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, CHV and BXT 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 on VLV/CHV 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

On BXT the entire PHY channel corresponds to the port. That means the PLL is also now associated with the port rather than the pipe, and so the clock needs to be routed to the appropriate transcoder. Port A PLL is directly connected to transcoder EDP and port B/C PLLs can be routed to any transcoder A/B/C.

Note: DDI0 is digital port B, DD1 is digital port C, and DDI2 is digital port D (CHV) or port A (BXT).

Dual channel PHY (VLV/CHV/BXT) --------------------------------- | CH0 | CH1 | | CMN/PLL/REF | CMN/PLL/REF | |---------------|---------------| Display PHY | PCS01 | PCS23 | PCS01 | PCS23 | |-------|-------|-------|-------| |TX0|TX1|TX2|TX3|TX0|TX1|TX2|TX3| --------------------------------- | DDI0 | DDI1 | DP/HDMI ports ---------------------------------

Single channel PHY (CHV/BXT) ----------------- | CH0 | | CMN/PLL/REF | |---------------| Display PHY | PCS01 | PCS23 | |-------|-------| |TX0|TX1|TX2|TX3| ----------------- | DDI2 | DP/HDMI port -----------------

CSR firmware support for DMC

intel_csr_load_program — write the firmware from memory to register.
intel_csr_ucode_init — initialize the firmware loading.
intel_csr_ucode_suspend — prepare CSR firmware before system suspend
intel_csr_ucode_resume — init CSR firmware during system resume
intel_csr_ucode_fini — unload the CSR firmware.

Display Context Save and Restore (CSR) firmware support added from gen9 onwards to drive newly added DMC (Display microcontroller) in display engine to save and restore the state of display engine when it enter into low-power state and comes back to normal.

Firmware loading status will be one of the below states: FW_UNINITIALIZED, FW_LOADED, FW_FAILED.

Once the firmware is written into the registers status will be moved from FW_UNINITIALIZED to FW_LOADED and for any erroneous condition status will be moved to FW_FAILED.

Video BIOS Table (VBT)

intel_bios_is_valid_vbt — does the given buffer contain a valid VBT
intel_bios_init — find VBT and initialize settings from the BIOS
intel_bios_is_tv_present — is integrated TV present in VBT
intel_bios_is_lvds_present — is LVDS present in VBT
intel_bios_is_port_edp — is the device in given port eDP
intel_bios_is_dsi_present — is DSI present in VBT
intel_bios_is_port_hpd_inverted — is HPD inverted for port
struct vbt_header — VBT Header structure
struct bdb_header — BDB Header structure

The Video BIOS Table, or VBT, provides platform and board specific configuration information to the driver that is not discoverable or available through other means. The configuration is mostly related to display hardware. The VBT is available via the ACPI OpRegion or, on older systems, in the PCI ROM.

The VBT consists of a VBT Header (defined as struct vbt_header), a BDB Header (struct bdb_header), and a number of BIOS Data Blocks (BDB) that contain the actual configuration information. The VBT Header, and thus the VBT, begins with $VBT signature. The VBT Header contains the offset of the BDB Header. The data blocks are concatenated after the BDB Header. The data blocks have a 1-byte Block ID, 2-byte Block Size, and Block Size bytes of data. (Block 53, the MIPI Sequence Block is an exception.)

The driver parses the VBT during load. The relevant information is stored in driver private data for ease of use, and the actual VBT is not read after that.