Display clocks

The display engine uses several different clocks to do its work. There are two main clocks involved that aren’t directly related to the actual pixel clock or any symbol/bit clock of the actual output port. These are the core display clock (CDCLK) and RAWCLK.

CDCLK clocks most of the display pipe logic, and thus its frequency must be high enough to support the rate at which pixels are flowing through the pipes. Downscaling must also be accounted as that increases the effective pixel rate.

On several platforms the CDCLK frequency can be changed dynamically to minimize power consumption for a given display configuration. Typically changes to the CDCLK frequency require all the display pipes to be shut down while the frequency is being changed.

On SKL+ the DMC will toggle the CDCLK off/on during DC5/6 entry/exit. DMC will not change the active CDCLK frequency however, so that part will still be performed by the driver directly.

There are multiple components involved in the generation of the CDCLK frequency:

  • We have the CDCLK PLL, which generates an output clock based on a reference clock and a ratio parameter.

  • The CD2X Divider, which divides the output of the PLL based on a divisor selected from a set of pre-defined choices.

  • The CD2X Squasher, which further divides the output based on a waveform represented as a sequence of bits where each zero “squashes out” a clock cycle.

  • And, finally, a fixed divider that divides the output frequency by 2.

As such, the resulting CDCLK frequency can be calculated with the following formula:

cdclk = vco / cd2x_div / (sq_len / sq_div) / 2

, where vco is the frequency generated by the PLL; cd2x_div represents the CD2X Divider; sq_len and sq_div are the bit length and the number of high bits for the CD2X Squasher waveform, respectively; and 2 represents the fixed divider.

Note that some older platforms do not contain the CD2X Divider and/or CD2X Squasher, in which case we can ignore their respective factors in the formula above.

Several methods exist to change the CDCLK frequency, which ones are supported depends on the platform:

  • Full PLL disable + re-enable with new VCO frequency. Pipes must be inactive.

  • CD2X divider update. Single pipe can be active as the divider update can be synchronized with the pipe’s start of vblank.

  • Crawl the PLL smoothly to the new VCO frequency. Pipes can be active.

  • Squash waveform update. Pipes can be active.

  • Crawl and squash can also be done back to back. Pipes can be active.

RAWCLK is a fixed frequency clock, often used by various auxiliary blocks such as AUX CH or backlight PWM. Hence the only thing we really need to know about RAWCLK is its frequency so that various dividers can be programmed correctly.

void intel_cdclk_init_hw(struct intel_display *display)

Initialize CDCLK hardware

Parameters

struct intel_display *display

display instance

Description

Initialize CDCLK. This consists mainly of initializing display->cdclk.hw and sanitizing the state of the hardware if needed. This is generally done only during the display core initialization sequence, after which the DMC will take care of turning CDCLK off/on as needed.

void intel_cdclk_uninit_hw(struct intel_display *display)

Uninitialize CDCLK hardware

Parameters

struct intel_display *display

display instance

Description

Uninitialize CDCLK. This is done only during the display core uninitialization sequence.

bool intel_cdclk_clock_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)

Check whether the clock changed

Parameters

const struct intel_cdclk_config *a

first CDCLK configuration

const struct intel_cdclk_config *b

second CDCLK configuration

Return

True if CDCLK changed in a way that requires re-programming and False otherwise.

bool intel_cdclk_can_cd2x_update(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)

Determine if changing between the two CDCLK configurations requires only a cd2x divider update

Parameters

struct intel_display *display

display instance

const struct intel_cdclk_config *a

first CDCLK configuration

const struct intel_cdclk_config *b

second CDCLK configuration

Return

True if changing between the two CDCLK configurations can be done with just a cd2x divider update, false if not.

bool intel_cdclk_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b)

Determine if two CDCLK configurations are different

Parameters

const struct intel_cdclk_config *a

first CDCLK configuration

const struct intel_cdclk_config *b

second CDCLK configuration

Return

True if the CDCLK configurations don’t match, false if they do.

void intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)

Push the CDCLK state to the hardware

Parameters

struct intel_atomic_state *state

intel atomic state

Description

Program the hardware before updating the HW plane state based on the new CDCLK state, if necessary.

void intel_set_cdclk_post_plane_update(struct intel_atomic_state *state)

Push the CDCLK state to the hardware

Parameters

struct intel_atomic_state *state

intel atomic state

Description

Program the hardware after updating the HW plane state based on the new CDCLK state, if necessary.

void intel_update_max_cdclk(struct intel_display *display)

Determine the maximum support CDCLK frequency

Parameters

struct intel_display *display

display instance

Description

Determine the maximum CDCLK frequency the platform supports, and also derive the maximum dot clock frequency the maximum CDCLK frequency allows.

void intel_update_cdclk(struct intel_display *display)

Determine the current CDCLK frequency

Parameters

struct intel_display *display

display instance

Description

Determine the current CDCLK frequency.

u32 intel_read_rawclk(struct intel_display *display)

Determine the current RAWCLK frequency

Parameters

struct intel_display *display

display instance

Description

Determine the current RAWCLK frequency. RAWCLK is a fixed frequency clock so this needs to done only once.

void intel_init_cdclk_hooks(struct intel_display *display)

Initialize CDCLK related modesetting hooks

Parameters

struct intel_display *display

display instance