diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_cdclk.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_cdclk.c | 1614 |
1 files changed, 831 insertions, 783 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index f672bfd70d45..c7a603589412 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -21,9 +21,15 @@ * DEALINGS IN THE SOFTWARE. */ +#include <linux/debugfs.h> #include <linux/time.h> +#include <drm/drm_fixed.h> + +#include "soc/intel_dram.h" + #include "hsw_ips.h" +#include "i915_drv.h" #include "i915_reg.h" #include "intel_atomic.h" #include "intel_atomic_plane.h" @@ -32,13 +38,15 @@ #include "intel_cdclk.h" #include "intel_crtc.h" #include "intel_de.h" -#include "intel_dp.h" #include "intel_display_types.h" #include "intel_mchbar_regs.h" #include "intel_pci_config.h" #include "intel_pcode.h" #include "intel_psr.h" #include "intel_vdsc.h" +#include "skl_watermark.h" +#include "skl_watermark_regs.h" +#include "vlv_dsi.h" #include "vlv_sideband.h" /** @@ -63,6 +71,32 @@ * 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: * @@ -80,80 +114,81 @@ */ struct intel_cdclk_funcs { - void (*get_cdclk)(struct drm_i915_private *i915, + void (*get_cdclk)(struct intel_display *display, struct intel_cdclk_config *cdclk_config); - void (*set_cdclk)(struct drm_i915_private *i915, + void (*set_cdclk)(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe); - int (*modeset_calc_cdclk)(struct intel_cdclk_state *state); + int (*modeset_calc_cdclk)(struct intel_atomic_state *state); u8 (*calc_voltage_level)(int cdclk); }; -void intel_cdclk_get_cdclk(struct drm_i915_private *dev_priv, +void intel_cdclk_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - dev_priv->display.funcs.cdclk->get_cdclk(dev_priv, cdclk_config); + display->funcs.cdclk->get_cdclk(display, cdclk_config); } -static void intel_cdclk_set_cdclk(struct drm_i915_private *dev_priv, +static void intel_cdclk_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { - dev_priv->display.funcs.cdclk->set_cdclk(dev_priv, cdclk_config, pipe); + display->funcs.cdclk->set_cdclk(display, cdclk_config, pipe); } -static int intel_cdclk_modeset_calc_cdclk(struct drm_i915_private *dev_priv, - struct intel_cdclk_state *cdclk_config) +static int intel_cdclk_modeset_calc_cdclk(struct intel_atomic_state *state) { - return dev_priv->display.funcs.cdclk->modeset_calc_cdclk(cdclk_config); + struct intel_display *display = to_intel_display(state); + + return display->funcs.cdclk->modeset_calc_cdclk(state); } -static u8 intel_cdclk_calc_voltage_level(struct drm_i915_private *dev_priv, +static u8 intel_cdclk_calc_voltage_level(struct intel_display *display, int cdclk) { - return dev_priv->display.funcs.cdclk->calc_voltage_level(cdclk); + return display->funcs.cdclk->calc_voltage_level(cdclk); } -static void fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_133mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 133333; } -static void fixed_200mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_200mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 200000; } -static void fixed_266mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_266mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 266667; } -static void fixed_333mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_333mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 333333; } -static void fixed_400mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_400mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 400000; } -static void fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv, +static void fixed_450mhz_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { cdclk_config->cdclk = 450000; } -static void i85x_get_cdclk(struct drm_i915_private *dev_priv, +static void i85x_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); u16 hpllcc = 0; /* @@ -192,10 +227,10 @@ static void i85x_get_cdclk(struct drm_i915_private *dev_priv, } } -static void i915gm_get_cdclk(struct drm_i915_private *dev_priv, +static void i915gm_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -216,10 +251,10 @@ static void i915gm_get_cdclk(struct drm_i915_private *dev_priv, } } -static void i945gm_get_cdclk(struct drm_i915_private *dev_priv, +static void i945gm_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -240,7 +275,7 @@ static void i945gm_get_cdclk(struct drm_i915_private *dev_priv, } } -static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv) +static unsigned int intel_hpll_vco(struct intel_display *display) { static const unsigned int blb_vco[8] = { [0] = 3200000, @@ -279,6 +314,7 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv) [4] = 2666667, [5] = 4266667, }; + struct drm_i915_private *dev_priv = to_i915(display->drm); const unsigned int *vco_table; unsigned int vco; u8 tmp = 0; @@ -297,23 +333,23 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv) else return 0; - tmp = intel_de_read(dev_priv, + tmp = intel_de_read(display, IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv) ? HPLLVCO_MOBILE : HPLLVCO); vco = vco_table[tmp & 0x7]; if (vco == 0) - drm_err(&dev_priv->drm, "Bad HPLL VCO (HPLLVCO=0x%02x)\n", + drm_err(display->drm, "Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp); else - drm_dbg_kms(&dev_priv->drm, "HPLL VCO %u kHz\n", vco); + drm_dbg_kms(display->drm, "HPLL VCO %u kHz\n", vco); return vco; } -static void g33_get_cdclk(struct drm_i915_private *dev_priv, +static void g33_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); static const u8 div_3200[] = { 12, 10, 8, 7, 5, 16 }; static const u8 div_4000[] = { 14, 12, 10, 8, 6, 20 }; static const u8 div_4800[] = { 20, 14, 12, 10, 8, 24 }; @@ -322,7 +358,7 @@ static void g33_get_cdclk(struct drm_i915_private *dev_priv, unsigned int cdclk_sel; u16 tmp = 0; - cdclk_config->vco = intel_hpll_vco(dev_priv); + cdclk_config->vco = intel_hpll_vco(display); pci_read_config_word(pdev, GCFGC, &tmp); @@ -353,16 +389,16 @@ static void g33_get_cdclk(struct drm_i915_private *dev_priv, return; fail: - drm_err(&dev_priv->drm, + drm_err(display->drm, "Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", cdclk_config->vco, tmp); cdclk_config->cdclk = 190476; } -static void pnv_get_cdclk(struct drm_i915_private *dev_priv, +static void pnv_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -381,7 +417,7 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv, cdclk_config->cdclk = 200000; break; default: - drm_err(&dev_priv->drm, + drm_err(display->drm, "Unknown pnv display core clock 0x%04x\n", gcfgc); fallthrough; case GC_DISPLAY_CLOCK_133_MHZ_PNV: @@ -393,10 +429,10 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv, } } -static void i965gm_get_cdclk(struct drm_i915_private *dev_priv, +static void i965gm_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); static const u8 div_3200[] = { 16, 10, 8 }; static const u8 div_4000[] = { 20, 12, 10 }; static const u8 div_5333[] = { 24, 16, 14 }; @@ -404,7 +440,7 @@ static void i965gm_get_cdclk(struct drm_i915_private *dev_priv, unsigned int cdclk_sel; u16 tmp = 0; - cdclk_config->vco = intel_hpll_vco(dev_priv); + cdclk_config->vco = intel_hpll_vco(display); pci_read_config_word(pdev, GCFGC, &tmp); @@ -432,20 +468,20 @@ static void i965gm_get_cdclk(struct drm_i915_private *dev_priv, return; fail: - drm_err(&dev_priv->drm, + drm_err(display->drm, "Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", cdclk_config->vco, tmp); cdclk_config->cdclk = 200000; } -static void gm45_get_cdclk(struct drm_i915_private *dev_priv, +static void gm45_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + struct pci_dev *pdev = to_pci_dev(display->drm->dev); unsigned int cdclk_sel; u16 tmp = 0; - cdclk_config->vco = intel_hpll_vco(dev_priv); + cdclk_config->vco = intel_hpll_vco(display); pci_read_config_word(pdev, GCFGC, &tmp); @@ -461,7 +497,7 @@ static void gm45_get_cdclk(struct drm_i915_private *dev_priv, cdclk_config->cdclk = cdclk_sel ? 320000 : 228571; break; default: - drm_err(&dev_priv->drm, + drm_err(display->drm, "Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", cdclk_config->vco, tmp); cdclk_config->cdclk = 222222; @@ -469,15 +505,16 @@ static void gm45_get_cdclk(struct drm_i915_private *dev_priv, } } -static void hsw_get_cdclk(struct drm_i915_private *dev_priv, +static void hsw_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - u32 lcpll = intel_de_read(dev_priv, LCPLL_CTL); + struct drm_i915_private *dev_priv = to_i915(display->drm); + u32 lcpll = intel_de_read(display, LCPLL_CTL); u32 freq = lcpll & LCPLL_CLK_FREQ_MASK; if (lcpll & LCPLL_CD_SOURCE_FCLK) cdclk_config->cdclk = 800000; - else if (intel_de_read(dev_priv, FUSE_STRAP) & HSW_CDCLK_LIMIT) + else if (intel_de_read(display, FUSE_STRAP) & HSW_CDCLK_LIMIT) cdclk_config->cdclk = 450000; else if (freq == LCPLL_CLK_FREQ_450) cdclk_config->cdclk = 450000; @@ -487,8 +524,9 @@ static void hsw_get_cdclk(struct drm_i915_private *dev_priv, cdclk_config->cdclk = 540000; } -static int vlv_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) +static int vlv_calc_cdclk(struct intel_display *display, int min_cdclk) { + struct drm_i915_private *dev_priv = to_i915(display->drm); int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ? 333333 : 320000; @@ -507,8 +545,10 @@ static int vlv_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) return 200000; } -static u8 vlv_calc_voltage_level(struct drm_i915_private *dev_priv, int cdclk) +static u8 vlv_calc_voltage_level(struct intel_display *display, int cdclk) { + struct drm_i915_private *dev_priv = to_i915(display->drm); + if (IS_VALLEYVIEW(dev_priv)) { if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */ return 2; @@ -526,9 +566,10 @@ static u8 vlv_calc_voltage_level(struct drm_i915_private *dev_priv, int cdclk) } } -static void vlv_get_cdclk(struct drm_i915_private *dev_priv, +static void vlv_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { + struct drm_i915_private *dev_priv = to_i915(display->drm); u32 val; vlv_iosf_sb_get(dev_priv, @@ -552,8 +593,9 @@ static void vlv_get_cdclk(struct drm_i915_private *dev_priv, DSPFREQGUAR_SHIFT_CHV; } -static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) +static void vlv_program_pfi_credits(struct intel_display *display) { + struct drm_i915_private *dev_priv = to_i915(display->drm); unsigned int credits, default_credits; if (IS_CHERRYVIEW(dev_priv)) @@ -561,7 +603,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) else default_credits = PFI_CREDIT(8); - if (dev_priv->display.cdclk.hw.cdclk >= dev_priv->czclk_freq) { + if (display->cdclk.hw.cdclk >= dev_priv->czclk_freq) { /* CHV suggested value is 31 or 63 */ if (IS_CHERRYVIEW(dev_priv)) credits = PFI_CREDIT_63; @@ -575,24 +617,25 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) * WA - write default credits before re-programming * FIXME: should we also set the resend bit here? */ - intel_de_write(dev_priv, GCI_CONTROL, + intel_de_write(display, GCI_CONTROL, VGA_FAST_MODE_DISABLE | default_credits); - intel_de_write(dev_priv, GCI_CONTROL, + intel_de_write(display, GCI_CONTROL, VGA_FAST_MODE_DISABLE | credits | PFI_CREDIT_RESEND); /* * FIXME is this guaranteed to clear * immediately or should we poll for it? */ - drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, GCI_CONTROL) & PFI_CREDIT_RESEND); + drm_WARN_ON(display->drm, + intel_de_read(display, GCI_CONTROL) & PFI_CREDIT_RESEND); } -static void vlv_set_cdclk(struct drm_i915_private *dev_priv, +static void vlv_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; u32 val, cmd = cdclk_config->voltage_level; intel_wakeref_t wakeref; @@ -629,7 +672,7 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv, if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM) & DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), 50)) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "timed out waiting for CDclk change\n"); } @@ -648,7 +691,7 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv, if (wait_for((vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL) & CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT), 50)) - drm_err(&dev_priv->drm, + drm_err(display->drm, "timed out waiting for CDclk change\n"); } @@ -671,17 +714,18 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv, BIT(VLV_IOSF_SB_BUNIT) | BIT(VLV_IOSF_SB_PUNIT)); - intel_update_cdclk(dev_priv); + intel_update_cdclk(display); - vlv_program_pfi_credits(dev_priv); + vlv_program_pfi_credits(display); intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); } -static void chv_set_cdclk(struct drm_i915_private *dev_priv, +static void chv_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; u32 val, cmd = cdclk_config->voltage_level; intel_wakeref_t wakeref; @@ -713,15 +757,15 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv, if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPSSPM) & DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV), 50)) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "timed out waiting for CDclk change\n"); } vlv_punit_put(dev_priv); - intel_update_cdclk(dev_priv); + intel_update_cdclk(display); - vlv_program_pfi_credits(dev_priv); + vlv_program_pfi_credits(display); intel_display_power_put(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref); } @@ -753,15 +797,15 @@ static u8 bdw_calc_voltage_level(int cdclk) } } -static void bdw_get_cdclk(struct drm_i915_private *dev_priv, +static void bdw_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - u32 lcpll = intel_de_read(dev_priv, LCPLL_CTL); + u32 lcpll = intel_de_read(display, LCPLL_CTL); u32 freq = lcpll & LCPLL_CLK_FREQ_MASK; if (lcpll & LCPLL_CD_SOURCE_FCLK) cdclk_config->cdclk = 800000; - else if (intel_de_read(dev_priv, FUSE_STRAP) & HSW_CDCLK_LIMIT) + else if (intel_de_read(display, FUSE_STRAP) & HSW_CDCLK_LIMIT) cdclk_config->cdclk = 450000; else if (freq == LCPLL_CLK_FREQ_450) cdclk_config->cdclk = 450000; @@ -797,15 +841,16 @@ static u32 bdw_cdclk_freq_sel(int cdclk) } } -static void bdw_set_cdclk(struct drm_i915_private *dev_priv, +static void bdw_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; int ret; - if (drm_WARN(&dev_priv->drm, - (intel_de_read(dev_priv, LCPLL_CTL) & + 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 | @@ -815,39 +860,39 @@ static void bdw_set_cdclk(struct drm_i915_private *dev_priv, ret = snb_pcode_write(&dev_priv->uncore, BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); if (ret) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "failed to inform pcode about cdclk change\n"); return; } - intel_de_rmw(dev_priv, LCPLL_CTL, + intel_de_rmw(display, LCPLL_CTL, 0, LCPLL_CD_SOURCE_FCLK); /* * 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(dev_priv, LCPLL_CTL) & + if (wait_for_us(intel_de_read(display, LCPLL_CTL) & LCPLL_CD_SOURCE_FCLK_DONE, 100)) - drm_err(&dev_priv->drm, "Switching to FCLK failed\n"); + drm_err(display->drm, "Switching to FCLK failed\n"); - intel_de_rmw(dev_priv, LCPLL_CTL, + intel_de_rmw(display, LCPLL_CTL, LCPLL_CLK_FREQ_MASK, bdw_cdclk_freq_sel(cdclk)); - intel_de_rmw(dev_priv, LCPLL_CTL, + intel_de_rmw(display, LCPLL_CTL, LCPLL_CD_SOURCE_FCLK, 0); - if (wait_for_us((intel_de_read(dev_priv, LCPLL_CTL) & + if (wait_for_us((intel_de_read(display, LCPLL_CTL) & LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) - drm_err(&dev_priv->drm, "Switching back to LCPLL failed\n"); + drm_err(display->drm, "Switching back to LCPLL failed\n"); snb_pcode_write(&dev_priv->uncore, HSW_PCODE_DE_WRITE_FREQ_REQ, cdclk_config->voltage_level); - intel_de_write(dev_priv, CDCLK_FREQ, + intel_de_write(display, CDCLK_FREQ, DIV_ROUND_CLOSEST(cdclk, 1000) - 1); - intel_update_cdclk(dev_priv); + intel_update_cdclk(display); } static int skl_calc_cdclk(int min_cdclk, int vco) @@ -885,7 +930,7 @@ static u8 skl_calc_voltage_level(int cdclk) return 0; } -static void skl_dpll0_update(struct drm_i915_private *dev_priv, +static void skl_dpll0_update(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { u32 val; @@ -893,16 +938,16 @@ static void skl_dpll0_update(struct drm_i915_private *dev_priv, cdclk_config->ref = 24000; cdclk_config->vco = 0; - val = intel_de_read(dev_priv, LCPLL1_CTL); + val = intel_de_read(display, LCPLL1_CTL); if ((val & LCPLL_PLL_ENABLE) == 0) return; - if (drm_WARN_ON(&dev_priv->drm, (val & LCPLL_PLL_LOCK) == 0)) + if (drm_WARN_ON(display->drm, (val & LCPLL_PLL_LOCK) == 0)) return; - val = intel_de_read(dev_priv, DPLL_CTRL1); + val = intel_de_read(display, DPLL_CTRL1); - if (drm_WARN_ON(&dev_priv->drm, + if (drm_WARN_ON(display->drm, (val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) | DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) != @@ -926,19 +971,19 @@ static void skl_dpll0_update(struct drm_i915_private *dev_priv, } } -static void skl_get_cdclk(struct drm_i915_private *dev_priv, +static void skl_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { u32 cdctl; - skl_dpll0_update(dev_priv, cdclk_config); + skl_dpll0_update(display, cdclk_config); cdclk_config->cdclk = cdclk_config->bypass = cdclk_config->ref; if (cdclk_config->vco == 0) goto out; - cdctl = intel_de_read(dev_priv, CDCLK_CTL); + cdctl = intel_de_read(display, CDCLK_CTL); if (cdclk_config->vco == 8640000) { switch (cdctl & CDCLK_FREQ_SEL_MASK) { @@ -993,20 +1038,19 @@ static int skl_cdclk_decimal(int cdclk) return DIV_ROUND_CLOSEST(cdclk - 1000, 500); } -static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, - int vco) +static void skl_set_preferred_cdclk_vco(struct intel_display *display, int vco) { - bool changed = dev_priv->skl_preferred_vco_freq != vco; + bool changed = display->cdclk.skl_preferred_vco_freq != vco; - dev_priv->skl_preferred_vco_freq = vco; + display->cdclk.skl_preferred_vco_freq = vco; if (changed) - intel_update_max_cdclk(dev_priv); + intel_update_max_cdclk(display); } -static u32 skl_dpll0_link_rate(struct drm_i915_private *dev_priv, int vco) +static u32 skl_dpll0_link_rate(struct intel_display *display, int vco) { - drm_WARN_ON(&dev_priv->drm, vco != 8100000 && vco != 8640000); + drm_WARN_ON(display->drm, vco != 8100000 && vco != 8640000); /* * We always enable DPLL0 with the lowest link rate possible, but still @@ -1023,47 +1067,47 @@ static u32 skl_dpll0_link_rate(struct drm_i915_private *dev_priv, int vco) return DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0); } -static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco) +static void skl_dpll0_enable(struct intel_display *display, int vco) { - intel_de_rmw(dev_priv, DPLL_CTRL1, + intel_de_rmw(display, DPLL_CTRL1, DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) | DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0), DPLL_CTRL1_OVERRIDE(SKL_DPLL0) | - skl_dpll0_link_rate(dev_priv, vco)); - intel_de_posting_read(dev_priv, DPLL_CTRL1); + skl_dpll0_link_rate(display, vco)); + intel_de_posting_read(display, DPLL_CTRL1); - intel_de_rmw(dev_priv, LCPLL1_CTL, + intel_de_rmw(display, LCPLL1_CTL, 0, LCPLL_PLL_ENABLE); - if (intel_de_wait_for_set(dev_priv, LCPLL1_CTL, LCPLL_PLL_LOCK, 5)) - drm_err(&dev_priv->drm, "DPLL0 not locked\n"); + if (intel_de_wait_for_set(display, LCPLL1_CTL, LCPLL_PLL_LOCK, 5)) + drm_err(display->drm, "DPLL0 not locked\n"); - dev_priv->display.cdclk.hw.vco = vco; + display->cdclk.hw.vco = vco; /* We'll want to keep using the current vco from now on. */ - skl_set_preferred_cdclk_vco(dev_priv, vco); + skl_set_preferred_cdclk_vco(display, vco); } -static void skl_dpll0_disable(struct drm_i915_private *dev_priv) +static void skl_dpll0_disable(struct intel_display *display) { - intel_de_rmw(dev_priv, LCPLL1_CTL, + intel_de_rmw(display, LCPLL1_CTL, LCPLL_PLL_ENABLE, 0); - if (intel_de_wait_for_clear(dev_priv, LCPLL1_CTL, LCPLL_PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "Couldn't disable DPLL0\n"); + if (intel_de_wait_for_clear(display, LCPLL1_CTL, LCPLL_PLL_LOCK, 1)) + drm_err(display->drm, "Couldn't disable DPLL0\n"); - dev_priv->display.cdclk.hw.vco = 0; + display->cdclk.hw.vco = 0; } -static u32 skl_cdclk_freq_sel(struct drm_i915_private *dev_priv, +static u32 skl_cdclk_freq_sel(struct intel_display *display, int cdclk, int vco) { switch (cdclk) { default: - drm_WARN_ON(&dev_priv->drm, - cdclk != dev_priv->display.cdclk.hw.bypass); - drm_WARN_ON(&dev_priv->drm, vco != 0); + drm_WARN_ON(display->drm, + cdclk != display->cdclk.hw.bypass); + drm_WARN_ON(display->drm, vco != 0); fallthrough; case 308571: case 337500: @@ -1079,10 +1123,11 @@ static u32 skl_cdclk_freq_sel(struct drm_i915_private *dev_priv, } } -static void skl_set_cdclk(struct drm_i915_private *dev_priv, +static void skl_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *dev_priv = to_i915(display->drm); int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; u32 freq_select, cdclk_ctl; @@ -1096,7 +1141,7 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, * use the corresponding VCO freq as that always leads to using the * minimum 308MHz CDCLK. */ - drm_WARN_ON_ONCE(&dev_priv->drm, + drm_WARN_ON_ONCE(display->drm, IS_SKYLAKE(dev_priv) && vco == 8640000); ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, @@ -1104,54 +1149,54 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, SKL_CDCLK_READY_FOR_CHANGE, SKL_CDCLK_READY_FOR_CHANGE, 3); if (ret) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "Failed to inform PCU about cdclk change (%d)\n", ret); return; } - freq_select = skl_cdclk_freq_sel(dev_priv, cdclk, vco); + freq_select = skl_cdclk_freq_sel(display, cdclk, vco); - if (dev_priv->display.cdclk.hw.vco != 0 && - dev_priv->display.cdclk.hw.vco != vco) - skl_dpll0_disable(dev_priv); + if (display->cdclk.hw.vco != 0 && + display->cdclk.hw.vco != vco) + skl_dpll0_disable(display); - cdclk_ctl = intel_de_read(dev_priv, CDCLK_CTL); + cdclk_ctl = intel_de_read(display, CDCLK_CTL); - if (dev_priv->display.cdclk.hw.vco != vco) { + if (display->cdclk.hw.vco != vco) { /* Wa Display #1183: skl,kbl,cfl */ cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); - intel_de_write(dev_priv, CDCLK_CTL, cdclk_ctl); + intel_de_write(display, CDCLK_CTL, cdclk_ctl); } /* Wa Display #1183: skl,kbl,cfl */ cdclk_ctl |= CDCLK_DIVMUX_CD_OVERRIDE; - intel_de_write(dev_priv, CDCLK_CTL, cdclk_ctl); - intel_de_posting_read(dev_priv, CDCLK_CTL); + intel_de_write(display, CDCLK_CTL, cdclk_ctl); + intel_de_posting_read(display, CDCLK_CTL); - if (dev_priv->display.cdclk.hw.vco != vco) - skl_dpll0_enable(dev_priv, vco); + if (display->cdclk.hw.vco != vco) + skl_dpll0_enable(display, vco); /* Wa Display #1183: skl,kbl,cfl */ cdclk_ctl &= ~(CDCLK_FREQ_SEL_MASK | CDCLK_FREQ_DECIMAL_MASK); - intel_de_write(dev_priv, CDCLK_CTL, cdclk_ctl); + intel_de_write(display, CDCLK_CTL, cdclk_ctl); cdclk_ctl |= freq_select | skl_cdclk_decimal(cdclk); - intel_de_write(dev_priv, CDCLK_CTL, cdclk_ctl); + intel_de_write(display, CDCLK_CTL, cdclk_ctl); /* Wa Display #1183: skl,kbl,cfl */ cdclk_ctl &= ~CDCLK_DIVMUX_CD_OVERRIDE; - intel_de_write(dev_priv, CDCLK_CTL, cdclk_ctl); - intel_de_posting_read(dev_priv, CDCLK_CTL); + intel_de_write(display, CDCLK_CTL, cdclk_ctl); + intel_de_posting_read(display, CDCLK_CTL); /* inform PCU of the change */ snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, cdclk_config->voltage_level); - intel_update_cdclk(dev_priv); + intel_update_cdclk(display); } -static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) +static void skl_sanitize_cdclk(struct intel_display *display) { u32 cdctl, expected; @@ -1160,15 +1205,15 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) * 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(dev_priv, SWF_ILK(0x18)) & 0x00FFFFFF) == 0) + if ((intel_de_read(display, SWF_ILK(0x18)) & 0x00FFFFFF) == 0) goto sanitize; - intel_update_cdclk(dev_priv); - intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "Current CDCLK"); + intel_update_cdclk(display); + intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); /* Is PLL enabled and locked ? */ - if (dev_priv->display.cdclk.hw.vco == 0 || - dev_priv->display.cdclk.hw.cdclk == dev_priv->display.cdclk.hw.bypass) + if (display->cdclk.hw.vco == 0 || + display->cdclk.hw.cdclk == display->cdclk.hw.bypass) goto sanitize; /* DPLL okay; verify the cdclock @@ -1177,60 +1222,60 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv) * decimal part is programmed wrong from BIOS where pre-os does not * enable display. Verify the same as well. */ - cdctl = intel_de_read(dev_priv, CDCLK_CTL); + cdctl = intel_de_read(display, CDCLK_CTL); expected = (cdctl & CDCLK_FREQ_SEL_MASK) | - skl_cdclk_decimal(dev_priv->display.cdclk.hw.cdclk); + skl_cdclk_decimal(display->cdclk.hw.cdclk); if (cdctl == expected) /* All well; nothing to sanitize */ return; sanitize: - drm_dbg_kms(&dev_priv->drm, "Sanitizing cdclk programmed by pre-os\n"); + drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n"); /* force cdclk programming */ - dev_priv->display.cdclk.hw.cdclk = 0; + display->cdclk.hw.cdclk = 0; /* force full PLL disable + enable */ - dev_priv->display.cdclk.hw.vco = ~0; + display->cdclk.hw.vco = ~0; } -static void skl_cdclk_init_hw(struct drm_i915_private *dev_priv) +static void skl_cdclk_init_hw(struct intel_display *display) { struct intel_cdclk_config cdclk_config; - skl_sanitize_cdclk(dev_priv); + skl_sanitize_cdclk(display); - if (dev_priv->display.cdclk.hw.cdclk != 0 && - dev_priv->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 (dev_priv->skl_preferred_vco_freq == 0) - skl_set_preferred_cdclk_vco(dev_priv, - dev_priv->display.cdclk.hw.vco); + if (display->cdclk.skl_preferred_vco_freq == 0) + skl_set_preferred_cdclk_vco(display, + display->cdclk.hw.vco); return; } - cdclk_config = dev_priv->display.cdclk.hw; + cdclk_config = display->cdclk.hw; - cdclk_config.vco = dev_priv->skl_preferred_vco_freq; + cdclk_config.vco = display->cdclk.skl_preferred_vco_freq; if (cdclk_config.vco == 0) cdclk_config.vco = 8100000; cdclk_config.cdclk = skl_calc_cdclk(0, cdclk_config.vco); cdclk_config.voltage_level = skl_calc_voltage_level(cdclk_config.cdclk); - skl_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); + skl_set_cdclk(display, &cdclk_config, INVALID_PIPE); } -static void skl_cdclk_uninit_hw(struct drm_i915_private *dev_priv) +static void skl_cdclk_uninit_hw(struct intel_display *display) { - struct intel_cdclk_config cdclk_config = dev_priv->display.cdclk.hw; + struct intel_cdclk_config cdclk_config = display->cdclk.hw; cdclk_config.cdclk = cdclk_config.bypass; cdclk_config.vco = 0; cdclk_config.voltage_level = skl_calc_voltage_level(cdclk_config.cdclk); - skl_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); + skl_set_cdclk(display, &cdclk_config, INVALID_PIPE); } struct intel_cdclk_vals { @@ -1391,7 +1436,7 @@ static const struct intel_cdclk_vals mtl_cdclk_table[] = { {} }; -static const struct intel_cdclk_vals lnl_cdclk_table[] = { +static const struct intel_cdclk_vals xe2lpd_cdclk_table[] = { { .refclk = 38400, .cdclk = 153600, .ratio = 16, .waveform = 0xaaaa }, { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, @@ -1416,6 +1461,47 @@ static const struct intel_cdclk_vals lnl_cdclk_table[] = { {} }; +/* + * Xe2_HPD always uses the minimal cdclk table from Wa_15015413771 + */ +static const struct intel_cdclk_vals xe2hpd_cdclk_table[] = { + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, + {} +}; + +static const struct intel_cdclk_vals xe3lpd_cdclk_table[] = { + { .refclk = 38400, .cdclk = 153600, .ratio = 16, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 172800, .ratio = 16, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 192000, .ratio = 16, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 211200, .ratio = 16, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 230400, .ratio = 16, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 249600, .ratio = 16, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 268800, .ratio = 16, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 288000, .ratio = 16, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 307200, .ratio = 16, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 326400, .ratio = 17, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 345600, .ratio = 18, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 364800, .ratio = 19, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 384000, .ratio = 20, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 403200, .ratio = 21, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 422400, .ratio = 22, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 441600, .ratio = 23, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 460800, .ratio = 24, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 499200, .ratio = 26, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 518400, .ratio = 27, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 537600, .ratio = 28, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 576000, .ratio = 30, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 595200, .ratio = 31, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 614400, .ratio = 32, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 633600, .ratio = 33, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 672000, .ratio = 35, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 691200, .ratio = 36, .waveform = 0xffff }, + {} +}; + static const int cdclk_squash_len = 16; static int cdclk_squash_divider(u16 waveform) @@ -1430,37 +1516,37 @@ static int cdclk_divider(int cdclk, int vco, u16 waveform) cdclk * cdclk_squash_len); } -static int bxt_calc_cdclk(struct drm_i915_private *dev_priv, int min_cdclk) +static int bxt_calc_cdclk(struct intel_display *display, int min_cdclk) { - const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table; + const struct intel_cdclk_vals *table = display->cdclk.table; int i; for (i = 0; table[i].refclk; i++) - if (table[i].refclk == dev_priv->display.cdclk.hw.ref && + if (table[i].refclk == display->cdclk.hw.ref && table[i].cdclk >= min_cdclk) return table[i].cdclk; - drm_WARN(&dev_priv->drm, 1, + drm_WARN(display->drm, 1, "Cannot satisfy minimum cdclk %d with refclk %u\n", - min_cdclk, dev_priv->display.cdclk.hw.ref); + min_cdclk, display->cdclk.hw.ref); return 0; } -static int bxt_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk) +static int bxt_calc_cdclk_pll_vco(struct intel_display *display, int cdclk) { - const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table; + const struct intel_cdclk_vals *table = display->cdclk.table; int i; - if (cdclk == dev_priv->display.cdclk.hw.bypass) + if (cdclk == display->cdclk.hw.bypass) return 0; for (i = 0; table[i].refclk; i++) - if (table[i].refclk == dev_priv->display.cdclk.hw.ref && + if (table[i].refclk == display->cdclk.hw.ref && table[i].cdclk == cdclk) - return dev_priv->display.cdclk.hw.ref * table[i].ratio; + return display->cdclk.hw.ref * table[i].ratio; - drm_WARN(&dev_priv->drm, 1, "cdclk %d not valid for refclk %u\n", - cdclk, dev_priv->display.cdclk.hw.ref); + drm_WARN(display->drm, 1, "cdclk %d not valid for refclk %u\n", + cdclk, display->cdclk.hw.ref); return 0; } @@ -1542,10 +1628,20 @@ static u8 rplu_calc_voltage_level(int cdclk) rplu_voltage_level_max_cdclk); } -static void icl_readout_refclk(struct drm_i915_private *dev_priv, +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; +} + +static void icl_readout_refclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { - u32 dssm = intel_de_read(dev_priv, SKL_DSSM) & ICL_DSSM_CDCLK_PLL_REFCLK_MASK; + u32 dssm = intel_de_read(display, SKL_DSSM) & ICL_DSSM_CDCLK_PLL_REFCLK_MASK; switch (dssm) { default: @@ -1563,19 +1659,20 @@ static void icl_readout_refclk(struct drm_i915_private *dev_priv, } } -static void bxt_de_pll_readout(struct drm_i915_private *dev_priv, +static void bxt_de_pll_readout(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { + struct drm_i915_private *dev_priv = to_i915(display->drm); u32 val, ratio; if (IS_DG2(dev_priv)) cdclk_config->ref = 38400; - else if (DISPLAY_VER(dev_priv) >= 11) - icl_readout_refclk(dev_priv, cdclk_config); + else if (DISPLAY_VER(display) >= 11) + icl_readout_refclk(display, cdclk_config); else cdclk_config->ref = 19200; - val = intel_de_read(dev_priv, BXT_DE_PLL_ENABLE); + val = intel_de_read(display, BXT_DE_PLL_ENABLE); if ((val & BXT_DE_PLL_PLL_ENABLE) == 0 || (val & BXT_DE_PLL_LOCK) == 0) { /* @@ -1590,26 +1687,26 @@ static void bxt_de_pll_readout(struct drm_i915_private *dev_priv, * DISPLAY_VER >= 11 have the ratio directly in the PLL enable register, * gen9lp had it in a separate PLL control register. */ - if (DISPLAY_VER(dev_priv) >= 11) + if (DISPLAY_VER(display) >= 11) ratio = val & ICL_CDCLK_PLL_RATIO_MASK; else - ratio = intel_de_read(dev_priv, BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK; + ratio = intel_de_read(display, BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK; cdclk_config->vco = ratio * cdclk_config->ref; } -static void bxt_get_cdclk(struct drm_i915_private *dev_priv, +static void bxt_get_cdclk(struct intel_display *display, struct intel_cdclk_config *cdclk_config) { u32 squash_ctl = 0; u32 divider; int div; - bxt_de_pll_readout(dev_priv, cdclk_config); + bxt_de_pll_readout(display, cdclk_config); - if (DISPLAY_VER(dev_priv) >= 12) + if (DISPLAY_VER(display) >= 12) cdclk_config->bypass = cdclk_config->ref / 2; - else if (DISPLAY_VER(dev_priv) >= 11) + else if (DISPLAY_VER(display) >= 11) cdclk_config->bypass = 50000; else cdclk_config->bypass = cdclk_config->ref; @@ -1619,7 +1716,7 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, goto out; } - divider = intel_de_read(dev_priv, CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK; + divider = intel_de_read(display, CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK; switch (divider) { case BXT_CDCLK_CD2X_DIV_SEL_1: @@ -1639,8 +1736,8 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, return; } - if (HAS_CDCLK_SQUASH(dev_priv)) - squash_ctl = intel_de_read(dev_priv, CDCLK_SQUASH_CTL); + if (HAS_CDCLK_SQUASH(display)) + squash_ctl = intel_de_read(display, CDCLK_SQUASH_CTL); if (squash_ctl & CDCLK_SQUASH_ENABLE) { u16 waveform; @@ -1656,105 +1753,107 @@ static void bxt_get_cdclk(struct drm_i915_private *dev_priv, } 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(dev_priv, cdclk_config->cdclk); + intel_cdclk_calc_voltage_level(display, cdclk_config->cdclk); } -static void bxt_de_pll_disable(struct drm_i915_private *dev_priv) +static void bxt_de_pll_disable(struct intel_display *display) { - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, 0); + intel_de_write(display, BXT_DE_PLL_ENABLE, 0); /* Timeout 200us */ - if (intel_de_wait_for_clear(dev_priv, + if (intel_de_wait_for_clear(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "timeout waiting for DE PLL unlock\n"); + drm_err(display->drm, "timeout waiting for DE PLL unlock\n"); - dev_priv->display.cdclk.hw.vco = 0; + display->cdclk.hw.vco = 0; } -static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco) +static void bxt_de_pll_enable(struct intel_display *display, int vco) { - int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->display.cdclk.hw.ref); + int ratio = DIV_ROUND_CLOSEST(vco, display->cdclk.hw.ref); - intel_de_rmw(dev_priv, BXT_DE_PLL_CTL, + intel_de_rmw(display, BXT_DE_PLL_CTL, BXT_DE_PLL_RATIO_MASK, BXT_DE_PLL_RATIO(ratio)); - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); + intel_de_write(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE); /* Timeout 200us */ - if (intel_de_wait_for_set(dev_priv, + if (intel_de_wait_for_set(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "timeout waiting for DE PLL lock\n"); + drm_err(display->drm, "timeout waiting for DE PLL lock\n"); - dev_priv->display.cdclk.hw.vco = vco; + display->cdclk.hw.vco = vco; } -static void icl_cdclk_pll_disable(struct drm_i915_private *dev_priv) +static void icl_cdclk_pll_disable(struct intel_display *display) { - intel_de_rmw(dev_priv, BXT_DE_PLL_ENABLE, + intel_de_rmw(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE, 0); /* Timeout 200us */ - if (intel_de_wait_for_clear(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "timeout waiting for CDCLK PLL unlock\n"); + if (intel_de_wait_for_clear(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) + drm_err(display->drm, "timeout waiting for CDCLK PLL unlock\n"); - dev_priv->display.cdclk.hw.vco = 0; + display->cdclk.hw.vco = 0; } -static void icl_cdclk_pll_enable(struct drm_i915_private *dev_priv, int vco) +static void icl_cdclk_pll_enable(struct intel_display *display, int vco) { - int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->display.cdclk.hw.ref); + int ratio = DIV_ROUND_CLOSEST(vco, display->cdclk.hw.ref); u32 val; val = ICL_CDCLK_PLL_RATIO(ratio); - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_write(display, BXT_DE_PLL_ENABLE, val); val |= BXT_DE_PLL_PLL_ENABLE; - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_write(display, BXT_DE_PLL_ENABLE, val); /* Timeout 200us */ - if (intel_de_wait_for_set(dev_priv, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) - drm_err(&dev_priv->drm, "timeout waiting for CDCLK PLL lock\n"); + if (intel_de_wait_for_set(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 1)) + drm_err(display->drm, "timeout waiting for CDCLK PLL lock\n"); - dev_priv->display.cdclk.hw.vco = vco; + display->cdclk.hw.vco = vco; } -static void adlp_cdclk_pll_crawl(struct drm_i915_private *dev_priv, int vco) +static void adlp_cdclk_pll_crawl(struct intel_display *display, int vco) { - int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->display.cdclk.hw.ref); + int ratio = DIV_ROUND_CLOSEST(vco, display->cdclk.hw.ref); u32 val; /* Write PLL ratio without disabling */ val = ICL_CDCLK_PLL_RATIO(ratio) | BXT_DE_PLL_PLL_ENABLE; - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_write(display, BXT_DE_PLL_ENABLE, val); /* Submit freq change request */ val |= BXT_DE_PLL_FREQ_REQ; - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_write(display, BXT_DE_PLL_ENABLE, val); /* Timeout 200us */ - if (intel_de_wait_for_set(dev_priv, BXT_DE_PLL_ENABLE, + if (intel_de_wait_for_set(display, BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK | BXT_DE_PLL_FREQ_REQ_ACK, 1)) - drm_err(&dev_priv->drm, "timeout waiting for FREQ change request ack\n"); + drm_err(display->drm, "timeout waiting for FREQ change request ack\n"); val &= ~BXT_DE_PLL_FREQ_REQ; - intel_de_write(dev_priv, BXT_DE_PLL_ENABLE, val); + intel_de_write(display, BXT_DE_PLL_ENABLE, val); - dev_priv->display.cdclk.hw.vco = vco; + display->cdclk.hw.vco = vco; } -static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) +static u32 bxt_cdclk_cd2x_pipe(struct intel_display *display, enum pipe pipe) { - if (DISPLAY_VER(dev_priv) >= 12) { + if (DISPLAY_VER(display) >= 12) { if (pipe == INVALID_PIPE) return TGL_CDCLK_CD2X_PIPE_NONE; else return TGL_CDCLK_CD2X_PIPE(pipe); - } else if (DISPLAY_VER(dev_priv) >= 11) { + } else if (DISPLAY_VER(display) >= 11) { if (pipe == INVALID_PIPE) return ICL_CDCLK_CD2X_PIPE_NONE; else @@ -1767,15 +1866,15 @@ static u32 bxt_cdclk_cd2x_pipe(struct drm_i915_private *dev_priv, enum pipe pipe } } -static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv, +static u32 bxt_cdclk_cd2x_div_sel(struct intel_display *display, int cdclk, int vco, u16 waveform) { /* cdclk = vco / 2 / div{1,1.5,2,4} */ switch (cdclk_divider(cdclk, vco, waveform)) { default: - drm_WARN_ON(&dev_priv->drm, - cdclk != dev_priv->display.cdclk.hw.bypass); - drm_WARN_ON(&dev_priv->drm, vco != 0); + drm_WARN_ON(display->drm, + cdclk != display->cdclk.hw.bypass); + drm_WARN_ON(display->drm, vco != 0); fallthrough; case 2: return BXT_CDCLK_CD2X_DIV_SEL_1; @@ -1788,47 +1887,47 @@ static u32 bxt_cdclk_cd2x_div_sel(struct drm_i915_private *dev_priv, } } -static u16 cdclk_squash_waveform(struct drm_i915_private *dev_priv, +static u16 cdclk_squash_waveform(struct intel_display *display, int cdclk) { - const struct intel_cdclk_vals *table = dev_priv->display.cdclk.table; + const struct intel_cdclk_vals *table = display->cdclk.table; int i; - if (cdclk == dev_priv->display.cdclk.hw.bypass) + if (cdclk == display->cdclk.hw.bypass) return 0; for (i = 0; table[i].refclk; i++) - if (table[i].refclk == dev_priv->display.cdclk.hw.ref && + if (table[i].refclk == display->cdclk.hw.ref && table[i].cdclk == cdclk) return table[i].waveform; - drm_WARN(&dev_priv->drm, 1, "cdclk %d not valid for refclk %u\n", - cdclk, dev_priv->display.cdclk.hw.ref); + drm_WARN(display->drm, 1, "cdclk %d not valid for refclk %u\n", + cdclk, display->cdclk.hw.ref); return 0xffff; } -static void icl_cdclk_pll_update(struct drm_i915_private *i915, int vco) +static void icl_cdclk_pll_update(struct intel_display *display, int vco) { - if (i915->display.cdclk.hw.vco != 0 && - i915->display.cdclk.hw.vco != vco) - icl_cdclk_pll_disable(i915); + if (display->cdclk.hw.vco != 0 && + display->cdclk.hw.vco != vco) + icl_cdclk_pll_disable(display); - if (i915->display.cdclk.hw.vco != vco) - icl_cdclk_pll_enable(i915, vco); + if (display->cdclk.hw.vco != vco) + icl_cdclk_pll_enable(display, vco); } -static void bxt_cdclk_pll_update(struct drm_i915_private *i915, int vco) +static void bxt_cdclk_pll_update(struct intel_display *display, int vco) { - if (i915->display.cdclk.hw.vco != 0 && - i915->display.cdclk.hw.vco != vco) - bxt_de_pll_disable(i915); + if (display->cdclk.hw.vco != 0 && + display->cdclk.hw.vco != vco) + bxt_de_pll_disable(display); - if (i915->display.cdclk.hw.vco != vco) - bxt_de_pll_enable(i915, vco); + if (display->cdclk.hw.vco != vco) + bxt_de_pll_enable(display, vco); } -static void dg2_cdclk_squash_program(struct drm_i915_private *i915, +static void dg2_cdclk_squash_program(struct intel_display *display, u16 waveform) { u32 squash_ctl = 0; @@ -1837,7 +1936,7 @@ static void dg2_cdclk_squash_program(struct drm_i915_private *i915, squash_ctl = CDCLK_SQUASH_ENABLE | CDCLK_SQUASH_WINDOW_SIZE(0xf) | waveform; - intel_de_write(i915, CDCLK_SQUASH_CTL, squash_ctl); + intel_de_write(display, CDCLK_SQUASH_CTL, squash_ctl); } static bool cdclk_pll_is_unknown(unsigned int vco) @@ -1850,7 +1949,40 @@ static bool cdclk_pll_is_unknown(unsigned int vco) return vco == ~0; } -static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i915, +static bool mdclk_source_is_cdclk_pll(struct intel_display *display) +{ + return DISPLAY_VER(display) >= 20; +} + +static u32 xe2lpd_mdclk_source_sel(struct intel_display *display) +{ + if (mdclk_source_is_cdclk_pll(display)) + return MDCLK_SOURCE_SEL_CDCLK_PLL; + + return MDCLK_SOURCE_SEL_CD2XCLK; +} + +int intel_mdclk_cdclk_ratio(struct intel_display *display, + const struct intel_cdclk_config *cdclk_config) +{ + if (mdclk_source_is_cdclk_pll(display)) + return DIV_ROUND_UP(cdclk_config->vco, cdclk_config->cdclk); + + /* Otherwise, source for MDCLK is CD2XCLK. */ + return 2; +} + +static void xe2lpd_mdclk_cdclk_ratio_program(struct intel_display *display, + const struct intel_cdclk_config *cdclk_config) +{ + struct drm_i915_private *i915 = to_i915(display->drm); + + intel_dbuf_mdclk_cdclk_ratio_update(i915, + intel_mdclk_cdclk_ratio(display, cdclk_config), + cdclk_config->joined_mbus); +} + +static bool cdclk_compute_crawl_and_squash_midpoint(struct intel_display *display, const struct intel_cdclk_config *old_cdclk_config, const struct intel_cdclk_config *new_cdclk_config, struct intel_cdclk_config *mid_cdclk_config) @@ -1863,11 +1995,11 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 return false; /* Return if both Squash and Crawl are not present */ - if (!HAS_CDCLK_CRAWL(i915) || !HAS_CDCLK_SQUASH(i915)) + if (!HAS_CDCLK_CRAWL(display) || !HAS_CDCLK_SQUASH(display)) return false; - old_waveform = cdclk_squash_waveform(i915, old_cdclk_config->cdclk); - new_waveform = cdclk_squash_waveform(i915, new_cdclk_config->cdclk); + old_waveform = cdclk_squash_waveform(display, old_cdclk_config->cdclk); + new_waveform = cdclk_squash_waveform(display, new_cdclk_config->cdclk); /* Return if Squash only or Crawl only is the desired action */ if (old_cdclk_config->vco == 0 || new_cdclk_config->vco == 0 || @@ -1884,7 +2016,7 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 * Should not happen currently. We might need more midpoint * transitions if we need to also change the cd2x divider. */ - if (drm_WARN_ON(&i915->drm, old_div != new_div)) + if (drm_WARN_ON(display->drm, old_div != new_div)) return false; *mid_cdclk_config = *new_cdclk_config; @@ -1913,37 +2045,40 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 /* make sure the mid clock came out sane */ - drm_WARN_ON(&i915->drm, mid_cdclk_config->cdclk < + drm_WARN_ON(display->drm, mid_cdclk_config->cdclk < min(old_cdclk_config->cdclk, new_cdclk_config->cdclk)); - drm_WARN_ON(&i915->drm, mid_cdclk_config->cdclk > - i915->display.cdclk.max_cdclk_freq); - drm_WARN_ON(&i915->drm, cdclk_squash_waveform(i915, mid_cdclk_config->cdclk) != + drm_WARN_ON(display->drm, mid_cdclk_config->cdclk > + display->cdclk.max_cdclk_freq); + drm_WARN_ON(display->drm, cdclk_squash_waveform(display, mid_cdclk_config->cdclk) != mid_waveform); return true; } -static bool pll_enable_wa_needed(struct drm_i915_private *dev_priv) +static bool pll_enable_wa_needed(struct intel_display *display) { - return (DISPLAY_VER_FULL(dev_priv) == IP_VER(20, 0) || - DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0) || + struct drm_i915_private *dev_priv = to_i915(display->drm); + + return (DISPLAY_VERx100(display) == 2000 || + DISPLAY_VERx100(display) == 1400 || IS_DG2(dev_priv)) && - dev_priv->display.cdclk.hw.vco > 0; + display->cdclk.hw.vco > 0; } -static u32 bxt_cdclk_ctl(struct drm_i915_private *i915, +static u32 bxt_cdclk_ctl(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *i915 = to_i915(display->drm); int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; u16 waveform; u32 val; - waveform = cdclk_squash_waveform(i915, cdclk); + waveform = cdclk_squash_waveform(display, cdclk); - val = bxt_cdclk_cd2x_div_sel(i915, cdclk, vco, waveform) | - bxt_cdclk_cd2x_pipe(i915, pipe); + val = bxt_cdclk_cd2x_div_sel(display, cdclk, vco, waveform) | + bxt_cdclk_cd2x_pipe(display, pipe); /* * Disable SSA Precharge when CD clock frequency < 500 MHz, @@ -1953,50 +2088,52 @@ static u32 bxt_cdclk_ctl(struct drm_i915_private *i915, cdclk >= 500000) val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE; - if (DISPLAY_VER(i915) >= 20) - val |= MDCLK_SOURCE_SEL_CDCLK_PLL; + if (DISPLAY_VER(display) >= 20) + val |= xe2lpd_mdclk_source_sel(display); else val |= skl_cdclk_decimal(cdclk); return val; } -static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, +static void _bxt_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; - u16 waveform; - if (HAS_CDCLK_CRAWL(dev_priv) && dev_priv->display.cdclk.hw.vco > 0 && vco > 0 && - !cdclk_pll_is_unknown(dev_priv->display.cdclk.hw.vco)) { - if (dev_priv->display.cdclk.hw.vco != vco) - adlp_cdclk_pll_crawl(dev_priv, vco); - } else if (DISPLAY_VER(dev_priv) >= 11) { + if (HAS_CDCLK_CRAWL(display) && display->cdclk.hw.vco > 0 && vco > 0 && + !cdclk_pll_is_unknown(display->cdclk.hw.vco)) { + if (display->cdclk.hw.vco != vco) + adlp_cdclk_pll_crawl(display, vco); + } else if (DISPLAY_VER(display) >= 11) { /* wa_15010685871: dg2, mtl */ - if (pll_enable_wa_needed(dev_priv)) - dg2_cdclk_squash_program(dev_priv, 0); + if (pll_enable_wa_needed(display)) + dg2_cdclk_squash_program(display, 0); - icl_cdclk_pll_update(dev_priv, vco); - } else - bxt_cdclk_pll_update(dev_priv, vco); + icl_cdclk_pll_update(display, vco); + } else { + bxt_cdclk_pll_update(display, vco); + } - waveform = cdclk_squash_waveform(dev_priv, cdclk); + if (HAS_CDCLK_SQUASH(display)) { + u16 waveform = cdclk_squash_waveform(display, cdclk); - if (HAS_CDCLK_SQUASH(dev_priv)) - dg2_cdclk_squash_program(dev_priv, waveform); + dg2_cdclk_squash_program(display, waveform); + } - intel_de_write(dev_priv, CDCLK_CTL, bxt_cdclk_ctl(dev_priv, cdclk_config, pipe)); + intel_de_write(display, CDCLK_CTL, bxt_cdclk_ctl(display, cdclk_config, pipe)); if (pipe != INVALID_PIPE) - intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(dev_priv, pipe)); + intel_crtc_wait_for_next_vblank(intel_crtc_for_pipe(display, pipe)); } -static void bxt_set_cdclk(struct drm_i915_private *dev_priv, +static void bxt_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, enum pipe pipe) { + struct drm_i915_private *dev_priv = to_i915(display->drm); struct intel_cdclk_config mid_cdclk_config; int cdclk = cdclk_config->cdclk; int ret = 0; @@ -2007,9 +2144,9 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, * mailbox communication, skip * this step. */ - if (DISPLAY_VER(dev_priv) >= 14 || IS_DG2(dev_priv)) + if (DISPLAY_VER(display) >= 14 || IS_DG2(dev_priv)) /* NOOP */; - else if (DISPLAY_VER(dev_priv) >= 11) + else if (DISPLAY_VER(display) >= 11) ret = skl_pcode_request(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, SKL_CDCLK_PREPARE_FOR_CHANGE, SKL_CDCLK_READY_FOR_CHANGE, @@ -2024,29 +2161,35 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, 0x80000000, 150, 2); if (ret) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "Failed to inform PCU about cdclk change (err %d, freq %d)\n", ret, cdclk); return; } - if (cdclk_compute_crawl_and_squash_midpoint(dev_priv, &dev_priv->display.cdclk.hw, + if (DISPLAY_VER(display) >= 20 && cdclk < display->cdclk.hw.cdclk) + xe2lpd_mdclk_cdclk_ratio_program(display, cdclk_config); + + if (cdclk_compute_crawl_and_squash_midpoint(display, &display->cdclk.hw, cdclk_config, &mid_cdclk_config)) { - _bxt_set_cdclk(dev_priv, &mid_cdclk_config, pipe); - _bxt_set_cdclk(dev_priv, cdclk_config, pipe); + _bxt_set_cdclk(display, &mid_cdclk_config, pipe); + _bxt_set_cdclk(display, cdclk_config, pipe); } else { - _bxt_set_cdclk(dev_priv, cdclk_config, pipe); + _bxt_set_cdclk(display, cdclk_config, pipe); } - if (DISPLAY_VER(dev_priv) >= 14) + 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 */; - else if (DISPLAY_VER(dev_priv) >= 11 && !IS_DG2(dev_priv)) + else if (DISPLAY_VER(display) >= 11 && !IS_DG2(dev_priv)) ret = snb_pcode_write(&dev_priv->uncore, SKL_PCODE_CDCLK_CONTROL, cdclk_config->voltage_level); - if (DISPLAY_VER(dev_priv) < 11) { + if (DISPLAY_VER(display) < 11) { /* * The timeout isn't specified, the 2ms used here is based on * experiment. @@ -2059,42 +2202,42 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, 150, 2); } if (ret) { - drm_err(&dev_priv->drm, + drm_err(display->drm, "PCode CDCLK freq set failed, (err %d, freq %d)\n", ret, cdclk); return; } - intel_update_cdclk(dev_priv); + intel_update_cdclk(display); - if (DISPLAY_VER(dev_priv) >= 11) + if (DISPLAY_VER(display) >= 11) /* * Can't read out the voltage level :( * Let's just assume everything is as expected. */ - dev_priv->display.cdclk.hw.voltage_level = cdclk_config->voltage_level; + display->cdclk.hw.voltage_level = cdclk_config->voltage_level; } -static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) +static void bxt_sanitize_cdclk(struct intel_display *display) { u32 cdctl, expected; int cdclk, vco; - intel_update_cdclk(dev_priv); - intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "Current CDCLK"); + intel_update_cdclk(display); + intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); - if (dev_priv->display.cdclk.hw.vco == 0 || - dev_priv->display.cdclk.hw.cdclk == dev_priv->display.cdclk.hw.bypass) + 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(dev_priv, dev_priv->display.cdclk.hw.cdclk); - if (cdclk != dev_priv->display.cdclk.hw.cdclk) + 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(dev_priv, cdclk); - if (vco != dev_priv->display.cdclk.hw.vco) + vco = bxt_calc_cdclk_pll_vco(display, cdclk); + if (vco != display->cdclk.hw.vco) goto sanitize; /* @@ -2102,129 +2245,133 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv) * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4, * so sanitize this register. */ - cdctl = intel_de_read(dev_priv, CDCLK_CTL); - expected = bxt_cdclk_ctl(dev_priv, &dev_priv->display.cdclk.hw, INVALID_PIPE); + 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 synching to an active pipe, or asynchronously * (PIPE_NONE). */ - cdctl &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); - expected &= ~bxt_cdclk_cd2x_pipe(dev_priv, INVALID_PIPE); + 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(&dev_priv->drm, "Sanitizing cdclk programmed by pre-os\n"); + drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n"); /* force cdclk programming */ - dev_priv->display.cdclk.hw.cdclk = 0; + display->cdclk.hw.cdclk = 0; /* force full PLL disable + enable */ - dev_priv->display.cdclk.hw.vco = ~0; + display->cdclk.hw.vco = ~0; } -static void bxt_cdclk_init_hw(struct drm_i915_private *dev_priv) +static void bxt_cdclk_init_hw(struct intel_display *display) { struct intel_cdclk_config cdclk_config; - bxt_sanitize_cdclk(dev_priv); + bxt_sanitize_cdclk(display); - if (dev_priv->display.cdclk.hw.cdclk != 0 && - dev_priv->display.cdclk.hw.vco != 0) + if (display->cdclk.hw.cdclk != 0 && + display->cdclk.hw.vco != 0) return; - cdclk_config = dev_priv->display.cdclk.hw; + 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(dev_priv, 0); - cdclk_config.vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk_config.cdclk); + 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(dev_priv, cdclk_config.cdclk); + intel_cdclk_calc_voltage_level(display, cdclk_config.cdclk); - bxt_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); + bxt_set_cdclk(display, &cdclk_config, INVALID_PIPE); } -static void bxt_cdclk_uninit_hw(struct drm_i915_private *dev_priv) +static void bxt_cdclk_uninit_hw(struct intel_display *display) { - struct intel_cdclk_config cdclk_config = dev_priv->display.cdclk.hw; + struct intel_cdclk_config cdclk_config = display->cdclk.hw; cdclk_config.cdclk = cdclk_config.bypass; cdclk_config.vco = 0; cdclk_config.voltage_level = - intel_cdclk_calc_voltage_level(dev_priv, cdclk_config.cdclk); + intel_cdclk_calc_voltage_level(display, cdclk_config.cdclk); - bxt_set_cdclk(dev_priv, &cdclk_config, INVALID_PIPE); + bxt_set_cdclk(display, &cdclk_config, INVALID_PIPE); } /** * intel_cdclk_init_hw - Initialize CDCLK hardware - * @i915: i915 device + * @display: display instance * - * Initialize CDCLK. This consists mainly of initializing dev_priv->display.cdclk.hw and + * 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 drm_i915_private *i915) +void intel_cdclk_init_hw(struct intel_display *display) { - if (DISPLAY_VER(i915) >= 10 || IS_BROXTON(i915)) - bxt_cdclk_init_hw(i915); - else if (DISPLAY_VER(i915) == 9) - skl_cdclk_init_hw(i915); + struct drm_i915_private *i915 = to_i915(display->drm); + + if (DISPLAY_VER(display) >= 10 || IS_BROXTON(i915)) + bxt_cdclk_init_hw(display); + else if (DISPLAY_VER(display) == 9) + skl_cdclk_init_hw(display); } /** * intel_cdclk_uninit_hw - Uninitialize CDCLK hardware - * @i915: i915 device + * @display: display instance * * Uninitialize CDCLK. This is done only during the display core * uninitialization sequence. */ -void intel_cdclk_uninit_hw(struct drm_i915_private *i915) +void intel_cdclk_uninit_hw(struct intel_display *display) { - if (DISPLAY_VER(i915) >= 10 || IS_BROXTON(i915)) - bxt_cdclk_uninit_hw(i915); - else if (DISPLAY_VER(i915) == 9) - skl_cdclk_uninit_hw(i915); + struct drm_i915_private *i915 = to_i915(display->drm); + + if (DISPLAY_VER(display) >= 10 || IS_BROXTON(i915)) + bxt_cdclk_uninit_hw(display); + else if (DISPLAY_VER(display) == 9) + skl_cdclk_uninit_hw(display); } -static bool intel_cdclk_can_crawl_and_squash(struct drm_i915_private *i915, +static bool intel_cdclk_can_crawl_and_squash(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { u16 old_waveform; u16 new_waveform; - drm_WARN_ON(&i915->drm, cdclk_pll_is_unknown(a->vco)); + drm_WARN_ON(display->drm, cdclk_pll_is_unknown(a->vco)); if (a->vco == 0 || b->vco == 0) return false; - if (!HAS_CDCLK_CRAWL(i915) || !HAS_CDCLK_SQUASH(i915)) + if (!HAS_CDCLK_CRAWL(display) || !HAS_CDCLK_SQUASH(display)) return false; - old_waveform = cdclk_squash_waveform(i915, a->cdclk); - new_waveform = cdclk_squash_waveform(i915, b->cdclk); + old_waveform = cdclk_squash_waveform(display, a->cdclk); + new_waveform = cdclk_squash_waveform(display, b->cdclk); return a->vco != b->vco && old_waveform != new_waveform; } -static bool intel_cdclk_can_crawl(struct drm_i915_private *dev_priv, +static bool intel_cdclk_can_crawl(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { int a_div, b_div; - if (!HAS_CDCLK_CRAWL(dev_priv)) + if (!HAS_CDCLK_CRAWL(display)) return false; /* @@ -2240,7 +2387,7 @@ static bool intel_cdclk_can_crawl(struct drm_i915_private *dev_priv, a->ref == b->ref; } -static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv, +static bool intel_cdclk_can_squash(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { @@ -2250,7 +2397,7 @@ static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (!HAS_CDCLK_SQUASH(dev_priv)) + if (!HAS_CDCLK_SQUASH(display)) return false; return a->cdclk != b->cdclk && @@ -2260,16 +2407,15 @@ static bool intel_cdclk_can_squash(struct drm_i915_private *dev_priv, } /** - * intel_cdclk_needs_modeset - Determine if changong between the CDCLK - * configurations requires a modeset on all pipes + * intel_cdclk_clock_changed - Check whether the clock changed * @a: first CDCLK configuration * @b: second CDCLK configuration * * Returns: - * True if changing between the two CDCLK configurations - * requires all pipes to be off, false if not. + * True if CDCLK changed in a way that requires re-programming and + * False otherwise. */ -bool intel_cdclk_needs_modeset(const struct intel_cdclk_config *a, +bool intel_cdclk_clock_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { return a->cdclk != b->cdclk || @@ -2280,7 +2426,7 @@ bool intel_cdclk_needs_modeset(const struct intel_cdclk_config *a, /** * intel_cdclk_can_cd2x_update - Determine if changing between the two CDCLK * configurations requires only a cd2x divider update - * @dev_priv: i915 device + * @display: display instance * @a: first CDCLK configuration * @b: second CDCLK configuration * @@ -2288,12 +2434,14 @@ bool intel_cdclk_needs_modeset(const struct intel_cdclk_config *a, * True if changing between the two CDCLK configurations * can be done with just a cd2x divider update, false if not. */ -static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, +static bool intel_cdclk_can_cd2x_update(struct intel_display *display, const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { + struct drm_i915_private *dev_priv = to_i915(display->drm); + /* Older hw doesn't have the capability */ - if (DISPLAY_VER(dev_priv) < 10 && !IS_BROXTON(dev_priv)) + if (DISPLAY_VER(display) < 10 && !IS_BROXTON(dev_priv)) return false; /* @@ -2302,7 +2450,7 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, * the moment all platforms with squasher use a fixed cd2x * divider. */ - if (HAS_CDCLK_SQUASH(dev_priv)) + if (HAS_CDCLK_SQUASH(display)) return false; return a->cdclk != b->cdclk && @@ -2322,27 +2470,28 @@ static bool intel_cdclk_can_cd2x_update(struct drm_i915_private *dev_priv, static bool intel_cdclk_changed(const struct intel_cdclk_config *a, const struct intel_cdclk_config *b) { - return intel_cdclk_needs_modeset(a, b) || + return intel_cdclk_clock_changed(a, b) || a->voltage_level != b->voltage_level; } -void intel_cdclk_dump_config(struct drm_i915_private *i915, +void intel_cdclk_dump_config(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, const char *context) { - drm_dbg_kms(&i915->drm, "%s %d kHz, VCO %d kHz, ref %d kHz, bypass %d kHz, voltage level %d\n", + drm_dbg_kms(display->drm, "%s %d kHz, VCO %d kHz, ref %d kHz, bypass %d kHz, voltage level %d\n", context, cdclk_config->cdclk, cdclk_config->vco, cdclk_config->ref, cdclk_config->bypass, cdclk_config->voltage_level); } -static void intel_pcode_notify(struct drm_i915_private *i915, +static void intel_pcode_notify(struct intel_display *display, u8 voltage_level, u8 active_pipe_count, u16 cdclk, bool cdclk_update_valid, bool pipe_count_update_valid) { + struct drm_i915_private *i915 = to_i915(display->drm); int ret; u32 update_mask = 0; @@ -2363,35 +2512,27 @@ static void intel_pcode_notify(struct drm_i915_private *i915, SKL_CDCLK_READY_FOR_CHANGE, SKL_CDCLK_READY_FOR_CHANGE, 3); if (ret) - drm_err(&i915->drm, + drm_err(display->drm, "Failed to inform PCU about display config (err %d)\n", ret); } -/** - * intel_set_cdclk - Push the CDCLK configuration to the hardware - * @dev_priv: i915 device - * @cdclk_config: new CDCLK configuration - * @pipe: pipe with which to synchronize the update - * - * Program the hardware based on the passed in CDCLK state, - * if necessary. - */ -static void intel_set_cdclk(struct drm_i915_private *dev_priv, +static void intel_set_cdclk(struct intel_display *display, const struct intel_cdclk_config *cdclk_config, - enum pipe pipe) + enum pipe pipe, const char *context) { + struct drm_i915_private *dev_priv = to_i915(display->drm); struct intel_encoder *encoder; - if (!intel_cdclk_changed(&dev_priv->display.cdclk.hw, cdclk_config)) + if (!intel_cdclk_changed(&display->cdclk.hw, cdclk_config)) return; - if (drm_WARN_ON_ONCE(&dev_priv->drm, !dev_priv->display.funcs.cdclk->set_cdclk)) + if (drm_WARN_ON_ONCE(display->drm, !display->funcs.cdclk->set_cdclk)) return; - intel_cdclk_dump_config(dev_priv, cdclk_config, "Changing CDCLK to"); + intel_cdclk_dump_config(display, cdclk_config, context); - for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(display->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_psr_pause(intel_dp); @@ -2404,24 +2545,24 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, * functions use cdclk. Not all platforms/ports do, * but we'll lock them all for simplicity. */ - mutex_lock(&dev_priv->display.gmbus.mutex); - for_each_intel_dp(&dev_priv->drm, encoder) { + mutex_lock(&display->gmbus.mutex); + for_each_intel_dp(display->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); mutex_lock_nest_lock(&intel_dp->aux.hw_mutex, - &dev_priv->display.gmbus.mutex); + &display->gmbus.mutex); } - intel_cdclk_set_cdclk(dev_priv, cdclk_config, pipe); + intel_cdclk_set_cdclk(display, cdclk_config, pipe); - for_each_intel_dp(&dev_priv->drm, encoder) { + for_each_intel_dp(display->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); mutex_unlock(&intel_dp->aux.hw_mutex); } - mutex_unlock(&dev_priv->display.gmbus.mutex); + mutex_unlock(&display->gmbus.mutex); - for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(display->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); intel_psr_resume(intel_dp); @@ -2429,17 +2570,17 @@ static void intel_set_cdclk(struct drm_i915_private *dev_priv, intel_audio_cdclk_change_post(dev_priv); - if (drm_WARN(&dev_priv->drm, - intel_cdclk_changed(&dev_priv->display.cdclk.hw, cdclk_config), + if (drm_WARN(display->drm, + intel_cdclk_changed(&display->cdclk.hw, cdclk_config), "cdclk state doesn't match!\n")) { - intel_cdclk_dump_config(dev_priv, &dev_priv->display.cdclk.hw, "[hw state]"); - intel_cdclk_dump_config(dev_priv, cdclk_config, "[sw state]"); + intel_cdclk_dump_config(display, &display->cdclk.hw, "[hw state]"); + intel_cdclk_dump_config(display, cdclk_config, "[sw state]"); } } static void intel_cdclk_pcode_pre_notify(struct intel_atomic_state *state) { - struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); const struct intel_cdclk_state *old_cdclk_state = intel_atomic_get_old_cdclk_state(state); const struct intel_cdclk_state *new_cdclk_state = @@ -2478,13 +2619,13 @@ static void intel_cdclk_pcode_pre_notify(struct intel_atomic_state *state) if (update_pipe_count) num_active_pipes = hweight8(new_cdclk_state->active_pipes); - intel_pcode_notify(i915, voltage_level, num_active_pipes, cdclk, + intel_pcode_notify(display, voltage_level, num_active_pipes, cdclk, change_cdclk, update_pipe_count); } static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state) { - struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); const struct intel_cdclk_state *new_cdclk_state = intel_atomic_get_new_cdclk_state(state); const struct intel_cdclk_state *old_cdclk_state = @@ -2515,10 +2656,21 @@ static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state) if (update_pipe_count) num_active_pipes = hweight8(new_cdclk_state->active_pipes); - intel_pcode_notify(i915, voltage_level, num_active_pipes, cdclk, + intel_pcode_notify(display, voltage_level, num_active_pipes, cdclk, update_cdclk, update_pipe_count); } +bool intel_cdclk_is_decreasing_later(struct intel_atomic_state *state) +{ + const struct intel_cdclk_state *old_cdclk_state = + intel_atomic_get_old_cdclk_state(state); + const struct intel_cdclk_state *new_cdclk_state = + intel_atomic_get_new_cdclk_state(state); + + return new_cdclk_state && !new_cdclk_state->disable_pipes && + new_cdclk_state->actual.cdclk < old_cdclk_state->actual.cdclk; +} + /** * intel_set_cdclk_pre_plane_update - Push the CDCLK state to the hardware * @state: intel atomic state @@ -2529,7 +2681,8 @@ static void intel_cdclk_pcode_post_notify(struct intel_atomic_state *state) void intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) { - struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); + struct drm_i915_private *i915 = to_i915(display->drm); const struct intel_cdclk_state *old_cdclk_state = intel_atomic_get_old_cdclk_state(state); const struct intel_cdclk_state *new_cdclk_state = @@ -2560,9 +2713,16 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) old_cdclk_state->actual.voltage_level); } - drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); + /* + * mbus joining will be changed later by + * intel_dbuf_mbus_{pre,post}_ddb_update() + */ + cdclk_config.joined_mbus = old_cdclk_state->actual.joined_mbus; + + drm_WARN_ON(display->drm, !new_cdclk_state->base.changed); - intel_set_cdclk(i915, &cdclk_config, pipe); + intel_set_cdclk(display, &cdclk_config, pipe, + "Pre changing CDCLK to"); } /** @@ -2575,7 +2735,8 @@ intel_set_cdclk_pre_plane_update(struct intel_atomic_state *state) void intel_set_cdclk_post_plane_update(struct intel_atomic_state *state) { - struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); + struct drm_i915_private *i915 = to_i915(display->drm); const struct intel_cdclk_state *old_cdclk_state = intel_atomic_get_old_cdclk_state(state); const struct intel_cdclk_state *new_cdclk_state = @@ -2595,185 +2756,78 @@ intel_set_cdclk_post_plane_update(struct intel_atomic_state *state) else pipe = INVALID_PIPE; - drm_WARN_ON(&i915->drm, !new_cdclk_state->base.changed); + drm_WARN_ON(display->drm, !new_cdclk_state->base.changed); - intel_set_cdclk(i915, &new_cdclk_state->actual, pipe); + intel_set_cdclk(display, &new_cdclk_state->actual, pipe, + "Post changing CDCLK to"); } -static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state) +/* pixels per CDCLK */ +static int intel_cdclk_ppc(struct intel_display *display, bool double_wide) { - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - int pixel_rate = crtc_state->pixel_rate; + return DISPLAY_VER(display) >= 10 || double_wide ? 2 : 1; +} + +/* max pixel rate as % of CDCLK (not accounting for PPC) */ +static int intel_cdclk_guardband(struct intel_display *display) +{ + struct drm_i915_private *dev_priv = to_i915(display->drm); - if (DISPLAY_VER(dev_priv) >= 10) - return DIV_ROUND_UP(pixel_rate, 2); - else if (DISPLAY_VER(dev_priv) == 9 || - IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) - return pixel_rate; + if (DISPLAY_VER(display) >= 9 || + IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + return 100; else if (IS_CHERRYVIEW(dev_priv)) - return DIV_ROUND_UP(pixel_rate * 100, 95); - else if (crtc_state->double_wide) - return DIV_ROUND_UP(pixel_rate * 100, 90 * 2); + return 95; else - return DIV_ROUND_UP(pixel_rate * 100, 90); + return 90; } -static int intel_planes_min_cdclk(const struct intel_crtc_state *crtc_state) +static int intel_pixel_rate_to_cdclk(const struct intel_crtc_state *crtc_state) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_plane *plane; - int min_cdclk = 0; - - for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) - min_cdclk = max(crtc_state->min_cdclk[plane->id], min_cdclk); + struct intel_display *display = to_intel_display(crtc_state); + int ppc = intel_cdclk_ppc(display, crtc_state->double_wide); + int guardband = intel_cdclk_guardband(display); + int pixel_rate = crtc_state->pixel_rate; - return min_cdclk; + return DIV_ROUND_UP(pixel_rate * 100, guardband * ppc); } -static int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) +static int intel_planes_min_cdclk(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *i915 = to_i915(crtc->base.dev); - int num_vdsc_instances = intel_dsc_get_num_vdsc_instances(crtc_state); + struct intel_display *display = to_intel_display(crtc); + struct intel_plane *plane; int min_cdclk = 0; - /* - * When we decide to use only one VDSC engine, since - * each VDSC operates with 1 ppc throughput, pixel clock - * cannot be higher than the VDSC clock (cdclk) - * If there 2 VDSC engines, then pixel clock can't be higher than - * VDSC clock(cdclk) * 2 and so on. - */ - min_cdclk = max_t(int, min_cdclk, - DIV_ROUND_UP(crtc_state->pixel_rate, num_vdsc_instances)); - - if (crtc_state->bigjoiner_pipes) { - int pixel_clock = intel_dp_mode_to_fec_clock(crtc_state->hw.adjusted_mode.clock); - - /* - * According to Bigjoiner bw check: - * compressed_bpp <= PPC * CDCLK * Big joiner Interface bits / Pixel clock - * - * We have already computed compressed_bpp, so now compute the min CDCLK that - * is required to support this compressed_bpp. - * - * => CDCLK >= compressed_bpp * Pixel clock / (PPC * Bigjoiner Interface bits) - * - * Since PPC = 2 with bigjoiner - * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits - */ - int bigjoiner_interface_bits = DISPLAY_VER(i915) >= 14 ? 36 : 24; - int min_cdclk_bj = - (to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) * - pixel_clock) / (2 * bigjoiner_interface_bits); - - min_cdclk = max(min_cdclk, min_cdclk_bj); - } + for_each_intel_plane_on_crtc(display->drm, crtc, plane) + min_cdclk = max(min_cdclk, crtc_state->min_cdclk[plane->id]); return min_cdclk; } int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = - to_i915(crtc_state->uapi.crtc->dev); int min_cdclk; if (!crtc_state->hw.enable) return 0; min_cdclk = intel_pixel_rate_to_cdclk(crtc_state); - - /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (IS_BROADWELL(dev_priv) && hsw_crtc_state_ips_capable(crtc_state)) - min_cdclk = DIV_ROUND_UP(min_cdclk * 100, 95); - - /* BSpec says "Do not use DisplayPort with CDCLK less than 432 MHz, - * audio enabled, port width x4, and link rate HBR2 (5.4 GHz), or else - * there may be audio corruption or screen corruption." This cdclk - * restriction for GLK is 316.8 MHz. - */ - if (intel_crtc_has_dp_encoder(crtc_state) && - crtc_state->has_audio && - crtc_state->port_clock >= 540000 && - crtc_state->lane_count == 4) { - if (DISPLAY_VER(dev_priv) == 10) { - /* Display WA #1145: glk */ - min_cdclk = max(316800, min_cdclk); - } else if (DISPLAY_VER(dev_priv) == 9 || IS_BROADWELL(dev_priv)) { - /* Display WA #1144: skl,bxt */ - min_cdclk = max(432000, min_cdclk); - } - } - - /* - * According to BSpec, "The CD clock frequency must be at least twice - * the frequency of the Azalia BCLK." and BCLK is 96 MHz by default. - */ - if (crtc_state->has_audio && DISPLAY_VER(dev_priv) >= 9) - min_cdclk = max(2 * 96000, min_cdclk); - - /* - * "For DP audio configuration, cdclk frequency shall be set to - * meet the following requirements: - * DP Link Frequency(MHz) | Cdclk frequency(MHz) - * 270 | 320 or higher - * 162 | 200 or higher" - */ - if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - intel_crtc_has_dp_encoder(crtc_state) && crtc_state->has_audio) - min_cdclk = max(crtc_state->port_clock, min_cdclk); - - /* - * On Valleyview some DSI panels lose (v|h)sync when the clock is lower - * than 320000KHz. - */ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) && - IS_VALLEYVIEW(dev_priv)) - min_cdclk = max(320000, min_cdclk); - - /* - * On Geminilake once the CDCLK gets as low as 79200 - * picture gets unstable, despite that values are - * correct for DSI PLL and DE PLL. - */ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) && - IS_GEMINILAKE(dev_priv)) - min_cdclk = max(158400, min_cdclk); - - /* Account for additional needs from the planes */ - min_cdclk = max(intel_planes_min_cdclk(crtc_state), min_cdclk); - - if (crtc_state->dsc.compression_enable) - min_cdclk = max(min_cdclk, intel_vdsc_min_cdclk(crtc_state)); - - /* - * HACK. Currently for TGL/DG2 platforms we calculate - * min_cdclk initially based on pixel_rate divided - * by 2, accounting for also plane requirements, - * however in some cases the lowest possible CDCLK - * doesn't work and causing the underruns. - * Explicitly stating here that this seems to be currently - * rather a Hack, than final solution. - */ - if (IS_TIGERLAKE(dev_priv) || IS_DG2(dev_priv)) { - /* - * Clamp to max_cdclk_freq in case pixel rate is higher, - * in order not to break an 8K, but still leave W/A at place. - */ - min_cdclk = max_t(int, min_cdclk, - min_t(int, crtc_state->pixel_rate, - dev_priv->display.cdclk.max_cdclk_freq)); - } + min_cdclk = max(min_cdclk, hsw_ips_min_cdclk(crtc_state)); + min_cdclk = max(min_cdclk, intel_audio_min_cdclk(crtc_state)); + min_cdclk = max(min_cdclk, vlv_dsi_min_cdclk(crtc_state)); + min_cdclk = max(min_cdclk, intel_planes_min_cdclk(crtc_state)); + min_cdclk = max(min_cdclk, intel_vdsc_min_cdclk(crtc_state)); return min_cdclk; } -static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) +static int intel_compute_min_cdclk(struct intel_atomic_state *state) { - struct intel_atomic_state *state = cdclk_state->base.state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); + struct drm_i915_private *dev_priv = to_i915(display->drm); + struct intel_cdclk_state *cdclk_state = + intel_atomic_get_new_cdclk_state(state); const struct intel_bw_state *bw_state; struct intel_crtc *crtc; struct intel_crtc_state *crtc_state; @@ -2814,8 +2868,8 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) min_cdclk = max(cdclk_state->force_min_cdclk, cdclk_state->bw_min_cdclk); - for_each_pipe(dev_priv, pipe) - min_cdclk = max(cdclk_state->min_cdclk[pipe], min_cdclk); + for_each_pipe(display, pipe) + min_cdclk = max(min_cdclk, cdclk_state->min_cdclk[pipe]); /* * Avoid glk_force_audio_cdclk() causing excessive screen @@ -2827,12 +2881,12 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) */ if (IS_GEMINILAKE(dev_priv) && cdclk_state->active_pipes && !is_power_of_2(cdclk_state->active_pipes)) - min_cdclk = max(2 * 96000, min_cdclk); + min_cdclk = max(min_cdclk, 2 * 96000); - if (min_cdclk > dev_priv->display.cdclk.max_cdclk_freq) { - drm_dbg_kms(&dev_priv->drm, + if (min_cdclk > display->cdclk.max_cdclk_freq) { + drm_dbg_kms(display->drm, "required cdclk (%d kHz) exceeds max (%d kHz)\n", - min_cdclk, dev_priv->display.cdclk.max_cdclk_freq); + min_cdclk, display->cdclk.max_cdclk_freq); return -EINVAL; } @@ -2852,10 +2906,11 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) * future platforms this code will need to be * adjusted. */ -static int bxt_compute_min_voltage_level(struct intel_cdclk_state *cdclk_state) +static int bxt_compute_min_voltage_level(struct intel_atomic_state *state) { - struct intel_atomic_state *state = cdclk_state->base.state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + 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; @@ -2881,35 +2936,36 @@ static int bxt_compute_min_voltage_level(struct intel_cdclk_state *cdclk_state) } min_voltage_level = 0; - for_each_pipe(dev_priv, pipe) - min_voltage_level = max(cdclk_state->min_voltage_level[pipe], - min_voltage_level); + for_each_pipe(display, pipe) + min_voltage_level = max(min_voltage_level, + cdclk_state->min_voltage_level[pipe]); return min_voltage_level; } -static int vlv_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) +static int vlv_modeset_calc_cdclk(struct intel_atomic_state *state) { - struct intel_atomic_state *state = cdclk_state->base.state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); + struct intel_cdclk_state *cdclk_state = + intel_atomic_get_new_cdclk_state(state); int min_cdclk, cdclk; - min_cdclk = intel_compute_min_cdclk(cdclk_state); + min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk; - cdclk = vlv_calc_cdclk(dev_priv, min_cdclk); + cdclk = vlv_calc_cdclk(display, min_cdclk); cdclk_state->logical.cdclk = cdclk; cdclk_state->logical.voltage_level = - vlv_calc_voltage_level(dev_priv, cdclk); + vlv_calc_voltage_level(display, cdclk); if (!cdclk_state->active_pipes) { - cdclk = vlv_calc_cdclk(dev_priv, cdclk_state->force_min_cdclk); + cdclk = vlv_calc_cdclk(display, cdclk_state->force_min_cdclk); cdclk_state->actual.cdclk = cdclk; cdclk_state->actual.voltage_level = - vlv_calc_voltage_level(dev_priv, cdclk); + vlv_calc_voltage_level(display, cdclk); } else { cdclk_state->actual = cdclk_state->logical; } @@ -2917,11 +2973,13 @@ static int vlv_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) return 0; } -static int bdw_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) +static int bdw_modeset_calc_cdclk(struct intel_atomic_state *state) { + struct intel_cdclk_state *cdclk_state = + intel_atomic_get_new_cdclk_state(state); int min_cdclk, cdclk; - min_cdclk = intel_compute_min_cdclk(cdclk_state); + min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk; @@ -2944,17 +3002,18 @@ static int bdw_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) return 0; } -static int skl_dpll0_vco(struct intel_cdclk_state *cdclk_state) +static int skl_dpll0_vco(struct intel_atomic_state *state) { - struct intel_atomic_state *state = cdclk_state->base.state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + 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; int vco, i; vco = cdclk_state->logical.vco; if (!vco) - vco = dev_priv->skl_preferred_vco_freq; + vco = display->cdclk.skl_preferred_vco_freq; for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) { if (!crtc_state->hw.enable) @@ -2981,15 +3040,17 @@ static int skl_dpll0_vco(struct intel_cdclk_state *cdclk_state) return vco; } -static int skl_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) +static int skl_modeset_calc_cdclk(struct intel_atomic_state *state) { + struct intel_cdclk_state *cdclk_state = + intel_atomic_get_new_cdclk_state(state); int min_cdclk, cdclk, vco; - min_cdclk = intel_compute_min_cdclk(cdclk_state); + min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk; - vco = skl_dpll0_vco(cdclk_state); + vco = skl_dpll0_vco(state); cdclk = skl_calc_cdclk(min_cdclk, vco); @@ -3012,37 +3073,38 @@ static int skl_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) return 0; } -static int bxt_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) +static int bxt_modeset_calc_cdclk(struct intel_atomic_state *state) { - struct intel_atomic_state *state = cdclk_state->base.state; - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); + struct intel_cdclk_state *cdclk_state = + intel_atomic_get_new_cdclk_state(state); int min_cdclk, min_voltage_level, cdclk, vco; - min_cdclk = intel_compute_min_cdclk(cdclk_state); + min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk; - min_voltage_level = bxt_compute_min_voltage_level(cdclk_state); + min_voltage_level = bxt_compute_min_voltage_level(state); if (min_voltage_level < 0) return min_voltage_level; - cdclk = bxt_calc_cdclk(dev_priv, min_cdclk); - vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk); + cdclk = bxt_calc_cdclk(display, min_cdclk); + vco = bxt_calc_cdclk_pll_vco(display, cdclk); cdclk_state->logical.vco = vco; cdclk_state->logical.cdclk = cdclk; cdclk_state->logical.voltage_level = max_t(int, min_voltage_level, - intel_cdclk_calc_voltage_level(dev_priv, cdclk)); + intel_cdclk_calc_voltage_level(display, cdclk)); if (!cdclk_state->active_pipes) { - cdclk = bxt_calc_cdclk(dev_priv, cdclk_state->force_min_cdclk); - vco = bxt_calc_cdclk_pll_vco(dev_priv, cdclk); + cdclk = bxt_calc_cdclk(display, cdclk_state->force_min_cdclk); + vco = bxt_calc_cdclk_pll_vco(display, cdclk); cdclk_state->actual.vco = vco; cdclk_state->actual.cdclk = cdclk; cdclk_state->actual.voltage_level = - intel_cdclk_calc_voltage_level(dev_priv, cdclk); + intel_cdclk_calc_voltage_level(display, cdclk); } else { cdclk_state->actual = cdclk_state->logical; } @@ -3050,7 +3112,7 @@ static int bxt_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) return 0; } -static int fixed_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) +static int fixed_modeset_calc_cdclk(struct intel_atomic_state *state) { int min_cdclk; @@ -3059,7 +3121,7 @@ static int fixed_modeset_calc_cdclk(struct intel_cdclk_state *cdclk_state) * check that the required minimum frequency doesn't exceed * the actual cdclk frequency. */ - min_cdclk = intel_compute_min_cdclk(cdclk_state); + min_cdclk = intel_compute_min_cdclk(state); if (min_cdclk < 0) return min_cdclk; @@ -3094,10 +3156,10 @@ static const struct intel_global_state_funcs intel_cdclk_funcs = { struct intel_cdclk_state * intel_atomic_get_cdclk_state(struct intel_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); struct intel_global_state *cdclk_state; - cdclk_state = intel_atomic_get_global_obj_state(state, &dev_priv->display.cdclk.obj); + cdclk_state = intel_atomic_get_global_obj_state(state, &display->cdclk.obj); if (IS_ERR(cdclk_state)) return ERR_CAST(cdclk_state); @@ -3139,7 +3201,21 @@ int intel_cdclk_atomic_check(struct intel_atomic_state *state, return 0; } -int intel_cdclk_init(struct drm_i915_private *dev_priv) +int intel_cdclk_state_set_joined_mbus(struct intel_atomic_state *state, bool joined_mbus) +{ + struct intel_cdclk_state *cdclk_state; + + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); + + cdclk_state->actual.joined_mbus = joined_mbus; + cdclk_state->logical.joined_mbus = joined_mbus; + + return intel_atomic_lock_global_state(&cdclk_state->base); +} + +int intel_cdclk_init(struct intel_display *display) { struct intel_cdclk_state *cdclk_state; @@ -3147,16 +3223,17 @@ int intel_cdclk_init(struct drm_i915_private *dev_priv) if (!cdclk_state) return -ENOMEM; - intel_atomic_global_obj_init(dev_priv, &dev_priv->display.cdclk.obj, + intel_atomic_global_obj_init(display, &display->cdclk.obj, &cdclk_state->base, &intel_cdclk_funcs); return 0; } -static bool intel_cdclk_need_serialize(struct drm_i915_private *i915, +static bool intel_cdclk_need_serialize(struct intel_display *display, const struct intel_cdclk_state *old_cdclk_state, const struct intel_cdclk_state *new_cdclk_state) { + struct drm_i915_private *i915 = to_i915(display->drm); bool power_well_cnt_changed = hweight8(old_cdclk_state->active_pipes) != hweight8(new_cdclk_state->active_pipes); bool cdclk_changed = intel_cdclk_changed(&old_cdclk_state->actual, @@ -3170,7 +3247,7 @@ static bool intel_cdclk_need_serialize(struct drm_i915_private *i915, int intel_modeset_calc_cdclk(struct intel_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->base.dev); + struct intel_display *display = to_intel_display(state); const struct intel_cdclk_state *old_cdclk_state; struct intel_cdclk_state *new_cdclk_state; enum pipe pipe = INVALID_PIPE; @@ -3185,11 +3262,11 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) new_cdclk_state->active_pipes = intel_calc_active_pipes(state, old_cdclk_state->active_pipes); - ret = intel_cdclk_modeset_calc_cdclk(dev_priv, new_cdclk_state); + ret = intel_cdclk_modeset_calc_cdclk(state); if (ret) return ret; - if (intel_cdclk_need_serialize(dev_priv, old_cdclk_state, new_cdclk_state)) { + 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. @@ -3209,14 +3286,14 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) } if (is_power_of_2(new_cdclk_state->active_pipes) && - intel_cdclk_can_cd2x_update(dev_priv, + intel_cdclk_can_cd2x_update(display, &old_cdclk_state->actual, &new_cdclk_state->actual)) { struct intel_crtc *crtc; struct intel_crtc_state *crtc_state; pipe = ilog2(new_cdclk_state->active_pipes); - crtc = intel_crtc_for_pipe(dev_priv, pipe); + crtc = intel_crtc_for_pipe(display, pipe); crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); if (IS_ERR(crtc_state)) @@ -3226,28 +3303,28 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) pipe = INVALID_PIPE; } - if (intel_cdclk_can_crawl_and_squash(dev_priv, + if (intel_cdclk_can_crawl_and_squash(display, &old_cdclk_state->actual, &new_cdclk_state->actual)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "Can change cdclk via crawling and squashing\n"); - } else if (intel_cdclk_can_squash(dev_priv, + } else if (intel_cdclk_can_squash(display, &old_cdclk_state->actual, &new_cdclk_state->actual)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "Can change cdclk via squashing\n"); - } else if (intel_cdclk_can_crawl(dev_priv, + } else if (intel_cdclk_can_crawl(display, &old_cdclk_state->actual, &new_cdclk_state->actual)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "Can change cdclk via crawling\n"); } else if (pipe != INVALID_PIPE) { new_cdclk_state->pipe = pipe; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "Can change cdclk cd2x divider with pipe %c active\n", pipe_name(pipe)); - } else if (intel_cdclk_needs_modeset(&old_cdclk_state->actual, + } else if (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"); @@ -3256,15 +3333,24 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) new_cdclk_state->disable_pipes = true; - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(display->drm, "Modeset required for cdclk change\n"); } - drm_dbg_kms(&dev_priv->drm, + 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(&dev_priv->drm, + 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); @@ -3272,53 +3358,49 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state) return 0; } -static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv) +static int intel_compute_max_dotclk(struct intel_display *display) { - int max_cdclk_freq = dev_priv->display.cdclk.max_cdclk_freq; + int ppc = intel_cdclk_ppc(display, HAS_DOUBLE_WIDE(display)); + int guardband = intel_cdclk_guardband(display); + int max_cdclk_freq = display->cdclk.max_cdclk_freq; - if (DISPLAY_VER(dev_priv) >= 10) - return 2 * max_cdclk_freq; - else if (DISPLAY_VER(dev_priv) == 9 || - IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) - return max_cdclk_freq; - else if (IS_CHERRYVIEW(dev_priv)) - return max_cdclk_freq*95/100; - else if (DISPLAY_VER(dev_priv) < 4) - return 2*max_cdclk_freq*90/100; - else - return max_cdclk_freq*90/100; + return ppc * max_cdclk_freq * guardband / 100; } /** * intel_update_max_cdclk - Determine the maximum support CDCLK frequency - * @dev_priv: i915 device + * @display: display instance * * Determine the maximum CDCLK frequency the platform supports, and also * derive the maximum dot clock frequency the maximum CDCLK frequency * allows. */ -void intel_update_max_cdclk(struct drm_i915_private *dev_priv) +void intel_update_max_cdclk(struct intel_display *display) { - if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) { - if (dev_priv->display.cdclk.hw.ref == 24000) - dev_priv->display.cdclk.max_cdclk_freq = 552000; + struct drm_i915_private *dev_priv = to_i915(display->drm); + + if (DISPLAY_VER(display) >= 30) { + display->cdclk.max_cdclk_freq = 691200; + } else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) { + if (display->cdclk.hw.ref == 24000) + display->cdclk.max_cdclk_freq = 552000; else - dev_priv->display.cdclk.max_cdclk_freq = 556800; - } else if (DISPLAY_VER(dev_priv) >= 11) { - if (dev_priv->display.cdclk.hw.ref == 24000) - dev_priv->display.cdclk.max_cdclk_freq = 648000; + display->cdclk.max_cdclk_freq = 556800; + } else if (DISPLAY_VER(display) >= 11) { + if (display->cdclk.hw.ref == 24000) + display->cdclk.max_cdclk_freq = 648000; else - dev_priv->display.cdclk.max_cdclk_freq = 652800; + display->cdclk.max_cdclk_freq = 652800; } else if (IS_GEMINILAKE(dev_priv)) { - dev_priv->display.cdclk.max_cdclk_freq = 316800; + display->cdclk.max_cdclk_freq = 316800; } else if (IS_BROXTON(dev_priv)) { - dev_priv->display.cdclk.max_cdclk_freq = 624000; - } else if (DISPLAY_VER(dev_priv) == 9) { - u32 limit = intel_de_read(dev_priv, SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + display->cdclk.max_cdclk_freq = 624000; + } else if (DISPLAY_VER(display) == 9) { + u32 limit = intel_de_read(display, SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; int max_cdclk, vco; - vco = dev_priv->skl_preferred_vco_freq; - drm_WARN_ON(&dev_priv->drm, vco != 8100000 && vco != 8640000); + vco = display->cdclk.skl_preferred_vco_freq; + drm_WARN_ON(display->drm, vco != 8100000 && vco != 8640000); /* * Use the lower (vco 8640) cdclk values as a @@ -3334,7 +3416,7 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv) else max_cdclk = 308571; - dev_priv->display.cdclk.max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco); + display->cdclk.max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco); } else if (IS_BROADWELL(dev_priv)) { /* * FIXME with extra cooling we can allow @@ -3342,41 +3424,43 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv) * How can we know if extra cooling is * available? PCI ID, VTB, something else? */ - if (intel_de_read(dev_priv, FUSE_STRAP) & HSW_CDCLK_LIMIT) - dev_priv->display.cdclk.max_cdclk_freq = 450000; + if (intel_de_read(display, FUSE_STRAP) & HSW_CDCLK_LIMIT) + display->cdclk.max_cdclk_freq = 450000; else if (IS_BROADWELL_ULX(dev_priv)) - dev_priv->display.cdclk.max_cdclk_freq = 450000; + display->cdclk.max_cdclk_freq = 450000; else if (IS_BROADWELL_ULT(dev_priv)) - dev_priv->display.cdclk.max_cdclk_freq = 540000; + display->cdclk.max_cdclk_freq = 540000; else - dev_priv->display.cdclk.max_cdclk_freq = 675000; + display->cdclk.max_cdclk_freq = 675000; } else if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.cdclk.max_cdclk_freq = 320000; + display->cdclk.max_cdclk_freq = 320000; } else if (IS_VALLEYVIEW(dev_priv)) { - dev_priv->display.cdclk.max_cdclk_freq = 400000; + display->cdclk.max_cdclk_freq = 400000; } else { /* otherwise assume cdclk is fixed */ - dev_priv->display.cdclk.max_cdclk_freq = dev_priv->display.cdclk.hw.cdclk; + display->cdclk.max_cdclk_freq = display->cdclk.hw.cdclk; } - dev_priv->max_dotclk_freq = intel_compute_max_dotclk(dev_priv); + display->cdclk.max_dotclk_freq = intel_compute_max_dotclk(display); - drm_dbg(&dev_priv->drm, "Max CD clock rate: %d kHz\n", - dev_priv->display.cdclk.max_cdclk_freq); + drm_dbg(display->drm, "Max CD clock rate: %d kHz\n", + display->cdclk.max_cdclk_freq); - drm_dbg(&dev_priv->drm, "Max dotclock rate: %d kHz\n", - dev_priv->max_dotclk_freq); + drm_dbg(display->drm, "Max dotclock rate: %d kHz\n", + display->cdclk.max_dotclk_freq); } /** * intel_update_cdclk - Determine the current CDCLK frequency - * @dev_priv: i915 device + * @display: display instance * * Determine the current CDCLK frequency. */ -void intel_update_cdclk(struct drm_i915_private *dev_priv) +void intel_update_cdclk(struct intel_display *display) { - intel_cdclk_get_cdclk(dev_priv, &dev_priv->display.cdclk.hw); + struct drm_i915_private *dev_priv = to_i915(display->drm); + + intel_cdclk_get_cdclk(display, &display->cdclk.hw); /* * 9:0 CMBUS [sic] CDCLK frequency (cdfreq): @@ -3385,28 +3469,29 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv) * generate GMBus clock. This will vary with the cdclk freq. */ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - intel_de_write(dev_priv, GMBUSFREQ_VLV, - DIV_ROUND_UP(dev_priv->display.cdclk.hw.cdclk, 1000)); + intel_de_write(display, GMBUSFREQ_VLV, + DIV_ROUND_UP(display->cdclk.hw.cdclk, 1000)); } -static int dg1_rawclk(struct drm_i915_private *dev_priv) +static int dg1_rawclk(struct intel_display *display) { /* * DG1 always uses a 38.4 MHz rawclk. The bspec tells us * "Program Numerator=2, Denominator=4, Divider=37 decimal." */ - intel_de_write(dev_priv, PCH_RAWCLK_FREQ, + intel_de_write(display, PCH_RAWCLK_FREQ, CNP_RAWCLK_DEN(4) | CNP_RAWCLK_DIV(37) | ICP_RAWCLK_NUM(2)); return 38400; } -static int cnp_rawclk(struct drm_i915_private *dev_priv) +static int cnp_rawclk(struct intel_display *display) { - u32 rawclk; + struct drm_i915_private *dev_priv = to_i915(display->drm); int divider, fraction; + u32 rawclk; - if (intel_de_read(dev_priv, SFUSE_STRAP) & SFUSE_STRAP_RAW_FREQUENCY) { + if (intel_de_read(display, SFUSE_STRAP) & SFUSE_STRAP_RAW_FREQUENCY) { /* 24 MHz */ divider = 24000; fraction = 0; @@ -3426,87 +3511,42 @@ static int cnp_rawclk(struct drm_i915_private *dev_priv) rawclk |= ICP_RAWCLK_NUM(numerator); } - intel_de_write(dev_priv, PCH_RAWCLK_FREQ, rawclk); + intel_de_write(display, PCH_RAWCLK_FREQ, rawclk); return divider + fraction; } -static int pch_rawclk(struct drm_i915_private *dev_priv) +static int pch_rawclk(struct intel_display *display) { - return (intel_de_read(dev_priv, PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000; + return (intel_de_read(display, PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000; } -static int vlv_hrawclk(struct drm_i915_private *dev_priv) +static int vlv_hrawclk(struct intel_display *display) { + struct drm_i915_private *dev_priv = to_i915(display->drm); + /* RAWCLK_FREQ_VLV register updated from power well code */ return vlv_get_cck_clock_hpll(dev_priv, "hrawclk", CCK_DISPLAY_REF_CLOCK_CONTROL); } -static int i9xx_hrawclk(struct drm_i915_private *dev_priv) +static int i9xx_hrawclk(struct intel_display *display) { - u32 clkcfg; + struct drm_i915_private *i915 = to_i915(display->drm); - /* - * hrawclock is 1/4 the FSB frequency - * - * Note that this only reads the state of the FSB - * straps, not the actual FSB frequency. Some BIOSen - * let you configure each independently. Ideally we'd - * read out the actual FSB frequency but sadly we - * don't know which registers have that information, - * and all the relevant docs have gone to bit heaven :( - */ - clkcfg = intel_de_read(dev_priv, CLKCFG) & CLKCFG_FSB_MASK; - - if (IS_MOBILE(dev_priv)) { - switch (clkcfg) { - case CLKCFG_FSB_400: - return 100000; - case CLKCFG_FSB_533: - return 133333; - case CLKCFG_FSB_667: - return 166667; - case CLKCFG_FSB_800: - return 200000; - case CLKCFG_FSB_1067: - return 266667; - case CLKCFG_FSB_1333: - return 333333; - default: - MISSING_CASE(clkcfg); - return 133333; - } - } else { - switch (clkcfg) { - case CLKCFG_FSB_400_ALT: - return 100000; - case CLKCFG_FSB_533: - return 133333; - case CLKCFG_FSB_667: - return 166667; - case CLKCFG_FSB_800: - return 200000; - case CLKCFG_FSB_1067_ALT: - return 266667; - case CLKCFG_FSB_1333_ALT: - return 333333; - case CLKCFG_FSB_1600_ALT: - return 400000; - default: - return 133333; - } - } + /* hrawclock is 1/4 the FSB frequency */ + return DIV_ROUND_CLOSEST(i9xx_fsb_freq(i915), 4); } /** * intel_read_rawclk - Determine the current RAWCLK frequency - * @dev_priv: i915 device + * @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 drm_i915_private *dev_priv) +u32 intel_read_rawclk(struct intel_display *display) { + struct drm_i915_private *dev_priv = to_i915(display->drm); u32 freq; if (INTEL_PCH_TYPE(dev_priv) >= PCH_MTL) @@ -3517,15 +3557,15 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) */ freq = 38400; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) - freq = dg1_rawclk(dev_priv); + freq = dg1_rawclk(display); else if (INTEL_PCH_TYPE(dev_priv) >= PCH_CNP) - freq = cnp_rawclk(dev_priv); + freq = cnp_rawclk(display); else if (HAS_PCH_SPLIT(dev_priv)) - freq = pch_rawclk(dev_priv); + freq = pch_rawclk(display); else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - freq = vlv_hrawclk(dev_priv); - else if (DISPLAY_VER(dev_priv) >= 3) - freq = i9xx_hrawclk(dev_priv); + freq = vlv_hrawclk(display); + else if (DISPLAY_VER(display) >= 3) + freq = i9xx_hrawclk(display); else /* no rawclk on other platforms, or no need to know it */ return 0; @@ -3535,30 +3575,30 @@ u32 intel_read_rawclk(struct drm_i915_private *dev_priv) static int i915_cdclk_info_show(struct seq_file *m, void *unused) { - struct drm_i915_private *i915 = m->private; + struct intel_display *display = m->private; - seq_printf(m, "Current CD clock frequency: %d kHz\n", i915->display.cdclk.hw.cdclk); - seq_printf(m, "Max CD clock frequency: %d kHz\n", i915->display.cdclk.max_cdclk_freq); - seq_printf(m, "Max pixel clock frequency: %d kHz\n", i915->max_dotclk_freq); + seq_printf(m, "Current CD clock frequency: %d kHz\n", display->cdclk.hw.cdclk); + seq_printf(m, "Max CD clock frequency: %d kHz\n", display->cdclk.max_cdclk_freq); + seq_printf(m, "Max pixel clock frequency: %d kHz\n", display->cdclk.max_dotclk_freq); return 0; } DEFINE_SHOW_ATTRIBUTE(i915_cdclk_info); -void intel_cdclk_debugfs_register(struct drm_i915_private *i915) +void intel_cdclk_debugfs_register(struct intel_display *display) { - struct drm_minor *minor = i915->drm.primary; + struct drm_minor *minor = display->drm->primary; debugfs_create_file("i915_cdclk_info", 0444, minor->debugfs_root, - i915, &i915_cdclk_info_fops); + display, &i915_cdclk_info_fops); } -static const struct intel_cdclk_funcs mtl_cdclk_funcs = { +static const struct intel_cdclk_funcs xe3lpd_cdclk_funcs = { .get_cdclk = bxt_get_cdclk, .set_cdclk = bxt_set_cdclk, .modeset_calc_cdclk = bxt_modeset_calc_cdclk, - .calc_voltage_level = rplu_calc_voltage_level, + .calc_voltage_level = xe3lpd_calc_voltage_level, }; static const struct intel_cdclk_funcs rplu_cdclk_funcs = { @@ -3699,94 +3739,102 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = { /** * intel_init_cdclk_hooks - Initialize CDCLK related modesetting hooks - * @dev_priv: i915 device + * @display: display instance */ -void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) -{ - if (DISPLAY_VER(dev_priv) >= 20) { - dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; - dev_priv->display.cdclk.table = lnl_cdclk_table; - } else if (DISPLAY_VER(dev_priv) >= 14) { - dev_priv->display.funcs.cdclk = &mtl_cdclk_funcs; - dev_priv->display.cdclk.table = mtl_cdclk_table; +void intel_init_cdclk_hooks(struct intel_display *display) +{ + struct drm_i915_private *dev_priv = to_i915(display->drm); + + if (DISPLAY_VER(display) >= 30) { + display->funcs.cdclk = &xe3lpd_cdclk_funcs; + display->cdclk.table = xe3lpd_cdclk_table; + } else if (DISPLAY_VER(display) >= 20) { + display->funcs.cdclk = &rplu_cdclk_funcs; + display->cdclk.table = xe2lpd_cdclk_table; + } else if (DISPLAY_VERx100(display) >= 1401) { + display->funcs.cdclk = &rplu_cdclk_funcs; + display->cdclk.table = xe2hpd_cdclk_table; + } else if (DISPLAY_VER(display) >= 14) { + display->funcs.cdclk = &rplu_cdclk_funcs; + display->cdclk.table = mtl_cdclk_table; } else if (IS_DG2(dev_priv)) { - dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs; - dev_priv->display.cdclk.table = dg2_cdclk_table; + display->funcs.cdclk = &tgl_cdclk_funcs; + display->cdclk.table = dg2_cdclk_table; } else if (IS_ALDERLAKE_P(dev_priv)) { /* Wa_22011320316:adl-p[a0] */ if (IS_ALDERLAKE_P(dev_priv) && IS_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) { - dev_priv->display.cdclk.table = adlp_a_step_cdclk_table; - dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs; + display->cdclk.table = adlp_a_step_cdclk_table; + display->funcs.cdclk = &tgl_cdclk_funcs; } else if (IS_RAPTORLAKE_U(dev_priv)) { - dev_priv->display.cdclk.table = rplu_cdclk_table; - dev_priv->display.funcs.cdclk = &rplu_cdclk_funcs; + display->cdclk.table = rplu_cdclk_table; + display->funcs.cdclk = &rplu_cdclk_funcs; } else { - dev_priv->display.cdclk.table = adlp_cdclk_table; - dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs; + display->cdclk.table = adlp_cdclk_table; + display->funcs.cdclk = &tgl_cdclk_funcs; } } else if (IS_ROCKETLAKE(dev_priv)) { - dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs; - dev_priv->display.cdclk.table = rkl_cdclk_table; - } else if (DISPLAY_VER(dev_priv) >= 12) { - dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs; - dev_priv->display.cdclk.table = icl_cdclk_table; + display->funcs.cdclk = &tgl_cdclk_funcs; + display->cdclk.table = rkl_cdclk_table; + } else if (DISPLAY_VER(display) >= 12) { + display->funcs.cdclk = &tgl_cdclk_funcs; + display->cdclk.table = icl_cdclk_table; } else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) { - dev_priv->display.funcs.cdclk = &ehl_cdclk_funcs; - dev_priv->display.cdclk.table = icl_cdclk_table; - } else if (DISPLAY_VER(dev_priv) >= 11) { - dev_priv->display.funcs.cdclk = &icl_cdclk_funcs; - dev_priv->display.cdclk.table = icl_cdclk_table; + display->funcs.cdclk = &ehl_cdclk_funcs; + display->cdclk.table = icl_cdclk_table; + } else if (DISPLAY_VER(display) >= 11) { + display->funcs.cdclk = &icl_cdclk_funcs; + display->cdclk.table = icl_cdclk_table; } else if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) { - dev_priv->display.funcs.cdclk = &bxt_cdclk_funcs; + display->funcs.cdclk = &bxt_cdclk_funcs; if (IS_GEMINILAKE(dev_priv)) - dev_priv->display.cdclk.table = glk_cdclk_table; + display->cdclk.table = glk_cdclk_table; else - dev_priv->display.cdclk.table = bxt_cdclk_table; - } else if (DISPLAY_VER(dev_priv) == 9) { - dev_priv->display.funcs.cdclk = &skl_cdclk_funcs; + display->cdclk.table = bxt_cdclk_table; + } else if (DISPLAY_VER(display) == 9) { + display->funcs.cdclk = &skl_cdclk_funcs; } else if (IS_BROADWELL(dev_priv)) { - dev_priv->display.funcs.cdclk = &bdw_cdclk_funcs; + display->funcs.cdclk = &bdw_cdclk_funcs; } else if (IS_HASWELL(dev_priv)) { - dev_priv->display.funcs.cdclk = &hsw_cdclk_funcs; + display->funcs.cdclk = &hsw_cdclk_funcs; } else if (IS_CHERRYVIEW(dev_priv)) { - dev_priv->display.funcs.cdclk = &chv_cdclk_funcs; + display->funcs.cdclk = &chv_cdclk_funcs; } else if (IS_VALLEYVIEW(dev_priv)) { - dev_priv->display.funcs.cdclk = &vlv_cdclk_funcs; + display->funcs.cdclk = &vlv_cdclk_funcs; } else if (IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv)) { - dev_priv->display.funcs.cdclk = &fixed_400mhz_cdclk_funcs; + display->funcs.cdclk = &fixed_400mhz_cdclk_funcs; } else if (IS_IRONLAKE(dev_priv)) { - dev_priv->display.funcs.cdclk = &ilk_cdclk_funcs; + display->funcs.cdclk = &ilk_cdclk_funcs; } else if (IS_GM45(dev_priv)) { - dev_priv->display.funcs.cdclk = &gm45_cdclk_funcs; + display->funcs.cdclk = &gm45_cdclk_funcs; } else if (IS_G45(dev_priv)) { - dev_priv->display.funcs.cdclk = &g33_cdclk_funcs; + display->funcs.cdclk = &g33_cdclk_funcs; } else if (IS_I965GM(dev_priv)) { - dev_priv->display.funcs.cdclk = &i965gm_cdclk_funcs; + display->funcs.cdclk = &i965gm_cdclk_funcs; } else if (IS_I965G(dev_priv)) { - dev_priv->display.funcs.cdclk = &fixed_400mhz_cdclk_funcs; + display->funcs.cdclk = &fixed_400mhz_cdclk_funcs; } else if (IS_PINEVIEW(dev_priv)) { - dev_priv->display.funcs.cdclk = &pnv_cdclk_funcs; + display->funcs.cdclk = &pnv_cdclk_funcs; } else if (IS_G33(dev_priv)) { - dev_priv->display.funcs.cdclk = &g33_cdclk_funcs; + display->funcs.cdclk = &g33_cdclk_funcs; } else if (IS_I945GM(dev_priv)) { - dev_priv->display.funcs.cdclk = &i945gm_cdclk_funcs; + display->funcs.cdclk = &i945gm_cdclk_funcs; } else if (IS_I945G(dev_priv)) { - dev_priv->display.funcs.cdclk = &fixed_400mhz_cdclk_funcs; + display->funcs.cdclk = &fixed_400mhz_cdclk_funcs; } else if (IS_I915GM(dev_priv)) { - dev_priv->display.funcs.cdclk = &i915gm_cdclk_funcs; + display->funcs.cdclk = &i915gm_cdclk_funcs; } else if (IS_I915G(dev_priv)) { - dev_priv->display.funcs.cdclk = &i915g_cdclk_funcs; + display->funcs.cdclk = &i915g_cdclk_funcs; } else if (IS_I865G(dev_priv)) { - dev_priv->display.funcs.cdclk = &i865g_cdclk_funcs; + display->funcs.cdclk = &i865g_cdclk_funcs; } else if (IS_I85X(dev_priv)) { - dev_priv->display.funcs.cdclk = &i85x_cdclk_funcs; + display->funcs.cdclk = &i85x_cdclk_funcs; } else if (IS_I845G(dev_priv)) { - dev_priv->display.funcs.cdclk = &i845g_cdclk_funcs; + display->funcs.cdclk = &i845g_cdclk_funcs; } else if (IS_I830(dev_priv)) { - dev_priv->display.funcs.cdclk = &i830_cdclk_funcs; + display->funcs.cdclk = &i830_cdclk_funcs; } - if (drm_WARN(&dev_priv->drm, !dev_priv->display.funcs.cdclk, + if (drm_WARN(display->drm, !display->funcs.cdclk, "Unknown platform. Assuming i830\n")) - dev_priv->display.funcs.cdclk = &i830_cdclk_funcs; + display->funcs.cdclk = &i830_cdclk_funcs; } |