/** * DOC: CDCLK / RAWCLK * * 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.
*/
/* * Logical configuration of cdclk (used for all scaling, * watermark, etc. calculations and checks). This is * computed as if all enabled crtcs were active.
*/ struct intel_cdclk_config logical;
/* * Actual configuration of cdclk, can be different from the * logical configuration only when all crtc's are DPMS off.
*/ struct intel_cdclk_config actual;
/* minimum acceptable cdclk to satisfy bandwidth requirements */ int bw_min_cdclk; /* minimum acceptable cdclk for each pipe */ int min_cdclk[I915_MAX_PIPES]; /* minimum acceptable voltage level for each pipe */
u8 min_voltage_level[I915_MAX_PIPES];
/* pipe to which cd2x update is synchronized */ enum pipe pipe;
/* forced minimum cdclk for glk+ audio w/a */ int force_min_cdclk;
/* bitmask of active pipes */
u8 active_pipes;
/* update cdclk with pipes disabled */ bool disable_pipes;
};
/* * 852GM/852GMV only supports 133 MHz and the HPLLCC * encoding is different :( * FIXME is this the right way to detect 852GM/852GMV?
*/ if (pdev->revision == 0x1) {
cdclk_config->cdclk = 133333; return;
}
/* Assume that the hardware is in the high speed state. This * should be the default.
*/ switch (hpllcc & GC_CLOCK_CONTROL_MASK) { case GC_CLOCK_133_200: case GC_CLOCK_133_200_2: case GC_CLOCK_100_200:
cdclk_config->cdclk = 200000; break; case GC_CLOCK_166_250:
cdclk_config->cdclk = 250000; break; case GC_CLOCK_100_133:
cdclk_config->cdclk = 133333; break; case GC_CLOCK_133_266: case GC_CLOCK_133_266_2: case GC_CLOCK_166_266:
cdclk_config->cdclk = 266667; break;
}
}
/* * We seem to get an unstable or solid color picture at 200MHz. * Not sure what's wrong. For now use 200MHz only when all pipes * are off.
*/ if (display->platform.valleyview && min_cdclk > freq_320) return 400000; elseif (min_cdclk > 266667) return freq_320; elseif (min_cdclk > 0) return 266667; else return 200000;
}
if (display->platform.valleyview) { if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */ return 2; elseif (cdclk >= 266667) return 1; else return 0;
} else { /* * Specs are full of misinformation, but testing on actual * hardware has shown that we just need to write the desired * CCK divider into the Punit register.
*/ return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
}
}
if (display->platform.cherryview)
default_credits = PFI_CREDIT(12); else
default_credits = PFI_CREDIT(8);
if (display->cdclk.hw.cdclk >= dev_priv->czclk_freq) { /* CHV suggested value is 31 or 63 */ if (display->platform.cherryview)
credits = PFI_CREDIT_63; else
credits = PFI_CREDIT(15);
} else {
credits = default_credits;
}
/* * WA - write default credits before re-programming * FIXME: should we also set the resend bit here?
*/
intel_de_write(display, GCI_CONTROL,
VGA_FAST_MODE_DISABLE | default_credits);
/* * FIXME is this guaranteed to clear * immediately or should we poll for it?
*/
drm_WARN_ON(display->drm,
intel_de_read(display, GCI_CONTROL) & PFI_CREDIT_RESEND);
}
switch (cdclk) { case 400000: case 333333: case 320000: case 266667: case 200000: break; default:
MISSING_CASE(cdclk); return;
}
/* There are cases where we can end up here with power domains * off and a CDCLK frequency other than the minimum, like when * issuing a modeset without actually changing any display after * a system suspend. So grab the display core domain, which covers * the HW blocks needed for the following programming.
*/
wakeref = intel_display_power_get(display, POWER_DOMAIN_DISPLAY_CORE);
/* adjust cdclk divider */
val = vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL);
val &= ~CCK_FREQUENCY_VALUES;
val |= divider;
vlv_cck_write(display->drm, CCK_DISPLAY_CLOCK_CONTROL, val);
if (wait_for((vlv_cck_read(display->drm, CCK_DISPLAY_CLOCK_CONTROL) &
CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT),
50))
drm_err(display->drm, "timed out waiting for CDclk change\n");
}
/* adjust self-refresh exit latency value */
val = vlv_bunit_read(display->drm, BUNIT_REG_BISOC);
val &= ~0x7f;
/* * For high bandwidth configs, we set a higher latency in the bunit * so that the core display fetch happens in time to avoid underruns.
*/ if (cdclk == 400000)
val |= 4500 / 250; /* 4.5 usec */ else
val |= 3000 / 250; /* 3.0 usec */
vlv_bunit_write(display->drm, BUNIT_REG_BISOC, val);
switch (cdclk) { case 333333: case 320000: case 266667: case 200000: break; default:
MISSING_CASE(cdclk); return;
}
/* There are cases where we can end up here with power domains * off and a CDCLK frequency other than the minimum, like when * issuing a modeset without actually changing any display after * a system suspend. So grab the display core domain, which covers * the HW blocks needed for the following programming.
*/
wakeref = intel_display_power_get(display, POWER_DOMAIN_DISPLAY_CORE);
vlv_punit_get(display->drm);
val = vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM);
val &= ~DSPFREQGUAR_MASK_CHV;
val |= (cmd << DSPFREQGUAR_SHIFT_CHV);
vlv_punit_write(display->drm, PUNIT_REG_DSPSSPM, val); if (wait_for((vlv_punit_read(display->drm, PUNIT_REG_DSPSSPM) &
DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV),
50)) {
drm_err(display->drm, "timed out waiting for CDclk change\n");
}
/* * Can't read this out :( Let's assume it's * at least what the CDCLK frequency requires.
*/
cdclk_config->voltage_level =
bdw_calc_voltage_level(cdclk_config->cdclk);
}
static u32 bdw_cdclk_freq_sel(int cdclk)
{ switch (cdclk) { default:
MISSING_CASE(cdclk);
fallthrough; case 337500: return LCPLL_CLK_FREQ_337_5_BDW; case 450000: return LCPLL_CLK_FREQ_450; case 540000: return LCPLL_CLK_FREQ_54O_BDW; case 675000: return LCPLL_CLK_FREQ_675_BDW;
}
}
staticvoid bdw_set_cdclk(struct intel_display *display, conststruct intel_cdclk_config *cdclk_config, enum pipe pipe)
{ int cdclk = cdclk_config->cdclk; int ret;
if (drm_WARN(display->drm,
(intel_de_read(display, LCPLL_CTL) &
(LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK |
LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE |
LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW |
LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK, "trying to change cdclk frequency with cdclk not enabled\n")) return;
ret = intel_pcode_write(display->drm, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); if (ret) {
drm_err(display->drm, "failed to inform pcode about cdclk change\n"); return;
}
/* * According to the spec, it should be enough to poll for this 1 us. * However, extensive testing shows that this can take longer.
*/ if (wait_for_us(intel_de_read(display, LCPLL_CTL) &
LCPLL_CD_SOURCE_FCLK_DONE, 100))
drm_err(display->drm, "Switching to FCLK failed\n");
if (cdclk_config->vco == 8640000) { switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432:
cdclk_config->cdclk = 432000; break; case CDCLK_FREQ_337_308:
cdclk_config->cdclk = 308571; break; case CDCLK_FREQ_540:
cdclk_config->cdclk = 540000; break; case CDCLK_FREQ_675_617:
cdclk_config->cdclk = 617143; break; default:
MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK); break;
}
} else { switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432:
cdclk_config->cdclk = 450000; break; case CDCLK_FREQ_337_308:
cdclk_config->cdclk = 337500; break; case CDCLK_FREQ_540:
cdclk_config->cdclk = 540000; break; case CDCLK_FREQ_675_617:
cdclk_config->cdclk = 675000; break; default:
MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK); break;
}
}
out: /* * Can't read this out :( Let's assume it's * at least what the CDCLK frequency requires.
*/
cdclk_config->voltage_level =
skl_calc_voltage_level(cdclk_config->cdclk);
}
/* convert from kHz to .1 fixpoint MHz with -1MHz offset */ staticint skl_cdclk_decimal(int cdclk)
{ return DIV_ROUND_CLOSEST(cdclk - 1000, 500);
}
/* * We always enable DPLL0 with the lowest link rate possible, but still * taking into account the VCO required to operate the eDP panel at the * desired frequency. The usual DP link rates operate with a VCO of * 8100 while the eDP 1.4 alternate link rates need a VCO of 8640. * The modeset code is responsible for the selection of the exact link * rate later on, with the constraint of choosing a frequency that * works with vco.
*/ if (vco == 8640000) return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0); else return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0);
}
if (intel_de_wait_for_clear(display, LCPLL1_CTL, LCPLL_PLL_LOCK, 1))
drm_err(display->drm, "Couldn't disable DPLL0\n");
display->cdclk.hw.vco = 0;
}
static u32 skl_cdclk_freq_sel(struct intel_display *display, int cdclk, int vco)
{ switch (cdclk) { default:
drm_WARN_ON(display->drm,
cdclk != display->cdclk.hw.bypass);
drm_WARN_ON(display->drm, vco != 0);
fallthrough; case 308571: case 337500: return CDCLK_FREQ_337_308; case 450000: case 432000: return CDCLK_FREQ_450_432; case 540000: return CDCLK_FREQ_540; case 617143: case 675000: return CDCLK_FREQ_675_617;
}
}
staticvoid skl_set_cdclk(struct intel_display *display, conststruct intel_cdclk_config *cdclk_config, enum pipe pipe)
{ int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco;
u32 freq_select, cdclk_ctl; int ret;
/* * Based on WA#1183 CDCLK rates 308 and 617MHz CDCLK rates are * unsupported on SKL. In theory this should never happen since only * the eDP1.4 2.16 and 4.32Gbps rates require it, but eDP1.4 is not * supported on SKL either, see the above WA. WARN whenever trying to * use the corresponding VCO freq as that always leads to using the * minimum 308MHz CDCLK.
*/
drm_WARN_ON_ONCE(display->drm,
display->platform.skylake && vco == 8640000);
ret = intel_pcode_request(display->drm, SKL_PCODE_CDCLK_CONTROL,
SKL_CDCLK_PREPARE_FOR_CHANGE,
SKL_CDCLK_READY_FOR_CHANGE,
SKL_CDCLK_READY_FOR_CHANGE, 3); if (ret) {
drm_err(display->drm, "Failed to inform PCU about cdclk change (%d)\n", ret); return;
}
/* * check if the pre-os initialized the display * There is SWF18 scratchpad register defined which is set by the * pre-os which can be used by the OS drivers to check the status
*/ if ((intel_de_read(display, SWF_ILK(0x18)) & 0x00FFFFFF) == 0) goto sanitize;
/* Is PLL enabled and locked ? */ if (display->cdclk.hw.vco == 0 ||
display->cdclk.hw.cdclk == display->cdclk.hw.bypass) goto sanitize;
/* DPLL okay; verify the cdclock * * Noticed in some instances that the freq selection is correct but * decimal part is programmed wrong from BIOS where pre-os does not * enable display. Verify the same as well.
*/
cdctl = intel_de_read(display, CDCLK_CTL);
expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
skl_cdclk_decimal(display->cdclk.hw.cdclk); if (cdctl == expected) /* All well; nothing to sanitize */ return;
sanitize:
drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");
/* force cdclk programming */
display->cdclk.hw.cdclk = 0; /* force full PLL disable + enable */
display->cdclk.hw.vco = ~0;
}
if (display->cdclk.hw.cdclk != 0 &&
display->cdclk.hw.vco != 0) { /* * Use the current vco as our initial * guess as to what the preferred vco is.
*/ if (display->cdclk.skl_preferred_vco_freq == 0)
skl_set_preferred_cdclk_vco(display,
display->cdclk.hw.vco); return;
}
static u8 xe3lpd_calc_voltage_level(int cdclk)
{ /* * Starting with xe3lpd power controller does not need the voltage * index when doing the modeset update. This function is best left * defined but returning 0 to the mask.
*/ return 0;
}
val = intel_de_read(display, BXT_DE_PLL_ENABLE); if ((val & BXT_DE_PLL_PLL_ENABLE) == 0 ||
(val & BXT_DE_PLL_LOCK) == 0) { /* * CDCLK PLL is disabled, the VCO/ratio doesn't matter, but * setting it to zero is a way to signal that.
*/
cdclk_config->vco = 0; return;
}
/* * DISPLAY_VER >= 11 have the ratio directly in the PLL enable register, * gen9lp had it in a separate PLL control register.
*/ if (DISPLAY_VER(display) >= 11)
ratio = val & ICL_CDCLK_PLL_RATIO_MASK; else
ratio = intel_de_read(display, BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK;
switch (divider) { case BXT_CDCLK_CD2X_DIV_SEL_1:
div = 2; break; case BXT_CDCLK_CD2X_DIV_SEL_1_5:
div = 3; break; case BXT_CDCLK_CD2X_DIV_SEL_2:
div = 4; break; case BXT_CDCLK_CD2X_DIV_SEL_4:
div = 8; break; default:
MISSING_CASE(divider); return;
}
if (HAS_CDCLK_SQUASH(display))
squash_ctl = intel_de_read(display, CDCLK_SQUASH_CTL);
if (squash_ctl & CDCLK_SQUASH_ENABLE) {
u16 waveform; int size;
out: if (DISPLAY_VER(display) >= 20)
cdclk_config->joined_mbus = intel_de_read(display, MBUS_CTL) & MBUS_JOIN; /* * Can't read this out :( Let's assume it's * at least what the CDCLK frequency requires.
*/
cdclk_config->voltage_level =
intel_cdclk_calc_voltage_level(display, cdclk_config->cdclk);
}
staticbool cdclk_pll_is_unknown(unsignedint vco)
{ /* * Ensure driver does not take the crawl path for the * case when the vco is set to ~0 in the * sanitize path.
*/ return vco == ~0;
}
/* Return if Squash only or Crawl only is the desired action */ if (old_cdclk_config->vco == 0 || new_cdclk_config->vco == 0 ||
old_cdclk_config->vco == new_cdclk_config->vco ||
old_waveform == new_waveform) returnfalse;
/* * Should not happen currently. We might need more midpoint * transitions if we need to also change the cd2x divider.
*/ if (drm_WARN_ON(display->drm, old_div != new_div)) returnfalse;
*mid_cdclk_config = *new_cdclk_config;
/* * Populate the mid_cdclk_config accordingly. * - If moving to a higher cdclk, the desired action is squashing. * The mid cdclk config should have the new (squash) waveform. * - If moving to a lower cdclk, the desired action is crawling. * The mid cdclk config should have the new vco.
*/
if (pipe != INVALID_PIPE)
intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, pipe));
}
staticvoid bxt_set_cdclk(struct intel_display *display, conststruct intel_cdclk_config *cdclk_config, enum pipe pipe)
{ struct intel_cdclk_config mid_cdclk_config; int cdclk = cdclk_config->cdclk; int ret = 0;
/* * Inform power controller of upcoming frequency change. * Display versions 14 and beyond do not follow the PUnit * mailbox communication, skip * this step.
*/ if (DISPLAY_VER(display) >= 14 || display->platform.dg2)
; /* NOOP */ elseif (DISPLAY_VER(display) >= 11)
ret = intel_pcode_request(display->drm, SKL_PCODE_CDCLK_CONTROL,
SKL_CDCLK_PREPARE_FOR_CHANGE,
SKL_CDCLK_READY_FOR_CHANGE,
SKL_CDCLK_READY_FOR_CHANGE, 3); else /* * BSpec requires us to wait up to 150usec, but that leads to * timeouts; the 2ms used here is based on experiment.
*/
ret = intel_pcode_write_timeout(display->drm,
HSW_PCODE_DE_WRITE_FREQ_REQ,
0x80000000, 2);
if (ret) {
drm_err(display->drm, "Failed to inform PCU about cdclk change (err %d, freq %d)\n",
ret, cdclk); return;
}
if (DISPLAY_VER(display) >= 20 && cdclk < display->cdclk.hw.cdclk)
xe2lpd_mdclk_cdclk_ratio_program(display, cdclk_config);
if (DISPLAY_VER(display) >= 20 && cdclk > display->cdclk.hw.cdclk)
xe2lpd_mdclk_cdclk_ratio_program(display, cdclk_config);
if (DISPLAY_VER(display) >= 14) /* * NOOP - No Pcode communication needed for * Display versions 14 and beyond
*/ elseif (DISPLAY_VER(display) >= 11 && !display->platform.dg2)
ret = intel_pcode_write(display->drm, SKL_PCODE_CDCLK_CONTROL,
cdclk_config->voltage_level); if (DISPLAY_VER(display) < 11) { /* * The timeout isn't specified, the 2ms used here is based on * experiment. * FIXME: Waiting for the request completion could be delayed * until the next PCODE request based on BSpec.
*/
ret = intel_pcode_write_timeout(display->drm,
HSW_PCODE_DE_WRITE_FREQ_REQ,
cdclk_config->voltage_level, 2);
} if (ret) {
drm_err(display->drm, "PCode CDCLK freq set failed, (err %d, freq %d)\n",
ret, cdclk); return;
}
intel_update_cdclk(display);
if (DISPLAY_VER(display) >= 11) /* * Can't read out the voltage level :( * Let's just assume everything is as expected.
*/
display->cdclk.hw.voltage_level = cdclk_config->voltage_level;
}
if (display->cdclk.hw.vco == 0 ||
display->cdclk.hw.cdclk == display->cdclk.hw.bypass) goto sanitize;
/* Make sure this is a legal cdclk value for the platform */
cdclk = bxt_calc_cdclk(display, display->cdclk.hw.cdclk); if (cdclk != display->cdclk.hw.cdclk) goto sanitize;
/* Make sure the VCO is correct for the cdclk */
vco = bxt_calc_cdclk_pll_vco(display, cdclk); if (vco != display->cdclk.hw.vco) goto sanitize;
/* * Some BIOS versions leave an incorrect decimal frequency value and * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, * so sanitize this register.
*/
cdctl = intel_de_read(display, CDCLK_CTL);
expected = bxt_cdclk_ctl(display, &display->cdclk.hw, INVALID_PIPE);
/* * Let's ignore the pipe field, since BIOS could have configured the * dividers both syncing to an active pipe, or asynchronously * (PIPE_NONE).
*/
cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
expected &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
if (cdctl == expected) /* All well; nothing to sanitize */ return;
sanitize:
drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");
/* force cdclk programming */
display->cdclk.hw.cdclk = 0;
/* force full PLL disable + enable */
display->cdclk.hw.vco = ~0;
}
if (display->cdclk.hw.cdclk != 0 &&
display->cdclk.hw.vco != 0) return;
cdclk_config = display->cdclk.hw;
/* * FIXME: * - The initial CDCLK needs to be read from VBT. * Need to make this change after VBT has changes for BXT.
*/
cdclk_config.cdclk = bxt_calc_cdclk(display, 0);
cdclk_config.vco = bxt_calc_cdclk_pll_vco(display, cdclk_config.cdclk);
cdclk_config.voltage_level =
intel_cdclk_calc_voltage_level(display, cdclk_config.cdclk);
/** * intel_cdclk_init_hw - Initialize CDCLK hardware * @display: display instance * * 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_init_hw(struct intel_display *display)
{ if (DISPLAY_VER(display) >= 10 || display->platform.broxton)
bxt_cdclk_init_hw(display); elseif (DISPLAY_VER(display) == 9)
skl_cdclk_init_hw(display);
}
/** * intel_cdclk_uninit_hw - Uninitialize CDCLK hardware * @display: display instance * * Uninitialize CDCLK. This is done only during the display core * uninitialization sequence.
*/ void intel_cdclk_uninit_hw(struct intel_display *display)
{ if (DISPLAY_VER(display) >= 10 || display->platform.broxton)
bxt_cdclk_uninit_hw(display); elseif (DISPLAY_VER(display) == 9)
skl_cdclk_uninit_hw(display);
}
/* * The vco and cd2x divider will change independently * from each, so we disallow cd2x change when crawling.
*/
a_div = DIV_ROUND_CLOSEST(a->vco, a->cdclk);
b_div = DIV_ROUND_CLOSEST(b->vco, b->cdclk);
staticbool intel_cdclk_can_squash(struct intel_display *display, conststruct intel_cdclk_config *a, conststruct intel_cdclk_config *b)
{ /* * FIXME should store a bit more state in intel_cdclk_config * to differentiate squasher vs. cd2x divider properly. For * the moment all platforms with squasher use a fixed cd2x * divider.
*/ if (!HAS_CDCLK_SQUASH(display)) returnfalse;
/** * intel_cdclk_clock_changed - Check whether the clock changed * @a: first CDCLK configuration * @b: second CDCLK configuration * * Returns: * True if CDCLK changed in a way that requires re-programming and * False otherwise.
*/ bool intel_cdclk_clock_changed(conststruct intel_cdclk_config *a, conststruct intel_cdclk_config *b)
{ return a->cdclk != b->cdclk ||
a->vco != b->vco ||
a->ref != b->ref;
}
/** * intel_cdclk_can_cd2x_update - Determine if changing between the two CDCLK * configurations requires only a cd2x divider update * @display: display instance * @a: first CDCLK configuration * @b: second CDCLK configuration * * Returns: * True if changing between the two CDCLK configurations * can be done with just a cd2x divider update, false if not.
*/ staticbool intel_cdclk_can_cd2x_update(struct intel_display *display, conststruct intel_cdclk_config *a, conststruct intel_cdclk_config *b)
{ /* Older hw doesn't have the capability */ if (DISPLAY_VER(display) < 10 && !display->platform.broxton) returnfalse;
/* * FIXME should store a bit more state in intel_cdclk_config * to differentiate squasher vs. cd2x divider properly. For * the moment all platforms with squasher use a fixed cd2x * divider.
*/ if (HAS_CDCLK_SQUASH(display)) returnfalse;
/** * intel_cdclk_changed - Determine if two CDCLK configurations are different * @a: first CDCLK configuration * @b: second CDCLK configuration * * Returns: * True if the CDCLK configurations don't match, false if they do.
*/ staticbool intel_cdclk_changed(conststruct intel_cdclk_config *a, conststruct intel_cdclk_config *b)
{ return intel_cdclk_clock_changed(a, b) ||
a->voltage_level != b->voltage_level;
}
/* * Lock aux/gmbus while we change cdclk in case those * functions use cdclk. Not all platforms/ports do, * but we'll lock them all for simplicity.
*/
mutex_lock(&display->gmbus.mutex);
for_each_intel_dp(display->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
/* * According to "Sequence Before Frequency Change", * if CDCLK is increasing, set bits 25:16 to upcoming CDCLK, * if CDCLK is decreasing or not changing, set bits 25:16 to current CDCLK, * which basically means we choose the maximum of old and new CDCLK, if we know both
*/ if (change_cdclk)
cdclk = max(new_cdclk_state->actual.cdclk, old_cdclk_state->actual.cdclk);
/* * According to "Sequence For Pipe Count Change", * if pipe count is increasing, set bits 25:16 to upcoming pipe count * (power well is enabled) * no action if it is decreasing, before the change
*/ if (update_pipe_count)
num_active_pipes = hweight8(new_cdclk_state->active_pipes);
/* * According to "Sequence After Frequency Change", * set bits 25:16 to current CDCLK
*/ if (update_cdclk)
cdclk = new_cdclk_state->actual.cdclk;
/* * According to "Sequence For Pipe Count Change", * if pipe count is decreasing, set bits 25:16 to current pipe count, * after the change(power well is disabled) * no action if it is increasing, after the change
*/ if (update_pipe_count)
num_active_pipes = hweight8(new_cdclk_state->active_pipes);
/** * intel_set_cdclk_pre_plane_update - Push the CDCLK state to the hardware * @state: intel atomic state * * Program the hardware before updating the HW plane state based on the * new CDCLK state, if necessary.
*/ void
intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state)
{ struct intel_display *display = to_intel_display(state); conststruct intel_cdclk_state *old_cdclk_state =
intel_atomic_get_old_cdclk_state(state); conststruct intel_cdclk_state *new_cdclk_state =
intel_atomic_get_new_cdclk_state(state); struct intel_cdclk_config cdclk_config; enum pipe pipe;
if (!intel_cdclk_changed(&old_cdclk_state->actual,
&new_cdclk_state->actual)) return;
if (display->platform.dg2)
intel_cdclk_pcode_pre_notify(state);
/* * mbus joining will be changed later by * intel_dbuf_mbus_{pre,post}_ddb_update()
*/
cdclk_config.joined_mbus = old_cdclk_state->actual.joined_mbus;
/** * intel_set_cdclk_post_plane_update - Push the CDCLK state to the hardware * @state: intel atomic state * * Program the hardware after 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)
{ struct intel_display *display = to_intel_display(state); conststruct intel_cdclk_state *old_cdclk_state =
intel_atomic_get_old_cdclk_state(state); conststruct intel_cdclk_state *new_cdclk_state =
intel_atomic_get_new_cdclk_state(state); enum pipe pipe;
if (!intel_cdclk_changed(&old_cdclk_state->actual,
&new_cdclk_state->actual)) return;
if (display->platform.dg2)
intel_cdclk_pcode_post_notify(state);
/* * Avoid glk_force_audio_cdclk() causing excessive screen * blinking when multiple pipes are active by making sure * CDCLK frequency is always high enough for audio. With a * single active pipe we can always change CDCLK frequency * by changing the cd2x divider (see glk_cdclk_table[]) and * thus a full modeset won't be needed then.
*/ if (display->platform.geminilake && cdclk_state->active_pipes &&
!is_power_of_2(cdclk_state->active_pipes))
min_cdclk = max(min_cdclk, 2 * 96000);
if (min_cdclk > display->cdclk.max_cdclk_freq) {
drm_dbg_kms(display->drm, "required cdclk (%d kHz) exceeds max (%d kHz)\n",
min_cdclk, display->cdclk.max_cdclk_freq); return -EINVAL;
}
return min_cdclk;
}
/* * Account for port clock min voltage level requirements. * This only really does something on DISPLA_VER >= 11 but can be * called on earlier platforms as well. * * Note that this functions assumes that 0 is * the lowest voltage value, and higher values * correspond to increasingly higher voltages. * * Should that relationship no longer hold on * future platforms this code will need to be * adjusted.
*/ staticint bxt_compute_min_voltage_level(struct intel_atomic_state *state)
{ struct intel_display *display = to_intel_display(state); struct intel_cdclk_state *cdclk_state =
intel_atomic_get_new_cdclk_state(state); struct intel_crtc *crtc; struct intel_crtc_state *crtc_state;
u8 min_voltage_level; int i; enum pipe pipe;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { int ret;
if (crtc_state->hw.enable)
min_voltage_level = crtc_state->min_voltage_level; else
min_voltage_level = 0;
if (cdclk_state->min_voltage_level[crtc->pipe] == min_voltage_level) continue;
vco = cdclk_state->logical.vco; if (!vco)
vco = display->cdclk.skl_preferred_vco_freq;
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->hw.enable) continue;
if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) continue;
/* * DPLL0 VCO may need to be adjusted to get the correct * clock for eDP. This will affect cdclk as well.
*/ switch (crtc_state->port_clock / 2) { case 108000: case 216000:
vco = 8640000; break; default:
vco = 8100000; break;
}
}
staticint fixed_modeset_calc_cdclk(struct intel_atomic_state *state)
{ int min_cdclk;
/* * We can't change the cdclk frequency, but we still want to * check that the required minimum frequency doesn't exceed * the actual cdclk frequency.
*/
min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk;
cdclk_state = intel_atomic_get_global_obj_state(state, &display->cdclk.obj); if (IS_ERR(cdclk_state)) return ERR_CAST(cdclk_state);
return to_intel_cdclk_state(cdclk_state);
}
int intel_cdclk_atomic_check(struct intel_atomic_state *state, bool *need_cdclk_calc)
{ conststruct intel_cdclk_state *old_cdclk_state; conststruct intel_cdclk_state *new_cdclk_state; struct intel_plane_state __maybe_unused *plane_state; struct intel_plane *plane; int ret; int i;
/* * active_planes bitmask has been updated, and potentially affected * planes are part of the state. We can now compute the minimum cdclk * for each plane.
*/
for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
ret = intel_plane_calc_min_cdclk(state, plane, need_cdclk_calc); if (ret) return ret;
}
ret = intel_bw_calc_min_cdclk(state, need_cdclk_calc); if (ret) return ret;
ret = intel_cdclk_modeset_calc_cdclk(state); if (ret) return ret;
if (intel_cdclk_need_serialize(display, old_cdclk_state, new_cdclk_state)) { /* * Also serialize commits across all crtcs * if the actual hw needs to be poked.
*/
ret = intel_atomic_serialize_global_state(&new_cdclk_state->base); if (ret) return ret;
} elseif (old_cdclk_state->active_pipes != new_cdclk_state->active_pipes ||
old_cdclk_state->force_min_cdclk != new_cdclk_state->force_min_cdclk ||
intel_cdclk_changed(&old_cdclk_state->logical,
&new_cdclk_state->logical)) {
ret = intel_atomic_lock_global_state(&new_cdclk_state->base); if (ret) return ret;
} else { return 0;
}
crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state);
if (intel_crtc_needs_modeset(crtc_state))
pipe = INVALID_PIPE;
}
if (intel_cdclk_can_crawl_and_squash(display,
&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
drm_dbg_kms(display->drm, "Can change cdclk via crawling and squashing\n");
} elseif (intel_cdclk_can_squash(display,
&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
drm_dbg_kms(display->drm, "Can change cdclk via squashing\n");
} elseif (intel_cdclk_can_crawl(display,
&old_cdclk_state->actual,
&new_cdclk_state->actual)) {
drm_dbg_kms(display->drm, "Can change cdclk via crawling\n");
} elseif (pipe != INVALID_PIPE) {
new_cdclk_state->pipe = pipe;
drm_dbg_kms(display->drm, "Can change cdclk cd2x divider with pipe %c active\n",
pipe_name(pipe));
} elseif (intel_cdclk_clock_changed(&old_cdclk_state->actual,
&new_cdclk_state->actual)) { /* All pipes must be switched off while we change the cdclk. */
ret = intel_modeset_all_pipes_late(state, "CDCLK change"); if (ret) return ret;
new_cdclk_state->disable_pipes = true;
drm_dbg_kms(display->drm, "Modeset required for cdclk change\n");
}
if (intel_mdclk_cdclk_ratio(display, &old_cdclk_state->actual) !=
intel_mdclk_cdclk_ratio(display, &new_cdclk_state->actual)) { int ratio = intel_mdclk_cdclk_ratio(display, &new_cdclk_state->actual);
ret = intel_dbuf_state_set_mdclk_cdclk_ratio(state, ratio); if (ret) return ret;
}
drm_dbg_kms(display->drm, "New cdclk calculated to be logical %u kHz, actual %u kHz\n",
new_cdclk_state->logical.cdclk,
new_cdclk_state->actual.cdclk);
drm_dbg_kms(display->drm, "New voltage level calculated to be logical %u, actual %u\n",
new_cdclk_state->logical.voltage_level,
new_cdclk_state->actual.voltage_level);
/* * Use the lower (vco 8640) cdclk values as a * first guess. skl_calc_cdclk() will correct it * if the preferred vco is 8100 instead.
*/ if (limit == SKL_DFSM_CDCLK_LIMIT_675)
max_cdclk = 617143; elseif (limit == SKL_DFSM_CDCLK_LIMIT_540)
max_cdclk = 540000; elseif (limit == SKL_DFSM_CDCLK_LIMIT_450)
max_cdclk = 432000; else
max_cdclk = 308571;
display->cdclk.max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco);
} elseif (display->platform.broadwell) { /* * FIXME with extra cooling we can allow * 540 MHz for ULX and 675 Mhz for ULT. * How can we know if extra cooling is * available? PCI ID, VTB, something else?
*/ if (intel_de_read(display, FUSE_STRAP) & HSW_CDCLK_LIMIT)
display->cdclk.max_cdclk_freq = 450000; elseif (display->platform.broadwell_ulx)
display->cdclk.max_cdclk_freq = 450000; elseif (display->platform.broadwell_ult)
display->cdclk.max_cdclk_freq = 540000; else
display->cdclk.max_cdclk_freq = 675000;
} elseif (display->platform.cherryview) {
display->cdclk.max_cdclk_freq = 320000;
} elseif (display->platform.valleyview) {
display->cdclk.max_cdclk_freq = 400000;
} else { /* otherwise assume cdclk is fixed */
display->cdclk.max_cdclk_freq = display->cdclk.hw.cdclk;
}
/** * intel_update_cdclk - Determine the current CDCLK frequency * @display: display instance * * Determine the current CDCLK frequency.
*/ void intel_update_cdclk(struct intel_display *display)
{
intel_cdclk_get_cdclk(display, &display->cdclk.hw);
/* * 9:0 CMBUS [sic] CDCLK frequency (cdfreq): * Programmng [sic] note: bit[9:2] should be programmed to the number * of cdclk that generates 4MHz reference clock freq which is used to * generate GMBus clock. This will vary with the cdclk freq.
*/ if (display->platform.valleyview || display->platform.cherryview)
intel_de_write(display, GMBUSFREQ_VLV,
DIV_ROUND_UP(display->cdclk.hw.cdclk, 1000));
}
/* hrawclock is 1/4 the FSB frequency */ return DIV_ROUND_CLOSEST(i9xx_fsb_freq(i915), 4);
}
/** * intel_read_rawclk - Determine the current RAWCLK frequency * @display: display instance * * Determine the current RAWCLK frequency. RAWCLK is a fixed * frequency clock so this needs to done only once.
*/
u32 intel_read_rawclk(struct intel_display *display)
{
u32 freq;
if (INTEL_PCH_TYPE(display) >= PCH_MTL) /* * MTL always uses a 38.4 MHz rawclk. The bspec tells us * "RAWCLK_FREQ defaults to the values for 38.4 and does * not need to be programmed."
*/
freq = 38400; elseif (INTEL_PCH_TYPE(display) >= PCH_DG1)
freq = dg1_rawclk(display); elseif (INTEL_PCH_TYPE(display) >= PCH_CNP)
freq = cnp_rawclk(display); elseif (HAS_PCH_SPLIT(display))
freq = pch_rawclk(display); elseif (display->platform.valleyview || display->platform.cherryview)
freq = vlv_hrawclk(display); elseif (DISPLAY_VER(display) >= 3)
freq = i9xx_hrawclk(display); else /* no rawclk on other platforms, or no need to know it */ return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.