From 7e6c064ed834c86bb517841b72bed146d1a2d36d Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Tue, 19 Jan 2021 11:29:30 -0800 Subject: [PATCH 001/142] drm/i915/tgl: Use TGL stepping info for applying WAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TGL adds another level of indirection for applying WA based on stepping information rather than PCI REVID. So change TGL_REVID enum into stepping enum and use PCI REVID as index into revid to stepping table to fetch correct display and GT stepping for application of WAs as suggested by Matt Roper. Cc: Matt Roper Cc: Lucas De Marchi Cc: José Roberto de Souza Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210119192931.1116500-1-lucas.demarchi@intel.com --- .../drm/i915/display/intel_display_power.c | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 4 +- drivers/gpu/drm/i915/display/intel_sprite.c | 2 +- drivers/gpu/drm/i915/gt/intel_workarounds.c | 26 +++++----- drivers/gpu/drm/i915/i915_drv.h | 50 +++++++++---------- drivers/gpu/drm/i915/intel_pm.c | 2 +- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index d52374f013168..bb04b502a442a 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -5340,7 +5340,7 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv) int config, i; if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0) || - IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B0)) + IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_B0)) /* Wa_1409767108:tgl,dg1 */ table = wa_1409767108_buddy_page_masks; else diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index c24ae69426cf3..a93717178957f 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -550,7 +550,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (dev_priv->psr.psr2_sel_fetch_enabled) { /* WA 1408330847 */ - if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) || + if (IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_A0) || IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)) intel_de_rmw(dev_priv, CHICKEN_PAR1_1, DIS_RAM_BYPASS_PSR2_MAN_TRACK, @@ -1102,7 +1102,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) /* WA 1408330847 */ if (dev_priv->psr.psr2_sel_fetch_enabled && - (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_A0) || + (IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_A0) || IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))) intel_de_rmw(dev_priv, CHICKEN_PAR1_1, DIS_RAM_BYPASS_PSR2_MAN_TRACK, 0); diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index cf3589fd0ddb3..4ce32df3855fc 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -3033,7 +3033,7 @@ static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, { /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */ if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) || - IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_C0)) + IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0)) return false; return plane_id < PLANE_SPRITE4; diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index d99773e6776ee..077c18fe1ae7d 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -71,17 +71,17 @@ const struct i915_rev_steppings kbl_revids[] = { [7] = { .gt_stepping = KBL_REVID_G0, .disp_stepping = KBL_REVID_C0 }, }; -const struct i915_rev_steppings tgl_uy_revids[] = { - [0] = { .gt_stepping = TGL_REVID_A0, .disp_stepping = TGL_REVID_A0 }, - [1] = { .gt_stepping = TGL_REVID_B0, .disp_stepping = TGL_REVID_C0 }, - [2] = { .gt_stepping = TGL_REVID_B1, .disp_stepping = TGL_REVID_C0 }, - [3] = { .gt_stepping = TGL_REVID_C0, .disp_stepping = TGL_REVID_D0 }, +const struct i915_rev_steppings tgl_uy_revid_step_tbl[] = { + [0] = { .gt_stepping = STEP_A0, .disp_stepping = STEP_A0 }, + [1] = { .gt_stepping = STEP_B0, .disp_stepping = STEP_C0 }, + [2] = { .gt_stepping = STEP_B1, .disp_stepping = STEP_C0 }, + [3] = { .gt_stepping = STEP_C0, .disp_stepping = STEP_D0 }, }; /* Same GT stepping between tgl_uy_revids and tgl_revids don't mean the same HW */ -const struct i915_rev_steppings tgl_revids[] = { - [0] = { .gt_stepping = TGL_REVID_A0, .disp_stepping = TGL_REVID_B0 }, - [1] = { .gt_stepping = TGL_REVID_B0, .disp_stepping = TGL_REVID_D0 }, +const struct i915_rev_steppings tgl_revid_step_tbl[] = { + [0] = { .gt_stepping = STEP_A0, .disp_stepping = STEP_B0 }, + [1] = { .gt_stepping = STEP_B0, .disp_stepping = STEP_D0 }, }; static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name) @@ -1123,19 +1123,19 @@ tgl_gt_workarounds_init(struct drm_i915_private *i915, struct i915_wa_list *wal) gen12_gt_workarounds_init(i915, wal); /* Wa_1409420604:tgl */ - if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) + if (IS_TGL_UY_GT_STEPPING(i915, STEP_A0, STEP_A0)) wa_write_or(wal, SUBSLICE_UNIT_LEVEL_CLKGATE2, CPSSUNIT_CLKGATE_DIS); /* Wa_1607087056:tgl also know as BUG:1409180338 */ - if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) + if (IS_TGL_UY_GT_STEPPING(i915, STEP_A0, STEP_A0)) wa_write_or(wal, SLICE_UNIT_LEVEL_CLKGATE, L3_CLKGATE_DIS | L3_CR2X_CLKGATE_DIS); /* Wa_1408615072:tgl[a0] */ - if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) + if (IS_TGL_UY_GT_STEPPING(i915, STEP_A0, STEP_A0)) wa_write_or(wal, UNSLICE_UNIT_LEVEL_CLKGATE2, VSUNIT_CLKGATE_DIS_TGL); } @@ -1613,7 +1613,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) struct drm_i915_private *i915 = engine->i915; if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || - IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) { + IS_TGL_UY_GT_STEPPING(i915, STEP_A0, STEP_A0)) { /* * Wa_1607138336:tgl[a0],dg1[a0] * Wa_1607063988:tgl[a0],dg1[a0] @@ -1623,7 +1623,7 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN12_DISABLE_POSH_BUSY_FF_DOP_CG); } - if (IS_TGL_UY_GT_REVID(i915, TGL_REVID_A0, TGL_REVID_A0)) { + if (IS_TGL_UY_GT_STEPPING(i915, STEP_A0, STEP_A0)) { /* * Wa_1606679103:tgl * (see also Wa_1606682166:icl) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e3d58299b323f..c7d5a9bed4417 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1559,54 +1559,54 @@ extern const struct i915_rev_steppings kbl_revids[]; (IS_JSL_EHL(p) && IS_REVID(p, since, until)) enum { - TGL_REVID_A0, - TGL_REVID_B0, - TGL_REVID_B1, - TGL_REVID_C0, - TGL_REVID_D0, + STEP_A0, + STEP_B0, + STEP_B1, + STEP_C0, + STEP_D0, }; -#define TGL_UY_REVIDS_SIZE 4 -#define TGL_REVIDS_SIZE 2 +#define TGL_UY_REVID_STEP_TBL_SIZE 4 +#define TGL_REVID_STEP_TBL_SIZE 2 -extern const struct i915_rev_steppings tgl_uy_revids[TGL_UY_REVIDS_SIZE]; -extern const struct i915_rev_steppings tgl_revids[TGL_REVIDS_SIZE]; +extern const struct i915_rev_steppings tgl_uy_revid_step_tbl[TGL_UY_REVID_STEP_TBL_SIZE]; +extern const struct i915_rev_steppings tgl_revid_step_tbl[TGL_REVID_STEP_TBL_SIZE]; static inline const struct i915_rev_steppings * -tgl_revids_get(struct drm_i915_private *dev_priv) +tgl_stepping_get(struct drm_i915_private *dev_priv) { u8 revid = INTEL_REVID(dev_priv); u8 size; - const struct i915_rev_steppings *tgl_revid_tbl; + const struct i915_rev_steppings *revid_step_tbl; if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { - tgl_revid_tbl = tgl_uy_revids; - size = ARRAY_SIZE(tgl_uy_revids); + revid_step_tbl = tgl_uy_revid_step_tbl; + size = ARRAY_SIZE(tgl_uy_revid_step_tbl); } else { - tgl_revid_tbl = tgl_revids; - size = ARRAY_SIZE(tgl_revids); + revid_step_tbl = tgl_revid_step_tbl; + size = ARRAY_SIZE(tgl_revid_step_tbl); } revid = min_t(u8, revid, size - 1); - return &tgl_revid_tbl[revid]; + return &revid_step_tbl[revid]; } -#define IS_TGL_DISP_REVID(p, since, until) \ +#define IS_TGL_DISP_STEPPING(p, since, until) \ (IS_TIGERLAKE(p) && \ - tgl_revids_get(p)->disp_stepping >= (since) && \ - tgl_revids_get(p)->disp_stepping <= (until)) + tgl_stepping_get(p)->disp_stepping >= (since) && \ + tgl_stepping_get(p)->disp_stepping <= (until)) -#define IS_TGL_UY_GT_REVID(p, since, until) \ +#define IS_TGL_UY_GT_STEPPING(p, since, until) \ ((IS_TGL_U(p) || IS_TGL_Y(p)) && \ - tgl_revids_get(p)->gt_stepping >= (since) && \ - tgl_revids_get(p)->gt_stepping <= (until)) + tgl_stepping_get(p)->gt_stepping >= (since) && \ + tgl_stepping_get(p)->gt_stepping <= (until)) -#define IS_TGL_GT_REVID(p, since, until) \ +#define IS_TGL_GT_STEPPING(p, since, until) \ (IS_TIGERLAKE(p) && \ !(IS_TGL_U(p) || IS_TGL_Y(p)) && \ - tgl_revids_get(p)->gt_stepping >= (since) && \ - tgl_revids_get(p)->gt_stepping <= (until)) + tgl_stepping_get(p)->gt_stepping >= (since) && \ + tgl_stepping_get(p)->gt_stepping <= (until)) #define RKL_REVID_A0 0x0 #define RKL_REVID_B0 0x1 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bbc73df7f753b..319acca2630b9 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7110,7 +7110,7 @@ static void tgl_init_clock_gating(struct drm_i915_private *dev_priv) ILK_DPFC_CHICKEN_COMP_DUMMY_PIXEL); /* Wa_1409825376:tgl (pre-prod)*/ - if (IS_TGL_DISP_REVID(dev_priv, TGL_REVID_A0, TGL_REVID_B1)) + if (IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_B1)) intel_uncore_write(&dev_priv->uncore, GEN9_CLKGATE_DIS_3, intel_uncore_read(&dev_priv->uncore, GEN9_CLKGATE_DIS_3) | TGL_VRH_GATING_DIS); From 0883d63b19bbd6bb09f27786e768c1af09aa0ede Mon Sep 17 00:00:00 2001 From: Caz Yokoyama Date: Tue, 19 Jan 2021 11:29:31 -0800 Subject: [PATCH 002/142] drm/i915/adl_s: Add ADL-S platform info and PCI ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add the initial platform information for Alderlake-S. - Specify ppgtt_size value - Add dma_mask_size - Add ADLS REVIDs - HW tracking(Selective Update Tracking Enable) has been removed from ADLS. Disable PSR2 till we enable software/ manual tracking. v2: - Add support for different ADLS SOC steppings to select correct GT/DISP stepping based on Bspec 53655 based on feedback from Matt Roper.(aswarup) v3: - Make display/gt steppings info generic for reuse with TGL and ADLS. - Modify the macros to reuse tgl_revids_get() - Add HTI support to adls device info.(mdroper) v4: - Rebase on TGL patch for applying WAs based on stepping info from Matt Roper's feedback.(aswarup) v5: - Replace macros with PCI IDs in revid to stepping table. v6: remove stray adls_revids (Lucas) Bspec: 53597 Bspec: 53648 Bspec: 53655 Bspec: 48028 Bspec: 53650 BSpec: 50422 Cc: José Roberto de Souza Cc: Matt Roper Cc: Lucas De Marchi Cc: Anusha Srivatsa Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Signed-off-by: Caz Yokoyama Signed-off-by: Aditya Swarup Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210119192931.1116500-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 8 +++++++ drivers/gpu/drm/i915/i915_drv.h | 25 ++++++++++++++++++++- drivers/gpu/drm/i915/i915_pci.c | 13 +++++++++++ drivers/gpu/drm/i915/intel_device_info.c | 1 + drivers/gpu/drm/i915/intel_device_info.h | 1 + include/drm/i915_pciids.h | 11 +++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 077c18fe1ae7d..4b95ce5d2d3c5 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -84,6 +84,14 @@ const struct i915_rev_steppings tgl_revid_step_tbl[] = { [1] = { .gt_stepping = STEP_B0, .disp_stepping = STEP_D0 }, }; +const struct i915_rev_steppings adls_revid_step_tbl[] = { + [0x0] = { .gt_stepping = STEP_A0, .disp_stepping = STEP_A0 }, + [0x1] = { .gt_stepping = STEP_A0, .disp_stepping = STEP_A2 }, + [0x4] = { .gt_stepping = STEP_B0, .disp_stepping = STEP_B0 }, + [0x8] = { .gt_stepping = STEP_C0, .disp_stepping = STEP_B0 }, + [0xC] = { .gt_stepping = STEP_D0, .disp_stepping = STEP_C0 }, +}; + static void wa_init_start(struct i915_wa_list *wal, const char *name, const char *engine_name) { wal->name = name; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c7d5a9bed4417..3b75b5ee4c889 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1417,6 +1417,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_TIGERLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_TIGERLAKE) #define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, INTEL_ROCKETLAKE) #define IS_DG1(dev_priv) IS_PLATFORM(dev_priv, INTEL_DG1) +#define IS_ALDERLAKE_S(dev_priv) IS_PLATFORM(dev_priv, INTEL_ALDERLAKE_S) #define IS_HSW_EARLY_SDV(dev_priv) (IS_HASWELL(dev_priv) && \ (INTEL_DEVID(dev_priv) & 0xFF00) == 0x0C00) #define IS_BDW_ULT(dev_priv) \ @@ -1560,6 +1561,7 @@ extern const struct i915_rev_steppings kbl_revids[]; enum { STEP_A0, + STEP_A2, STEP_B0, STEP_B1, STEP_C0, @@ -1568,9 +1570,11 @@ enum { #define TGL_UY_REVID_STEP_TBL_SIZE 4 #define TGL_REVID_STEP_TBL_SIZE 2 +#define ADLS_REVID_STEP_TBL_SIZE 13 extern const struct i915_rev_steppings tgl_uy_revid_step_tbl[TGL_UY_REVID_STEP_TBL_SIZE]; extern const struct i915_rev_steppings tgl_revid_step_tbl[TGL_REVID_STEP_TBL_SIZE]; +extern const struct i915_rev_steppings adls_revid_step_tbl[ADLS_REVID_STEP_TBL_SIZE]; static inline const struct i915_rev_steppings * tgl_stepping_get(struct drm_i915_private *dev_priv) @@ -1579,7 +1583,10 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) u8 size; const struct i915_rev_steppings *revid_step_tbl; - if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + revid_step_tbl = adls_revid_step_tbl; + size = ARRAY_SIZE(adls_revid_step_tbl); + } else if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { revid_step_tbl = tgl_uy_revid_step_tbl; size = ARRAY_SIZE(tgl_uy_revid_step_tbl); } else { @@ -1621,6 +1628,22 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) #define IS_DG1_REVID(p, since, until) \ (IS_DG1(p) && IS_REVID(p, since, until)) +#define ADLS_REVID_A0 0x0 +#define ADLS_REVID_A2 0x1 +#define ADLS_REVID_B0 0x4 +#define ADLS_REVID_G0 0x8 +#define ADLS_REVID_C0 0xC /*Same as H0 ADLS SOC stepping*/ + +#define IS_ADLS_DISP_STEPPING(p, since, until) \ + (IS_ALDERLAKE_S(p) && \ + tgl_stepping_get(p)->disp_stepping >= (since) && \ + tgl_stepping_get(p)->disp_stepping <= (until)) + +#define IS_ADLS_GT_STEPPING(p, since, until) \ + (IS_ALDERLAKE_S(p) && \ + tgl_stepping_get(p)->gt_stepping >= (since) && \ + tgl_stepping_get(p)->gt_stepping <= (until)) + #define IS_LP(dev_priv) (INTEL_INFO(dev_priv)->is_lp) #define IS_GEN9_LP(dev_priv) (IS_GEN(dev_priv, 9) && IS_LP(dev_priv)) #define IS_GEN9_BC(dev_priv) (IS_GEN(dev_priv, 9) && !IS_LP(dev_priv)) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 39608381b4a41..73a10dc876429 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -923,6 +923,18 @@ static const struct intel_device_info dg1_info __maybe_unused = { .ppgtt_size = 47, }; +static const struct intel_device_info adl_s_info = { + GEN12_FEATURES, + PLATFORM(INTEL_ALDERLAKE_S), + .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), + .require_force_probe = 1, + .display.has_hti = 1, + .display.has_psr_hw_tracking = 0, + .platform_engine_mask = + BIT(RCS0) | BIT(BCS0) | BIT(VECS0) | BIT(VCS0) | BIT(VCS2), + .dma_mask_size = 46, +}; + #undef GEN #undef PLATFORM @@ -999,6 +1011,7 @@ static const struct pci_device_id pciidlist[] = { INTEL_JSL_IDS(&jsl_info), INTEL_TGL_12_IDS(&tgl_info), INTEL_RKL_IDS(&rkl_info), + INTEL_ADLS_IDS(&adl_s_info), {0, 0, 0} }; MODULE_DEVICE_TABLE(pci, pciidlist); diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index f2d5ae59081e4..699412c14c1d1 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -66,6 +66,7 @@ static const char * const platform_names[] = { PLATFORM_NAME(TIGERLAKE), PLATFORM_NAME(ROCKETLAKE), PLATFORM_NAME(DG1), + PLATFORM_NAME(ALDERLAKE_S), }; #undef PLATFORM_NAME diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index cf2d528c6e9b0..79dab5a6f2724 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -84,6 +84,7 @@ enum intel_platform { INTEL_TIGERLAKE, INTEL_ROCKETLAKE, INTEL_DG1, + INTEL_ALDERLAKE_S, INTEL_MAX_PLATFORMS }; diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 931e461910476..ebd0dd1c35b33 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -634,4 +634,15 @@ INTEL_VGA_DEVICE(0x4907, info), \ INTEL_VGA_DEVICE(0x4908, info) +/* ADL-S */ +#define INTEL_ADLS_IDS(info) \ + INTEL_VGA_DEVICE(0x4680, info), \ + INTEL_VGA_DEVICE(0x4681, info), \ + INTEL_VGA_DEVICE(0x4682, info), \ + INTEL_VGA_DEVICE(0x4683, info), \ + INTEL_VGA_DEVICE(0x4690, info), \ + INTEL_VGA_DEVICE(0x4691, info), \ + INTEL_VGA_DEVICE(0x4692, info), \ + INTEL_VGA_DEVICE(0x4693, info) + #endif /* _I915_PCIIDS_H */ From c6bba9e5fedf1391a52f1cd21d1ed6ac5fd99e55 Mon Sep 17 00:00:00 2001 From: Caz Yokoyama Date: Mon, 25 Jan 2021 16:17:44 -0800 Subject: [PATCH 003/142] x86/gpu: Add Alderlake-S stolen memory support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alderlake-S is a Gen 12 based hybrid processor architecture. As it belongs to Gen 12 family, it uses the same GTT stolen memory settings like its predecessors - ICL(Gen 11) and TGL(Gen 12). Inherit gen11 and gen 9 quirks for determining base and size of stolen memory. Bspec: 52055 Bspec: 49589 Bspec: 49636 Cc: Lucas De Marchi Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: x86@kernel.org Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Borislav Petkov Signed-off-by: Caz Yokoyama Signed-off-by: Aditya Swarup Reviewed-by: Lucas De Marchi Acked-by: Borislav Petkov Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210126001744.29442-2-aditya.swarup@intel.com --- arch/x86/kernel/early-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index a4b5af03dcc1b..6edd1e2ee8afa 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -551,6 +551,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = { INTEL_EHL_IDS(&gen11_early_ops), INTEL_TGL_12_IDS(&gen11_early_ops), INTEL_RKL_IDS(&gen11_early_ops), + INTEL_ADLS_IDS(&gen11_early_ops), }; struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0); From fb51970b8d115842821005032d0a34f7fec7f5fe Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 25 Jan 2021 06:07:45 -0800 Subject: [PATCH 004/142] drm/i915/adl_s: Add PCH support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Alderpoint(ADP) PCH used with Alderlake-S. v2: - Use drm_dbg_kms and drm_WARN_ON based on Jani's feedback.(aswarup) Cc: Matt Roper Cc: Lucas De Marchi Cc: Caz Yokoyama Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Signed-off-by: Anusha Srivatsa Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-3-aditya.swarup@intel.com --- drivers/gpu/drm/i915/intel_pch.c | 8 +++++++- drivers/gpu/drm/i915/intel_pch.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c index f31c0dabd0ccd..2a6d70f247e84 100644 --- a/drivers/gpu/drm/i915/intel_pch.c +++ b/drivers/gpu/drm/i915/intel_pch.c @@ -128,6 +128,10 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n"); drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv)); return PCH_JSP; + case INTEL_PCH_ADP_DEVICE_ID_TYPE: + drm_dbg_kms(&dev_priv->drm, "Found Alder Lake PCH\n"); + drm_WARN_ON(&dev_priv->drm, !IS_ALDERLAKE_S(dev_priv)); + return PCH_ADP; default: return PCH_NONE; } @@ -155,7 +159,9 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv) * make an educated guess as to which PCH is really there. */ - if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv)) + id = INTEL_PCH_ADP_DEVICE_ID_TYPE; + else if (IS_TIGERLAKE(dev_priv) || IS_ROCKETLAKE(dev_priv)) id = INTEL_PCH_TGP_DEVICE_ID_TYPE; else if (IS_JSL_EHL(dev_priv)) id = INTEL_PCH_MCC_DEVICE_ID_TYPE; diff --git a/drivers/gpu/drm/i915/intel_pch.h b/drivers/gpu/drm/i915/intel_pch.h index 06d2cd50af0b9..7318377503b00 100644 --- a/drivers/gpu/drm/i915/intel_pch.h +++ b/drivers/gpu/drm/i915/intel_pch.h @@ -26,6 +26,7 @@ enum intel_pch { PCH_JSP, /* Jasper Lake PCH */ PCH_MCC, /* Mule Creek Canyon PCH */ PCH_TGP, /* Tiger Lake PCH */ + PCH_ADP, /* Alder Lake PCH */ /* Fake PCHs, functionality handled on the same PCI dev */ PCH_DG1 = 1024, @@ -53,12 +54,14 @@ enum intel_pch { #define INTEL_PCH_TGP2_DEVICE_ID_TYPE 0x4380 #define INTEL_PCH_JSP_DEVICE_ID_TYPE 0x4D80 #define INTEL_PCH_JSP2_DEVICE_ID_TYPE 0x3880 +#define INTEL_PCH_ADP_DEVICE_ID_TYPE 0x7A80 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 #define INTEL_PCH_P3X_DEVICE_ID_TYPE 0x7000 #define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev_priv) ((dev_priv)->pch_type) #define INTEL_PCH_ID(dev_priv) ((dev_priv)->pch_id) +#define HAS_PCH_ADP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_ADP) #define HAS_PCH_DG1(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_DG1) #define HAS_PCH_JSP(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_JSP) #define HAS_PCH_MCC(dev_priv) (INTEL_PCH_TYPE(dev_priv) == PCH_MCC) From fa58c9e4e36402ae3dfaa05914df9d22e2d4d458 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 25 Jan 2021 06:07:46 -0800 Subject: [PATCH 005/142] drm/i915/adl_s: Add Interrupt Support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADLS follows ICP/TGP like interrupts. v2: Use "INTEL_PCH_TYPE(dev_priv) >= PCH_ICP" of hpd_icp (Lucas) Cc: Lucas De Marchi Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: José Roberto de Souza Signed-off-by: Anusha Srivatsa Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-4-aditya.swarup@intel.com --- drivers/gpu/drm/i915/i915_irq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dd1971040bbcc..c6b11f62e32dc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -209,8 +209,7 @@ static void intel_hpd_init_pins(struct drm_i915_private *dev_priv) if (HAS_PCH_DG1(dev_priv)) hpd->pch_hpd = hpd_sde_dg1; - else if (HAS_PCH_TGP(dev_priv) || HAS_PCH_JSP(dev_priv) || - HAS_PCH_ICP(dev_priv) || HAS_PCH_MCC(dev_priv)) + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) hpd->pch_hpd = hpd_icp; else if (HAS_PCH_CNP(dev_priv) || HAS_PCH_SPT(dev_priv)) hpd->pch_hpd = hpd_spt; From a84b4bd1172b8394d5540b51b3cf0f76c0dff17a Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 25 Jan 2021 06:07:47 -0800 Subject: [PATCH 006/142] drm/i915/adl_s: Add PHYs for Alderlake S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alderlake-S has 5 combo phys, add reg definitions for combo phys and update the port to phy helper for ADL-S. v2: - Change IS_GEN() >= 12 to IS_TIGERLAKE() in intel_phy_is_tc() and return false for platforms RKL,DG1 and ADLS.(mdroper) Cc: Lucas De Marchi Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Signed-off-by: Anusha Srivatsa Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-5-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 12 +++++++----- drivers/gpu/drm/i915/i915_reg.h | 5 ++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0189d379a55e9..1eae92e0e2683 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6935,6 +6935,8 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy) { if (phy == PHY_NONE) return false; + else if (IS_ALDERLAKE_S(dev_priv)) + return phy <= PHY_E; else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) return phy <= PHY_D; else if (IS_JSL_EHL(dev_priv)) @@ -6947,11 +6949,9 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy) bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) { - if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) - return false; - else if (INTEL_GEN(dev_priv) >= 12) + if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; - else if (INTEL_GEN(dev_priv) >= 11 && !IS_JSL_EHL(dev_priv)) + else if (IS_ICELAKE(dev_priv)) return phy >= PHY_C && phy <= PHY_F; else return false; @@ -6959,7 +6959,9 @@ bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port) { - if ((IS_DG1(i915) || IS_ROCKETLAKE(i915)) && port >= PORT_TC1) + if (IS_ALDERLAKE_S(i915) && port >= PORT_TC1) + return PHY_B + port - PORT_TC1; + else if ((IS_DG1(i915) || IS_ROCKETLAKE(i915)) && port >= PORT_TC1) return PHY_C + port - PORT_TC1; else if (IS_JSL_EHL(i915) && port == PORT_D) return PHY_A; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1d8ba10847ca1..56ba8f1d04242 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1874,10 +1874,13 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define _ICL_COMBOPHY_B 0x6C000 #define _EHL_COMBOPHY_C 0x160000 #define _RKL_COMBOPHY_D 0x161000 +#define _ADL_COMBOPHY_E 0x16B000 + #define _ICL_COMBOPHY(phy) _PICK(phy, _ICL_COMBOPHY_A, \ _ICL_COMBOPHY_B, \ _EHL_COMBOPHY_C, \ - _RKL_COMBOPHY_D) + _RKL_COMBOPHY_D, \ + _ADL_COMBOPHY_E) /* CNL/ICL Port CL_DW registers */ #define _ICL_PORT_CL_DW(dw, phy) (_ICL_COMBOPHY(phy) + \ From 80d0f76588b55e5226d65776bb5fca7360837f1d Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Mon, 25 Jan 2021 06:07:48 -0800 Subject: [PATCH 007/142] drm/i915/adl_s: Configure DPLL for ADL-S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add changes for configuring DPLL for ADL-S - Reusing DG1 DPLL 2 & DPLL 3 for ADL-S - Extend CNL macro to choose DPLL_ENABLE for ADL-S. - Select CFGCR0 and CFGCR1 for ADL-S plls. On BSpec: 53720 PLL arrangement dig for adls: DPLL2 cfgcr is programmed using _ADLS_DPLL3_CFGCR(0/1) DPLL3 cfgcr is programmed using _ADLS_DPLL4_CFGCR(0/1) v2 (Lucas): add missing update_ref_clks Bspec: 50288 Bspec: 50289 Bspec: 49443 v3 : Adding another bit to HDPORT_DPLL_USED_MASK bitfield for DPLL3_USED.(mdroper) Bspec: 53707 v4: BSpec 53723 has been updated with note - DPLL2 is controlled by DPLL4 CFGCR 0/1.(mdroper) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-6-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 38 +++++++++++++++++-- drivers/gpu/drm/i915/i915_reg.h | 22 ++++++++++- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index f6ad257a260e4..529b1d569af21 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -3559,7 +3559,13 @@ static bool icl_get_combo_phy_dpll(struct intel_atomic_state *state, icl_calc_dpll_state(dev_priv, &pll_params, &port_dpll->hw_state); - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + dpll_mask = + BIT(DPLL_ID_DG1_DPLL3) | + BIT(DPLL_ID_DG1_DPLL2) | + BIT(DPLL_ID_ICL_DPLL1) | + BIT(DPLL_ID_ICL_DPLL0); + } else if (IS_DG1(dev_priv)) { if (port == PORT_D || port == PORT_E) { dpll_mask = BIT(DPLL_ID_DG1_DPLL2) | @@ -3865,7 +3871,10 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv, if (!(val & PLL_ENABLE)) goto out; - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + hw_state->cfgcr0 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR0(id)); + hw_state->cfgcr1 = intel_de_read(dev_priv, ADLS_DPLL_CFGCR1(id)); + } else if (IS_DG1(dev_priv)) { hw_state->cfgcr0 = intel_de_read(dev_priv, DG1_DPLL_CFGCR0(id)); hw_state->cfgcr1 = intel_de_read(dev_priv, DG1_DPLL_CFGCR1(id)); } else if (IS_ROCKETLAKE(dev_priv)) { @@ -3921,7 +3930,10 @@ static void icl_dpll_write(struct drm_i915_private *dev_priv, const enum intel_dpll_id id = pll->info->id; i915_reg_t cfgcr0_reg, cfgcr1_reg; - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + cfgcr0_reg = ADLS_DPLL_CFGCR0(id); + cfgcr1_reg = ADLS_DPLL_CFGCR1(id); + } else if (IS_DG1(dev_priv)) { cfgcr0_reg = DG1_DPLL_CFGCR0(id); cfgcr1_reg = DG1_DPLL_CFGCR1(id); } else if (IS_ROCKETLAKE(dev_priv)) { @@ -4384,6 +4396,22 @@ static const struct intel_dpll_mgr dg1_pll_mgr = { .dump_hw_state = icl_dump_hw_state, }; +static const struct dpll_info adls_plls[] = { + { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, + { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, + { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 }, + { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 }, + { }, +}; + +static const struct intel_dpll_mgr adls_pll_mgr = { + .dpll_info = adls_plls, + .get_dplls = icl_get_dplls, + .put_dplls = icl_put_dplls, + .update_ref_clks = icl_update_dpll_ref_clks, + .dump_hw_state = icl_dump_hw_state, +}; + /** * intel_shared_dpll_init - Initialize shared DPLLs * @dev: drm device @@ -4397,7 +4425,9 @@ void intel_shared_dpll_init(struct drm_device *dev) const struct dpll_info *dpll_info; int i; - if (IS_DG1(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv)) + dpll_mgr = &adls_pll_mgr; + else if (IS_DG1(dev_priv)) dpll_mgr = &dg1_pll_mgr; else if (IS_ROCKETLAKE(dev_priv)) dpll_mgr = &rkl_pll_mgr; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 56ba8f1d04242..191b897ec3ebb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2930,7 +2930,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define MBUS_BBOX_CTL_S2 _MMIO(0x45044) #define HDPORT_STATE _MMIO(0x45050) -#define HDPORT_DPLL_USED_MASK REG_GENMASK(14, 12) +#define HDPORT_DPLL_USED_MASK REG_GENMASK(15, 12) #define HDPORT_DDI_USED(phy) REG_BIT(2 * (phy) + 1) #define HDPORT_ENABLED REG_BIT(0) @@ -10345,11 +10345,14 @@ enum skl_power_gate { /* CNL PLL */ #define DPLL0_ENABLE 0x46010 #define DPLL1_ENABLE 0x46014 +#define _ADLS_DPLL2_ENABLE 0x46018 +#define _ADLS_DPLL3_ENABLE 0x46030 #define PLL_ENABLE (1 << 31) #define PLL_LOCK (1 << 30) #define PLL_POWER_ENABLE (1 << 27) #define PLL_POWER_STATE (1 << 26) -#define CNL_DPLL_ENABLE(pll) _MMIO_PLL(pll, DPLL0_ENABLE, DPLL1_ENABLE) +#define CNL_DPLL_ENABLE(pll) _MMIO_PLL3(pll, DPLL0_ENABLE, DPLL1_ENABLE, \ + _ADLS_DPLL2_ENABLE, _ADLS_DPLL3_ENABLE) #define TBT_PLL_ENABLE _MMIO(0x46020) @@ -10595,6 +10598,21 @@ enum skl_power_gate { _DG1_DPLL2_CFGCR1, \ _DG1_DPLL3_CFGCR1) +/* For ADL-S DPLL4_CFGCR0/1 are used to control DPLL2 */ +#define _ADLS_DPLL3_CFGCR0 0x1642C0 +#define _ADLS_DPLL4_CFGCR0 0x164294 +#define ADLS_DPLL_CFGCR0(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR0, \ + _TGL_DPLL1_CFGCR0, \ + _ADLS_DPLL4_CFGCR0, \ + _ADLS_DPLL3_CFGCR0) + +#define _ADLS_DPLL3_CFGCR1 0x1642C4 +#define _ADLS_DPLL4_CFGCR1 0x164298 +#define ADLS_DPLL_CFGCR1(pll) _MMIO_PLL3(pll, _TGL_DPLL0_CFGCR1, \ + _TGL_DPLL1_CFGCR1, \ + _ADLS_DPLL4_CFGCR1, \ + _ADLS_DPLL3_CFGCR1) + #define _DKL_PHY1_BASE 0x168000 #define _DKL_PHY2_BASE 0x169000 #define _DKL_PHY3_BASE 0x16A000 From d6d2bc996e45073db16d1da1dde2116f3c86955c Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Mon, 25 Jan 2021 06:07:49 -0800 Subject: [PATCH 008/142] drm/i915/adl_s: Configure Port clock registers for ADL-S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add changes to configure port clock registers for ADL-S. Combo phy port clocks are configured by DPCLKA_CFGCR0 and DPCLKA_CFGCR1 registers. The DDI to internal clock mappings in DPCLKA_CFGCR0 register for ADL-S translates to DDI A -> DDIA DDI B -> USBC1 DDI I -> USBC2 For DPCLKA_CFGCR1 DDI J -> USBC3 DDI K -> USBC4 Bspec: 50287 Bspec: 53812 Bspec: 53723 v2: Replace I915_READ() with intel_de_read().(Jani) v3: - Use reg variable to assign ADLS specific registers inorder to replace branching with intel_de_read/write() calls.(mdroper) - Reuse icl_get_ddi_pll() for ADLS to fix issue with updating active dpll on driver load.(aswarup) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-7-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 62 +++++++++++++------- drivers/gpu/drm/i915/display/intel_display.c | 11 +++- drivers/gpu/drm/i915/i915_reg.h | 23 +++++++- 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ef98480014185..4aa94c66e502e 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3163,25 +3163,30 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - u32 val; + u32 val, mask, sel; + i915_reg_t reg; + + if (IS_ALDERLAKE_S(dev_priv)) { + reg = ADLS_DPCLKA_CFGCR(phy); + mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); + sel = ((pll->info->id) << ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy)); + } else if (IS_ROCKETLAKE(dev_priv)) { + reg = ICL_DPCLKA_CFGCR0; + mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + sel = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + } else { + reg = ICL_DPCLKA_CFGCR0; + mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); + sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); + } mutex_lock(&dev_priv->dpll.lock); - val = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0); + val = intel_de_read(dev_priv, reg); drm_WARN_ON(&dev_priv->drm, (val & icl_dpclka_cfgcr0_clk_off(dev_priv, phy)) == 0); if (intel_phy_is_combo(dev_priv, phy)) { - u32 mask, sel; - - if (IS_ROCKETLAKE(dev_priv)) { - mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - sel = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); - } else { - mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); - } - /* * Even though this register references DDIs, note that we * want to pass the PHY rather than the port (DDI). For @@ -3194,12 +3199,12 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, */ val &= ~mask; val |= sel; - intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val); - intel_de_posting_read(dev_priv, ICL_DPCLKA_CFGCR0); + intel_de_write(dev_priv, reg, val); + intel_de_posting_read(dev_priv, reg); } val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, phy); - intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val); + intel_de_write(dev_priv, reg, val); mutex_unlock(&dev_priv->dpll.lock); } @@ -3222,12 +3227,19 @@ static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); u32 val; + i915_reg_t reg; mutex_lock(&dev_priv->dpll.lock); - val = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0); + if (IS_ALDERLAKE_S(dev_priv)) + reg = ADLS_DPCLKA_CFGCR(phy); + else + reg = ICL_DPCLKA_CFGCR0; + + val = intel_de_read(dev_priv, reg); val |= icl_dpclka_cfgcr0_clk_off(dev_priv, phy); - intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val); + + intel_de_write(dev_priv, reg, val); mutex_unlock(&dev_priv->dpll.lock); } @@ -3267,13 +3279,21 @@ static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv, u32 port_mask, bool ddi_clk_needed) { enum port port; + bool ddi_clk_off; u32 val; + i915_reg_t reg; - val = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0); for_each_port_masked(port, port_mask) { enum phy phy = intel_port_to_phy(dev_priv, port); - bool ddi_clk_off = val & icl_dpclka_cfgcr0_clk_off(dev_priv, - phy); + + if (IS_ALDERLAKE_S(dev_priv)) + reg = ADLS_DPCLKA_CFGCR(phy); + else + reg = ICL_DPCLKA_CFGCR0; + + val = intel_de_read(dev_priv, reg); + ddi_clk_off = val & icl_dpclka_cfgcr0_clk_off(dev_priv, + phy); if (ddi_clk_needed == !ddi_clk_off) continue; @@ -3289,7 +3309,7 @@ static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv, "PHY %c is disabled/in DSI mode with an ungated DDI clock, gate it\n", phy_name(phy)); val |= icl_dpclka_cfgcr0_clk_off(dev_priv, phy); - intel_de_write(dev_priv, ICL_DPCLKA_CFGCR0, val); + intel_de_write(dev_priv, reg, val); } } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1eae92e0e2683..d7d76e68160f0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -10598,20 +10598,27 @@ static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, struct intel_shared_dpll *pll; enum intel_dpll_id id; bool pll_active; + i915_reg_t reg; u32 temp; if (intel_phy_is_combo(dev_priv, phy)) { u32 mask, shift; - if (IS_ROCKETLAKE(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + reg = ADLS_DPCLKA_CFGCR(phy); + mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); + shift = ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy); + } else if (IS_ROCKETLAKE(dev_priv)) { + reg = ICL_DPCLKA_CFGCR0; mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); } else { + reg = ICL_DPCLKA_CFGCR0; mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); } - temp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0) & mask; + temp = intel_de_read(dev_priv, reg) & mask; id = temp >> shift; port_dpll_id = ICL_PORT_DPLL_DEFAULT; } else if (intel_phy_is_tc(dev_priv, phy)) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 191b897ec3ebb..fe040de1c2aab 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -10307,7 +10307,7 @@ enum skl_power_gate { /* ICL Clocks */ #define ICL_DPCLKA_CFGCR0 _MMIO(0x164280) -#define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24)) +#define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) (1 << _PICK(phy, 10, 11, 24, 4, 5)) #define RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy) REG_BIT((phy) + 10) #define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) < TC_PORT_4 ? \ (tc_port) + 12 : \ @@ -10342,6 +10342,27 @@ enum skl_power_gate { #define DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy) \ (((clk_sel) >> DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)) + _DG1_PHY_DPLL_MAP(phy)) +/* ADLS Clocks */ +#define _ADLS_DPCLKA_CFGCR0 0x164280 +#define _ADLS_DPCLKA_CFGCR1 0x1642BC +#define ADLS_DPCLKA_CFGCR(phy) _MMIO_PHY((phy) / 3, \ + _ADLS_DPCLKA_CFGCR0, \ + _ADLS_DPCLKA_CFGCR1) +#define ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy) (((phy) % 3) * 2) +/* ADLS DPCLKA_CFGCR0 DDI mask */ +#define ADLS_DPCLKA_DDII_SEL_MASK REG_GENMASK(5, 4) +#define ADLS_DPCLKA_DDIB_SEL_MASK REG_GENMASK(3, 2) +#define ADLS_DPCLKA_DDIA_SEL_MASK REG_GENMASK(1, 0) +/* ADLS DPCLKA_CFGCR1 DDI mask */ +#define ADLS_DPCLKA_DDIK_SEL_MASK REG_GENMASK(3, 2) +#define ADLS_DPCLKA_DDIJ_SEL_MASK REG_GENMASK(1, 0) +#define ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy) _PICK((phy), \ + ADLS_DPCLKA_DDIA_SEL_MASK, \ + ADLS_DPCLKA_DDIB_SEL_MASK, \ + ADLS_DPCLKA_DDII_SEL_MASK, \ + ADLS_DPCLKA_DDIJ_SEL_MASK, \ + ADLS_DPCLKA_DDIK_SEL_MASK) + /* CNL PLL */ #define DPLL0_ENABLE 0x46010 #define DPLL1_ENABLE 0x46014 From e341c618acde39ea9bfd83d8262b4c4c70e92a5b Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Mon, 25 Jan 2021 06:07:50 -0800 Subject: [PATCH 009/142] drm/i915/adl_s: Initialize display for ADL-S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize display outputs for ADL-S. ADL-S has 5 display outputs -> 1 eDP, 2 HDMI and 2 DP++ outputs. v2: - Use PORT_TCx instead of PORT_D,E.. to stay consistent with other platforms.(mdroper) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-8-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d7d76e68160f0..ac3975ba934d1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -16155,7 +16155,13 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + intel_ddi_init(dev_priv, PORT_A); + intel_ddi_init(dev_priv, PORT_TC1); + intel_ddi_init(dev_priv, PORT_TC2); + intel_ddi_init(dev_priv, PORT_TC3); + intel_ddi_init(dev_priv, PORT_TC4); + } else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) { intel_ddi_init(dev_priv, PORT_A); intel_ddi_init(dev_priv, PORT_B); intel_ddi_init(dev_priv, PORT_TC1); From 7dc1f92f27f8d7046ff4bd4cb113b1f522b175e8 Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Mon, 25 Jan 2021 06:07:51 -0800 Subject: [PATCH 010/142] drm/i915/adl_s: Add adl-s ddc pin mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADL-S requires TC pins to set up ddc for Combo PHY B, C, D and E. Combo PHY A still uses the old ddc pin mapping. From VBT, ddc pin info suggests the following mapping: VBT DRIVER DDI B->ddc_pin=2 should translate to PORT_D->0x9 DDI C->ddc_pin=3 should translate to PORT_E->0xa DDI D->ddc_pin=4 should translate to PORT_F->0xb DDI E->ddc_pin=5 should translate to PORT_G->0xc Adding pin map to facilitate this translation as we cannot use existing icl ddc pin map due to conflict with DDI B and DDI C info. Bspec:20124 v2: Replace IS_ALDERLAKE_S() with HAS_PCH_ADP() as the pin map pairing depends on the PCH being used rather than the platform.(mdroper) v3: - Modify adls_port_to_ddc_pin() to make PHY_A the special case for check, else return pin mapping based on correct arithmetic with phy offset. Remove redundant platform checks and use HAS_PCH_ADP() instead of IS_ALDERLAKE_S() in intel_hdmi_ddc_pin().(mdroper) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Lucas De Marchi Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-9-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 13 +++++++++++- drivers/gpu/drm/i915/display/intel_hdmi.c | 20 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_vbt_defs.h | 4 ++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 987cf509337f2..e575e584e6d5d 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1630,12 +1630,23 @@ static const u8 rkl_pch_tgp_ddc_pin_map[] = { [RKL_DDC_BUS_DDI_E] = GMBUS_PIN_10_TC2_ICP, }; +static const u8 adls_ddc_pin_map[] = { + [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT, + [ADLS_DDC_BUS_PORT_TC1] = GMBUS_PIN_9_TC1_ICP, + [ADLS_DDC_BUS_PORT_TC2] = GMBUS_PIN_10_TC2_ICP, + [ADLS_DDC_BUS_PORT_TC3] = GMBUS_PIN_11_TC3_ICP, + [ADLS_DDC_BUS_PORT_TC4] = GMBUS_PIN_12_TC4_ICP, +}; + static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) { const u8 *ddc_pin_map; int n_entries; - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) { + if (HAS_PCH_ADP(dev_priv)) { + ddc_pin_map = adls_ddc_pin_map; + n_entries = ARRAY_SIZE(adls_ddc_pin_map); + } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) { return vbt_pin; } else if (IS_ROCKETLAKE(dev_priv) && INTEL_PCH_TYPE(dev_priv) == PCH_TGP) { ddc_pin_map = rkl_pch_tgp_ddc_pin_map; diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index c5959590562ba..0fe9094a0d2af 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3135,6 +3135,22 @@ static u8 dg1_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) return intel_port_to_phy(dev_priv, port) + 1; } +static u8 adls_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) +{ + enum phy phy = intel_port_to_phy(dev_priv, port); + + WARN_ON(port == PORT_B || port == PORT_C); + + /* + * Pin mapping for ADL-S requires TC pins for all combo phy outputs + * except first combo output. + */ + if (phy == PHY_A) + return GMBUS_PIN_1_BXT; + + return GMBUS_PIN_9_TC1_ICP + phy - PHY_B; +} + static u8 g4x_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) { @@ -3172,7 +3188,9 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder) return ddc_pin; } - if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) + if (HAS_PCH_ADP(dev_priv)) + ddc_pin = adls_port_to_ddc_pin(dev_priv, port); + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_DG1) ddc_pin = dg1_port_to_ddc_pin(dev_priv, port); else if (IS_ROCKETLAKE(dev_priv)) ddc_pin = rkl_port_to_ddc_pin(dev_priv, port); diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 187ec573de59d..6d10fa0377514 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -327,6 +327,10 @@ enum vbt_gmbus_ddi { ICL_DDC_BUS_PORT_4, TGL_DDC_BUS_PORT_5, TGL_DDC_BUS_PORT_6, + ADLS_DDC_BUS_PORT_TC1 = 0x2, + ADLS_DDC_BUS_PORT_TC2, + ADLS_DDC_BUS_PORT_TC3, + ADLS_DDC_BUS_PORT_TC4 }; #define DP_AUX_A 0x40 From 18c283df5a0ece65ac1cfc6f1e2867fd24636252 Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Mon, 25 Jan 2021 06:07:52 -0800 Subject: [PATCH 011/142] drm/i915/adl_s: Add vbt port and aux channel settings for adls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ADL-S driver internal mapping uses PORT D, E, F, G for Combo phy B, C, D and E. - Add ADLS specific port mappings for vbt port dvo settings. - Select appropriate AUX CH specific to ADLS based on port mapping. Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-10-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 57 ++++++++++++++++++----- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index e575e584e6d5d..04337ac6f8c48 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1719,8 +1719,26 @@ static enum port dvo_port_to_port(struct drm_i915_private *dev_priv, [PORT_TC1] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 }, [PORT_TC2] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, }; + /* + * Alderlake S ports used in the driver are PORT_A, PORT_D, PORT_E, + * PORT_F and PORT_G, we need to map that to correct VBT sections. + */ + static const int adls_port_mapping[][3] = { + [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 }, + [PORT_B] = { -1 }, + [PORT_C] = { -1 }, + [PORT_TC1] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 }, + [PORT_TC2] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 }, + [PORT_TC3] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, + [PORT_TC4] = { DVO_PORT_HDMIE, DVO_PORT_DPE, -1 }, + }; - if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv)) + return __dvo_port_to_port(ARRAY_SIZE(adls_port_mapping), + ARRAY_SIZE(adls_port_mapping[0]), + adls_port_mapping, + dvo_port); + else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) return __dvo_port_to_port(ARRAY_SIZE(rkl_port_mapping), ARRAY_SIZE(rkl_port_mapping[0]), rkl_port_mapping, @@ -2672,27 +2690,44 @@ enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv, return aux_ch; } + /* + * RKL/DG1 VBT uses PHY based mapping. Combo PHYs A,B,C,D + * map to DDI A,B,TC1,TC2 respectively. + * + * ADL-S VBT uses PHY based mapping. Combo PHYs A,B,C,D,E + * map to DDI A,TC1,TC2,TC3,TC4 respectively. + */ switch (info->alternate_aux_channel) { case DP_AUX_A: aux_ch = AUX_CH_A; break; case DP_AUX_B: - aux_ch = AUX_CH_B; + if (IS_ALDERLAKE_S(dev_priv)) + aux_ch = AUX_CH_USBC1; + else + aux_ch = AUX_CH_B; break; case DP_AUX_C: - /* - * RKL/DG1 VBT uses PHY based mapping. Combo PHYs A,B,C,D - * map to DDI A,B,TC1,TC2 respectively. - */ - aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ? - AUX_CH_USBC1 : AUX_CH_C; + if (IS_ALDERLAKE_S(dev_priv)) + aux_ch = AUX_CH_USBC2; + else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) + aux_ch = AUX_CH_USBC1; + else + aux_ch = AUX_CH_C; break; case DP_AUX_D: - aux_ch = (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) ? - AUX_CH_USBC2 : AUX_CH_D; + if (IS_ALDERLAKE_S(dev_priv)) + aux_ch = AUX_CH_USBC3; + else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) + aux_ch = AUX_CH_USBC2; + else + aux_ch = AUX_CH_D; break; case DP_AUX_E: - aux_ch = AUX_CH_E; + if (IS_ALDERLAKE_S(dev_priv)) + aux_ch = AUX_CH_USBC4; + else + aux_ch = AUX_CH_E; break; case DP_AUX_F: aux_ch = AUX_CH_F; From 52401eb8e3fced097628507e1d3056cc81d51ed9 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 25 Jan 2021 06:07:53 -0800 Subject: [PATCH 012/142] drm/i915/adl_s: Update combo PHY master/slave relationships MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADL-S switches up which PHYs are considered a master to other PHYs; PHY-C is no longer a master, but PHY-D is now. Bspec: 49291 Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Lucas De Marchi Signed-off-by: Matt Roper Signed-off-by: Aditya Swarup Reviewed-by: Anusha Srivatsa Signed-off-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210125140753.347998-11-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_combo_phy.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index 996ae0608a621..dd45cbafcf42b 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -246,14 +246,21 @@ static bool phy_is_master(struct drm_i915_private *dev_priv, enum phy phy) * RKL,DG1: * A(master) -> B(slave) * C(master) -> D(slave) + * ADL-S: + * A(master) -> B(slave), C(slave) + * D(master) -> E(slave) * * We must set the IREFGEN bit for any PHY acting as a master * to another PHY. */ - if ((IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) && phy == PHY_C) + if (phy == PHY_A) return true; + else if (IS_ALDERLAKE_S(dev_priv)) + return phy == PHY_D; + else if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv)) + return phy == PHY_C; - return phy == PHY_A; + return false; } static bool icl_combo_phy_verify_state(struct drm_i915_private *dev_priv, From f8c6b615b921d8a1bcd74870f9105e62b0bceff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Jan 2021 17:59:44 +0200 Subject: [PATCH 013/142] drm/i915: Skip vswing programming for TBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In thunderbolt mode the PHY is owned by the thunderbolt controller. We are not supposed to touch it. So skip the vswing programming as well (we already skipped the other steps not applicable to TBT). Touching this stuff could supposedly interfere with the PHY programming done by the thunderbolt controller. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210128155948.13678-1-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index fbd857f2bdb26..2ac92e7f53355 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2827,6 +2827,9 @@ static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, int n_entries, ln; u32 val; + if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT) + return; + ddi_translations = icl_get_mg_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) @@ -2962,6 +2965,9 @@ tgl_dkl_phy_ddi_vswing_sequence(struct intel_encoder *encoder, u32 val, dpcnt_mask, dpcnt_val; int n_entries, ln; + if (enc_to_dig_port(encoder)->tc_mode == TC_PORT_TBT_ALT) + return; + ddi_translations = tgl_get_dkl_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) From 5cdf706fb91a6e4e6af799bb957c4d598e6a067b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Jan 2021 17:59:45 +0200 Subject: [PATCH 014/142] drm/i915: Extract intel_ddi_power_up_lanes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce the copypasta by pulling the combo PHY lane power up stuff into a helper. We'll have a third user soon. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210128155948.13678-2-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 35 +++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2ac92e7f53355..34db7afcfc754 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3621,6 +3621,23 @@ static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, intel_de_posting_read(dev_priv, dp_tp_ctl_reg(encoder, crtc_state)); } +static void intel_ddi_power_up_lanes(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_phy_is_combo(i915, phy)) { + bool lane_reversal = + dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; + + intel_combo_phy_power_up_lanes(i915, phy, false, + crtc_state->lane_count, + lane_reversal); + } +} + static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, @@ -3712,14 +3729,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, * 7.f Combo PHY: Configure PORT_CL_DW10 Static Power Down to power up * the used lanes of the DDI. */ - if (intel_phy_is_combo(dev_priv, phy)) { - bool lane_reversal = - dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; - - intel_combo_phy_power_up_lanes(dev_priv, phy, false, - crtc_state->lane_count, - lane_reversal); - } + intel_ddi_power_up_lanes(encoder, crtc_state); /* * 7.g Configure and enable DDI_BUF_CTL @@ -3810,14 +3820,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, else intel_prepare_dp_ddi_buffers(encoder, crtc_state); - if (intel_phy_is_combo(dev_priv, phy)) { - bool lane_reversal = - dig_port->saved_port_bits & DDI_BUF_PORT_REVERSAL; - - intel_combo_phy_power_up_lanes(dev_priv, phy, false, - crtc_state->lane_count, - lane_reversal); - } + intel_ddi_power_up_lanes(encoder, crtc_state); intel_ddi_init_dp_buf_reg(encoder, crtc_state); if (!is_mst) From 1e0cb7bef35f0d1aed383bf69a209df218b807c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Jan 2021 17:59:46 +0200 Subject: [PATCH 015/142] drm/i915: Power up combo PHY lanes for for HDMI as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we only explicitly power up the combo PHY lanes for DP. The spec says we should do it for HDMI as well. Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210128155948.13678-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 34db7afcfc754..1bb40ec5fe5db 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4317,6 +4317,8 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, reg, val); } + intel_ddi_power_up_lanes(encoder, crtc_state); + /* In HDMI/DVI mode, the port width, and swing/emphasis values * are ignored so nothing special needs to be done besides * enabling the port. From c9b69041f0e0f3b6f2019c81ffe3b732f605ea00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Jan 2021 17:59:47 +0200 Subject: [PATCH 016/142] drm/i915: Move HDMI vswing programming to the right place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documented programming sequence indicates the correct point for the vswing programming is just before we enable the DDI. Make it so. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210128155948.13678-4-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 1bb40ec5fe5db..d35eccd547f76 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3873,7 +3873,6 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_hdmi *intel_hdmi = &dig_port->hdmi; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - int level = intel_ddi_hdmi_level(encoder, crtc_state); intel_dp_dual_mode_set_tmds_output(intel_hdmi, true); intel_ddi_clk_select(encoder, crtc_state); @@ -3884,20 +3883,6 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state, icl_program_mg_dp_mode(dig_port, crtc_state); - if (INTEL_GEN(dev_priv) >= 12) - tgl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (INTEL_GEN(dev_priv) == 11) - icl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_CANNONLAKE(dev_priv)) - cnl_ddi_vswing_sequence(encoder, crtc_state, level); - else if (IS_GEN9_LP(dev_priv)) - bxt_ddi_vswing_sequence(encoder, crtc_state, level); - else - intel_prepare_hdmi_ddi_buffers(encoder, level); - - if (IS_GEN9_BC(dev_priv)) - skl_ddi_set_iboost(encoder, crtc_state, level); - intel_ddi_enable_pipe_clock(encoder, crtc_state); dig_port->set_infoframes(encoder, @@ -4273,6 +4258,7 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct drm_connector *connector = conn_state->connector; + int level = intel_ddi_hdmi_level(encoder, crtc_state); enum port port = encoder->port; if (!intel_hdmi_handle_sink_scrambling(encoder, connector, @@ -4282,6 +4268,20 @@ static void intel_enable_ddi_hdmi(struct intel_atomic_state *state, "[CONNECTOR:%d:%s] Failed to configure sink scrambling/TMDS bit clock ratio\n", connector->base.id, connector->name); + if (INTEL_GEN(dev_priv) >= 12) + tgl_ddi_vswing_sequence(encoder, crtc_state, level); + else if (INTEL_GEN(dev_priv) == 11) + icl_ddi_vswing_sequence(encoder, crtc_state, level); + else if (IS_CANNONLAKE(dev_priv)) + cnl_ddi_vswing_sequence(encoder, crtc_state, level); + else if (IS_GEN9_LP(dev_priv)) + bxt_ddi_vswing_sequence(encoder, crtc_state, level); + else + intel_prepare_hdmi_ddi_buffers(encoder, level); + + if (IS_GEN9_BC(dev_priv)) + skl_ddi_set_iboost(encoder, crtc_state, level); + /* Display WA #1143: skl,kbl,cfl */ if (IS_GEN9_BC(dev_priv)) { /* From 5b6a9ba9f6cefa41b2dd9b0c9ba36646b81ce0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 28 Jan 2021 17:59:48 +0200 Subject: [PATCH 017/142] drm/i915: Don't check tc_mode unless dealing with a TC PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We shouldn't really trust tc_mode on non-TC PHYs since we never initialize it explicitly. So let's check for the PHY type first. Fortunately TC_PORT_TBT_ALT happens to be zero so I don't think there's an actual bug here, just a possibility for a future one if someone rearranges the enum values. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210128155948.13678-5-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak --- drivers/gpu/drm/i915/display/intel_ddi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index d35eccd547f76..c56de13b52923 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3443,10 +3443,12 @@ icl_program_mg_dp_mode(struct intel_digital_port *dig_port, { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + enum phy phy = intel_port_to_phy(dev_priv, dig_port->base.port); u32 ln0, ln1, pin_assignment; u8 width; - if (dig_port->tc_mode == TC_PORT_TBT_ALT) + if (!intel_phy_is_tc(dev_priv, phy) || + dig_port->tc_mode == TC_PORT_TBT_ALT) return; if (INTEL_GEN(dev_priv) >= 12) { From ee0735ff4633a30ffcc1ea5ce073d9490692a3ea Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 26 Jan 2021 22:50:34 -0800 Subject: [PATCH 018/142] drm/i915/hdcp: disable the QSES check for HDCP2.2 over MST Like the patch to disable QSES for HDCP 1.4 over MST https://patchwork.freedesktop.org/patch/415297/ the HDCP2.2 spec doesn't require QSES as well and we've seen QSES not supported on a couple HDCP2.2 docks so far (Dell WD19 and Lenovo LDC-G2) Remove it for now until we get a better idea of how widely supported QSES is and how to support it optionally. Signed-off-by: Juston Li Reviewed-by: Anshuman Gupta Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20210127065034.2501119-4-juston.li@intel.com --- drivers/gpu/drm/i915/display/intel_dp_hdcp.c | 31 +------------------- 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c index 4dba5bb15af5a..40c516e901939 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_dp_hdcp.c @@ -698,30 +698,6 @@ intel_dp_mst_hdcp_stream_encryption(struct intel_connector *connector, return 0; } -static bool intel_dp_mst_get_qses_status(struct intel_digital_port *dig_port, - struct intel_connector *connector) -{ - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - struct drm_dp_query_stream_enc_status_ack_reply reply; - struct intel_dp *intel_dp = &dig_port->dp; - int ret; - - ret = drm_dp_send_query_stream_enc_status(&intel_dp->mst_mgr, - connector->port, &reply); - if (ret) { - drm_dbg_kms(&i915->drm, - "[%s:%d] failed QSES ret=%d\n", - connector->base.name, connector->base.base.id, ret); - return false; - } - - drm_dbg_kms(&i915->drm, "[%s:%d] QSES stream auth: %d stream enc: %d\n", - connector->base.name, connector->base.base.id, - reply.auth_completed, reply.encryption_enabled); - - return reply.auth_completed && reply.encryption_enabled; -} - static int intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector, bool enable) @@ -757,11 +733,6 @@ intel_dp_mst_hdcp2_stream_encryption(struct intel_connector *connector, return 0; } -/* - * DP v2.0 I.3.3 ignore the stream signature L' in QSES reply msg reply. - * I.3.5 MST source device may use a QSES msg to query downstream status - * for a particular stream. - */ static int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port, struct intel_connector *connector) @@ -781,7 +752,7 @@ int intel_dp_mst_hdcp2_check_link(struct intel_digital_port *dig_port, return ret; } - return intel_dp_mst_get_qses_status(dig_port, connector) ? 0 : -EINVAL; + return 0; } static const struct intel_hdcp_shim intel_dp_mst_hdcp_shim = { From 6ee8d381257891c7fd2d620e9d2db1be9f0f7bf5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 Jan 2021 10:45:34 +0200 Subject: [PATCH 019/142] drm/i915/bios: tidy up child device debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the child device details easier to read by turning this: [drm:parse_ddi_port [i915]] Port B VBT info: CRT:0 DVI:1 HDMI:1 DP:0 eDP:0 LSPCON:0 USB-Type-C:0 TBT:0 DSC:0 [drm:parse_ddi_port [i915]] VBT HDMI level shift for port B: 8 [drm:parse_ddi_port [i915]] VBT DP max link rate for port B: 810000 [drm:parse_ddi_port [i915]] Port C VBT info: CRT:0 DVI:1 HDMI:1 DP:1 eDP:0 LSPCON:0 USB-Type-C:0 TBT:0 DSC:0 [drm:parse_ddi_port [i915]] VBT HDMI level shift for port C: 8 [drm:parse_ddi_port [i915]] VBT (e)DP boost level for port C: 3 [drm:parse_ddi_port [i915]] VBT HDMI boost level for port C: 1 [drm:parse_ddi_port [i915]] VBT DP max link rate for port C: 810000 into this: [drm:parse_ddi_port [i915]] Port B VBT info: CRT:0 DVI:1 HDMI:1 DP:0 eDP:0 LSPCON:0 USB-Type-C:0 TBT:0 DSC:0 [drm:parse_ddi_port [i915]] Port B VBT HDMI level shift: 8 [drm:parse_ddi_port [i915]] Port B VBT DP max link rate: 810000 [drm:parse_ddi_port [i915]] Port C VBT info: CRT:0 DVI:1 HDMI:1 DP:1 eDP:0 LSPCON:0 USB-Type-C:0 TBT:0 DSC:0 [drm:parse_ddi_port [i915]] Port C VBT HDMI level shift: 8 [drm:parse_ddi_port [i915]] Port C VBT (e)DP boost level: 3 [drm:parse_ddi_port [i915]] Port C VBT HDMI boost level: 1 [drm:parse_ddi_port [i915]] Port C VBT DP max link rate: 810000 Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210127084534.24406-1-jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 987cf509337f2..db8c44af325ba 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1800,7 +1800,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, /* The VBT HDMI level shift values match the table we have. */ u8 hdmi_level_shift = child->hdmi_level_shifter_value; drm_dbg_kms(&dev_priv->drm, - "VBT HDMI level shift for port %c: %d\n", + "Port %c VBT HDMI level shift: %d\n", port_name(port), hdmi_level_shift); info->hdmi_level_shift = hdmi_level_shift; @@ -1827,7 +1827,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, if (max_tmds_clock) drm_dbg_kms(&dev_priv->drm, - "VBT HDMI max TMDS clock for port %c: %d kHz\n", + "Port %c VBT HDMI max TMDS clock: %d kHz\n", port_name(port), max_tmds_clock); info->max_tmds_clock = max_tmds_clock; } @@ -1836,11 +1836,11 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, if (bdb_version >= 196 && child->iboost) { info->dp_boost_level = translate_iboost(child->dp_iboost_level); drm_dbg_kms(&dev_priv->drm, - "VBT (e)DP boost level for port %c: %d\n", + "Port %c VBT (e)DP boost level: %d\n", port_name(port), info->dp_boost_level); info->hdmi_boost_level = translate_iboost(child->hdmi_iboost_level); drm_dbg_kms(&dev_priv->drm, - "VBT HDMI boost level for port %c: %d\n", + "Port %c VBT HDMI boost level: %d\n", port_name(port), info->hdmi_boost_level); } @@ -1862,7 +1862,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, break; } drm_dbg_kms(&dev_priv->drm, - "VBT DP max link rate for port %c: %d\n", + "Port %c VBT DP max link rate: %d\n", port_name(port), info->dp_max_link_rate); } From b4cd8dd367ad1ec0e1aba45a59800361140b458a Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 29 Jan 2021 10:29:38 -0800 Subject: [PATCH 020/142] drm/i915/adl_s: Update PHY_MISC programming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADL-S switches up which PHYs are considered a master to other PHYs; PHY-C is no longer a master, but PHY-D is now. Bspec: 49291 Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Lucas De Marchi Signed-off-by: Matt Roper Signed-off-by: Aditya Swarup Reviewed-by: Aditya Swarup Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-2-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_combo_phy.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_combo_phy.c b/drivers/gpu/drm/i915/display/intel_combo_phy.c index dd45cbafcf42b..c55813c6194ab 100644 --- a/drivers/gpu/drm/i915/display/intel_combo_phy.c +++ b/drivers/gpu/drm/i915/display/intel_combo_phy.c @@ -187,10 +187,16 @@ static bool has_phy_misc(struct drm_i915_private *i915, enum phy phy) * Some platforms only expect PHY_MISC to be programmed for PHY-A and * PHY-B and may not even have instances of the register for the * other combo PHY's. + * + * ADL-S technically has three instances of PHY_MISC, but only requires + * that we program it for PHY A. */ - if (IS_JSL_EHL(i915) || - IS_ROCKETLAKE(i915) || - IS_DG1(i915)) + + if (IS_ALDERLAKE_S(i915)) + return phy == PHY_A; + else if (IS_JSL_EHL(i915) || + IS_ROCKETLAKE(i915) || + IS_DG1(i915)) return phy < PHY_C; return true; From a7ffb8154d698cdcf5cad3f859f2cd7efb73ae82 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 29 Jan 2021 10:29:39 -0800 Subject: [PATCH 021/142] drm/i915/adl_s: Add power wells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TGL power wells can be re-used for ADL-S with the exception of the fake power well for TC_COLD, just like DG-1. BSpec: 53597 Bspec: 49231 Cc: Imre Deak Cc: Matt Roper Cc: Aditya Swarup Signed-off-by: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-3-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index bb04b502a442a..2f35a217f95ad 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -4689,7 +4689,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) * The enabling order will be from lower to higher indexed wells, * the disabling order is reversed. */ - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv) || IS_DG1(dev_priv)) { err = set_power_wells_mask(power_domains, tgl_power_wells, BIT_ULL(TGL_DISP_PW_TC_COLD_OFF)); } else if (IS_ROCKETLAKE(dev_priv)) { From 51ecb30e74d027e35771d5f552f86c118a8048b0 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 29 Jan 2021 10:29:40 -0800 Subject: [PATCH 022/142] drm/i915/adl_s: Re-use TGL GuC/HuC firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADL-S, like RKL, uses the same internal device ID for the GuC and HuC as TGL did, making them all firmware-compatible. Let's re-use TGL's firmware for ADL-S. Bspec: 50668 Cc: John Harrison Cc: Lucas De Marchi Signed-off-by: Matt Roper Signed-off-by: Aditya Swarup Reviewed-by: Anusha Srivatsa Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-4-aditya.swarup@intel.com --- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 602f1a0bc5871..8b7358106a52e 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -44,9 +44,11 @@ void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw, * List of required GuC and HuC binaries per-platform. * Must be ordered based on platform + revid, from newer to older. * - * Note that RKL uses the same firmware as TGL. + * Note that RKL and ADL-S have the same GuC/HuC device ID's and use the same + * firmware as TGL. */ #define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \ + fw_def(ALDERLAKE_S, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \ fw_def(ROCKETLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \ fw_def(TIGERLAKE, 0, guc_def(tgl, 49, 0, 1), huc_def(tgl, 7, 5, 0)) \ fw_def(JASPERLAKE, 0, guc_def(ehl, 49, 0, 1), huc_def(ehl, 9, 0, 0)) \ From a75816e8410e01574e4d8ea13573fc1cdac2e4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Fri, 29 Jan 2021 10:29:41 -0800 Subject: [PATCH 023/142] drm/i915/display: Add HAS_D12_PLANE_MINIMIZATION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - As RKL and ADL-S only have 5 planes, primary and 4 sprites and the cursor plane, let's group the handling together under HAS_D12_PLANE_MINIMIZATION. - Also use macro to select pipe irq fault error mask. BSpec: 49251 Cc: Lucas De Marchi Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Signed-off-by: José Roberto de Souza Signed-off-by: Aditya Swarup Reviewed-by: Anusha Srivatsa Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-5-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_sprite.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/intel_device_info.c | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 4ce32df3855fc..5c366dcf25c2b 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -367,7 +367,7 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) { - if (IS_ROCKETLAKE(i915)) + if (HAS_D12_PLANE_MINIMIZATION(i915)) return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); else return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3b75b5ee4c889..548344ef1e8b8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1785,6 +1785,9 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) #define INTEL_DISPLAY_ENABLED(dev_priv) \ (drm_WARN_ON(&(dev_priv)->drm, !HAS_DISPLAY(dev_priv)), !(dev_priv)->params.disable_display) +#define HAS_D12_PLANE_MINIMIZATION(dev_priv) (IS_ROCKETLAKE(dev_priv) || \ + IS_ALDERLAKE_S(dev_priv)) + static inline bool intel_vtd_active(void) { #ifdef CONFIG_INTEL_IOMMU diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c6b11f62e32dc..75389f8ca1ed8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2257,7 +2257,7 @@ static u32 gen8_de_port_aux_mask(struct drm_i915_private *dev_priv) static u32 gen8_de_pipe_fault_mask(struct drm_i915_private *dev_priv) { - if (IS_ROCKETLAKE(dev_priv)) + if (HAS_D12_PLANE_MINIMIZATION(dev_priv)) return RKL_DE_PIPE_IRQ_FAULT_ERRORS; else if (INTEL_GEN(dev_priv) >= 11) return GEN11_DE_PIPE_IRQ_FAULT_ERRORS; diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 699412c14c1d1..7bdf447225541 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -261,7 +261,7 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) BUILD_BUG_ON(BITS_PER_TYPE(intel_engine_mask_t) < I915_NUM_ENGINES); - if (IS_ROCKETLAKE(dev_priv)) + if (HAS_D12_PLANE_MINIMIZATION(dev_priv)) for_each_pipe(dev_priv, pipe) runtime->num_sprites[pipe] = 4; else if (INTEL_GEN(dev_priv) >= 11) From 75b81fbbcad2648195fd1323b95c3a77393e4ad1 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Fri, 29 Jan 2021 10:29:42 -0800 Subject: [PATCH 024/142] drm/i915/adl_s: Load DMC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Load DMC on ADL_S v2.01. This is the first offcial release of DMC for ADL_S. Cc: Jani Nikula Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Cc: Aditya Swarup Signed-off-by: Anusha Srivatsa Signed-off-by: Aditya Swarup Reviewed-by: Aditya Swarup Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-6-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_csr.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c index 67dc64df78a5d..db9f219c4b5a2 100644 --- a/drivers/gpu/drm/i915/display/intel_csr.c +++ b/drivers/gpu/drm/i915/display/intel_csr.c @@ -40,6 +40,10 @@ #define GEN12_CSR_MAX_FW_SIZE ICL_CSR_MAX_FW_SIZE +#define ADLS_CSR_PATH "i915/adls_dmc_ver2_01.bin" +#define ADLS_CSR_VERSION_REQUIRED CSR_VERSION(2, 1) +MODULE_FIRMWARE(ADLS_CSR_PATH); + #define DG1_CSR_PATH "i915/dg1_dmc_ver2_02.bin" #define DG1_CSR_VERSION_REQUIRED CSR_VERSION(2, 2) MODULE_FIRMWARE(DG1_CSR_PATH); @@ -689,7 +693,11 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) */ intel_csr_runtime_pm_get(dev_priv); - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv)) { + csr->fw_path = ADLS_CSR_PATH; + csr->required_version = ADLS_CSR_VERSION_REQUIRED; + csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE; + } else if (IS_DG1(dev_priv)) { csr->fw_path = DG1_CSR_PATH; csr->required_version = DG1_CSR_VERSION_REQUIRED; csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE; From 918cc934682f4385506dbf95beed4f4bfd1e377f Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Fri, 29 Jan 2021 10:29:43 -0800 Subject: [PATCH 025/142] drm/i915/adl_s: Update memory bandwidth parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like RKL, the ADL_S platform also has different memory characteristics from past platforms. Update the values used by our memory bandwidth calculations accordingly. v2: Fix minor nitpick for shifting ADLS case above RKL(based on platform order).(mdroper) Bspec: 64631 Cc: Matt Roper Cc: Lucas De Marchi Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Signed-off-by: Tejas Upadhyay Signed-off-by: Aditya Swarup Reviewed-by: Anusha Srivatsa Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-7-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_bw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index bd060404d2495..d7575aada4507 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -205,6 +205,12 @@ static const struct intel_sa_info rkl_sa_info = { .displayrtids = 128, }; +static const struct intel_sa_info adls_sa_info = { + .deburst = 16, + .deprogbwlimit = 38, /* GB/s */ + .displayrtids = 256, +}; + static int icl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel_sa_info *sa) { struct intel_qgv_info qi = {}; @@ -315,7 +321,9 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv) if (!HAS_DISPLAY(dev_priv)) return; - if (IS_ROCKETLAKE(dev_priv)) + if (IS_ALDERLAKE_S(dev_priv)) + icl_get_bw_info(dev_priv, &adls_sa_info); + else if (IS_ROCKETLAKE(dev_priv)) icl_get_bw_info(dev_priv, &rkl_sa_info); else if (IS_GEN(dev_priv, 12)) icl_get_bw_info(dev_priv, &tgl_sa_info); From ea27113ea90cb1f689e5b5234ebf6323e838efff Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Fri, 29 Jan 2021 10:29:44 -0800 Subject: [PATCH 026/142] drm/i915/adl_s: Add display WAs for ADL-S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extend permanent driver WA Wa_1409767108, Wa_14010685332 and Wa_14011294188 to adl-s. - Extend permanent driver WA Wa_1606054188 to adl-s. - Add Wa_14011765242 for adl-s A0 stepping. Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Aditya Swarup Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-8-aditya.swarup@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 7 ++++--- drivers/gpu/drm/i915/display/intel_sprite.c | 4 ++-- drivers/gpu/drm/i915/intel_device_info.c | 6 +++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 2f35a217f95ad..139d5aef2fa51 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -5339,9 +5339,10 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv) unsigned long abox_mask = INTEL_INFO(dev_priv)->abox_mask; int config, i; - if (IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0) || + if (IS_ALDERLAKE_S(dev_priv) || + IS_DG1_REVID(dev_priv, DG1_REVID_A0, DG1_REVID_A0) || IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_B0)) - /* Wa_1409767108:tgl,dg1 */ + /* Wa_1409767108:tgl,dg1,adl-s */ table = wa_1409767108_buddy_page_masks; else table = tgl_buddy_page_masks; @@ -5379,7 +5380,7 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); - /* Wa_14011294188:ehl,jsl,tgl,rkl */ + /* Wa_14011294188:ehl,jsl,tgl,rkl,adl-s */ if (INTEL_PCH_TYPE(dev_priv) >= PCH_JSP && INTEL_PCH_TYPE(dev_priv) < PCH_DG1) intel_de_rmw(dev_priv, SOUTH_DSPCLK_GATE_D, 0, diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 5c366dcf25c2b..89ab21a900a1b 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -2372,8 +2372,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, return -EINVAL; } - /* Wa_1606054188:tgl */ - if (IS_TIGERLAKE(dev_priv) && + /* Wa_1606054188:tgl,adl-s */ + if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) && plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE && intel_format_is_p01x(fb->format->format)) { drm_dbg_kms(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index 7bdf447225541..db76d9c10bd4d 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -250,7 +250,11 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv) struct intel_runtime_info *runtime = RUNTIME_INFO(dev_priv); enum pipe pipe; - if (INTEL_GEN(dev_priv) >= 10) { + /* Wa_14011765242: adl-s A0 */ + if (IS_ADLS_DISP_STEPPING(dev_priv, STEP_A0, STEP_A0)) + for_each_pipe(dev_priv, pipe) + runtime->num_scalers[pipe] = 0; + else if (INTEL_GEN(dev_priv) >= 10) { for_each_pipe(dev_priv, pipe) runtime->num_scalers[pipe] = 2; } else if (IS_GEN(dev_priv, 9)) { From 4043277ad18fc7cb9a79d0d043063fb5f42a6f06 Mon Sep 17 00:00:00 2001 From: Aditya Swarup Date: Fri, 29 Jan 2021 10:29:45 -0800 Subject: [PATCH 027/142] drm/i915/adl_s: Add GT and CTX WAs for ADL-S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extend Wa_1606931601 and Wa_1409804808 to ADL-S. - Extend Wa_14010919138 and Wa_14010229206 to ADL-S (Madhumitha) - Extend Wa_22010271021 to ADLS (cyokoyam) v2: - Extend Wa_1409804808 and remove unnecessary branching/redundant adls workaround placeholder functions. - Split WAs properly based on previous platforms and applicable ADLS WA. Cc: Jani Nikula Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: Madhumitha Tolakanahalli Pradeep Signed-off-by: Aditya Swarup Reviewed-by: Matt Roper Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210129182945.217078-9-aditya.swarup@intel.com --- drivers/gpu/drm/i915/gt/intel_workarounds.c | 34 +++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 4b95ce5d2d3c5..53f7838bd3c4a 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -730,7 +730,8 @@ __intel_engine_init_ctx_wa(struct intel_engine_cs *engine, if (IS_DG1(i915)) dg1_ctx_workarounds_init(engine, wal); - else if (IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) + else if (IS_ALDERLAKE_S(i915) || IS_ROCKETLAKE(i915) || + IS_TIGERLAKE(i915)) tgl_ctx_workarounds_init(engine, wal); else if (IS_GEN(i915, 12)) gen12_ctx_workarounds_init(engine, wal); @@ -1641,45 +1642,45 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN7_DISABLE_SAMPLER_PREFETCH); } - if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { - /* Wa_1606931601:tgl,rkl,dg1 */ + if (IS_ALDERLAKE_S(i915) || IS_DG1(i915) || + IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1606931601:tgl,rkl,dg1,adl-s */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_DISABLE_EARLY_READ); /* * Wa_1407928979:tgl A* * Wa_18011464164:tgl[B0+],dg1[B0+] * Wa_22010931296:tgl[B0+],dg1[B0+] - * Wa_14010919138:rkl, dg1 + * Wa_14010919138:rkl,dg1,adl-s */ wa_write_or(wal, GEN7_FF_THREAD_MODE, GEN12_FF_TESSELATION_DOP_GATE_DISABLE); /* * Wa_1606700617:tgl,dg1 - * Wa_22010271021:tgl,rkl,dg1 + * Wa_22010271021:tgl,rkl,dg1, adl-s */ wa_masked_en(wal, GEN9_CS_DEBUG_MODE1, FF_DOP_CLOCK_GATE_DISABLE); - - /* Wa_1406941453:tgl,rkl,dg1 */ - wa_masked_en(wal, - GEN10_SAMPLER_MODE, - ENABLE_SMALLPL); } - if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || + if (IS_ALDERLAKE_S(i915) || IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { - /* Wa_1409804808:tgl,rkl,dg1[a0] */ + /* Wa_1409804808:tgl,rkl,dg1[a0],adl-s */ wa_masked_en(wal, GEN7_ROW_CHICKEN2, GEN12_PUSH_CONST_DEREF_HOLD_DIS); /* * Wa_1409085225:tgl - * Wa_14010229206:tgl,rkl,dg1[a0] + * Wa_14010229206:tgl,rkl,dg1[a0],adl-s */ wa_masked_en(wal, GEN9_ROW_CHICKEN4, GEN12_DISABLE_TDL_PUSH); + } + + if (IS_DG1_REVID(i915, DG1_REVID_A0, DG1_REVID_A0) || + IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* * Wa_1607030317:tgl * Wa_1607186500:tgl @@ -1696,6 +1697,13 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) GEN8_RC_SEMA_IDLE_MSG_DISABLE); } + if (IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { + /* Wa_1406941453:tgl,rkl,dg1 */ + wa_masked_en(wal, + GEN10_SAMPLER_MODE, + ENABLE_SMALLPL); + } + if (IS_GEN(i915, 11)) { /* This is not an Wa. Enable for better image quality */ wa_masked_en(wal, From 8ff5446a7ca47cffec206af679763a2e4cb1199a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 28 Jan 2021 14:31:23 +0100 Subject: [PATCH 028/142] drm/i915: Remove references to struct drm_device.pdev Using struct drm_device.pdev is deprecated. Convert i915 to struct drm_device.dev. No functional changes. v6: * also remove assignment in selftests/ in a later patch (Chris) v5: * remove assignment in later patch (Chris) v3: * rebased v2: * move gt/ and gvt/ changes into separate patches Signed-off-by: Thomas Zimmermann Reviewed-by: Chris Wilson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210128133127.2311-2-tzimmermann@suse.de --- drivers/gpu/drm/i915/display/intel_bios.c | 2 +- drivers/gpu/drm/i915/display/intel_cdclk.c | 14 +++++++------- drivers/gpu/drm/i915/display/intel_csr.c | 2 +- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 2 +- drivers/gpu/drm/i915/display/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/display/intel_gmbus.c | 2 +- .../gpu/drm/i915/display/intel_lpe_audio.c | 5 +++-- drivers/gpu/drm/i915/display/intel_opregion.c | 6 +++--- drivers/gpu/drm/i915/display/intel_overlay.c | 2 +- drivers/gpu/drm/i915/display/intel_panel.c | 4 ++-- drivers/gpu/drm/i915/display/intel_quirks.c | 2 +- drivers/gpu/drm/i915/display/intel_sdvo.c | 2 +- drivers/gpu/drm/i915/display/intel_vga.c | 8 ++++---- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 6 +++--- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +- drivers/gpu/drm/i915/gt/intel_region_lmem.c | 8 ++++---- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.c | 19 +++++++++---------- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 ++--- drivers/gpu/drm/i915/i915_getparam.c | 5 +++-- drivers/gpu/drm/i915/i915_gpu_error.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 6 +++--- drivers/gpu/drm/i915/i915_pmu.c | 2 +- drivers/gpu/drm/i915/i915_suspend.c | 4 ++-- drivers/gpu/drm/i915/i915_switcheroo.c | 4 ++-- drivers/gpu/drm/i915/i915_vgpu.c | 2 +- drivers/gpu/drm/i915/intel_device_info.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 4 ++-- drivers/gpu/drm/i915/selftests/mock_gtt.c | 2 +- 31 files changed, 66 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 04337ac6f8c48..5777e3e3f29c4 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2127,7 +2127,7 @@ bool intel_bios_is_valid_vbt(const void *buf, size_t size) static struct vbt_header *oprom_get_vbt(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); void __iomem *p = NULL, *oprom; struct vbt_header *vbt; u16 vbt_size; diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 2e878cc274b7b..bf83e9e752272 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -96,7 +96,7 @@ static void fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv, static void i85x_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u16 hpllcc = 0; /* @@ -138,7 +138,7 @@ static void i85x_get_cdclk(struct drm_i915_private *dev_priv, static void i915gm_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -162,7 +162,7 @@ static void i915gm_get_cdclk(struct drm_i915_private *dev_priv, static void i945gm_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -256,7 +256,7 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv) static void g33_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->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 }; @@ -305,7 +305,7 @@ static void g33_get_cdclk(struct drm_i915_private *dev_priv, static void pnv_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u16 gcfgc = 0; pci_read_config_word(pdev, GCFGC, &gcfgc); @@ -339,7 +339,7 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv, static void i965gm_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->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 }; @@ -384,7 +384,7 @@ static void i965gm_get_cdclk(struct drm_i915_private *dev_priv, static void gm45_get_cdclk(struct drm_i915_private *dev_priv, struct intel_cdclk_config *cdclk_config) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); unsigned int cdclk_sel; u16 tmp = 0; diff --git a/drivers/gpu/drm/i915/display/intel_csr.c b/drivers/gpu/drm/i915/display/intel_csr.c index db9f219c4b5a2..42005c1b5f0ef 100644 --- a/drivers/gpu/drm/i915/display/intel_csr.c +++ b/drivers/gpu/drm/i915/display/intel_csr.c @@ -644,7 +644,7 @@ static void csr_load_work_fn(struct work_struct *work) dev_priv = container_of(work, typeof(*dev_priv), csr.work); csr = &dev_priv->csr; - request_firmware(&fw, dev_priv->csr.fw_path, &dev_priv->drm.pdev->dev); + request_firmware(&fw, dev_priv->csr.fw_path, dev_priv->drm.dev); parse_csr_fw(dev_priv, fw); if (dev_priv->csr.dmc_payload) { diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index eed037ec0b297..e349caef19265 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -425,7 +425,7 @@ static void i2c_acpi_find_adapter(struct intel_dsi *intel_dsi, const u16 slave_addr) { struct drm_device *drm_dev = intel_dsi->base.base.dev; - struct device *dev = &drm_dev->pdev->dev; + struct device *dev = drm_dev->dev; struct acpi_device *acpi_dev; struct list_head resource_list; struct i2c_adapter_lookup lookup; diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 842c04e632147..4ccb462bd4971 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -167,7 +167,7 @@ static int intelfb_create(struct drm_fb_helper *helper, struct intel_framebuffer *intel_fb = ifbdev->fb; struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = to_i915(dev); - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct i915_ggtt *ggtt = &dev_priv->ggtt; const struct i915_ggtt_view view = { .type = I915_GGTT_VIEW_NORMAL, diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index b0d71bbbf2ada..0c952e1d720e5 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -840,7 +840,7 @@ static const struct i2c_lock_operations gmbus_lock_ops = { */ int intel_gmbus_setup(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_gmbus *bus; unsigned int pin; int ret; diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index 1c939f9c9bc9e..7f3c638c8950d 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -80,6 +80,7 @@ static struct platform_device * lpe_audio_platdev_create(struct drm_i915_private *dev_priv) { struct drm_device *dev = &dev_priv->drm; + struct pci_dev *pdev = to_pci_dev(dev->dev); struct platform_device_info pinfo = {}; struct resource *rsc; struct platform_device *platdev; @@ -99,9 +100,9 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv) rsc[0].flags = IORESOURCE_IRQ; rsc[0].name = "hdmi-lpe-audio-irq"; - rsc[1].start = pci_resource_start(dev->pdev, 0) + + rsc[1].start = pci_resource_start(pdev, 0) + I915_HDMI_LPE_AUDIO_BASE; - rsc[1].end = pci_resource_start(dev->pdev, 0) + + rsc[1].end = pci_resource_start(pdev, 0) + I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1; rsc[1].flags = IORESOURCE_MEM; rsc[1].name = "hdmi-lpe-audio-mmio"; diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 4f77cf849171d..dfd724e506b52 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -247,7 +247,7 @@ static int swsci(struct drm_i915_private *dev_priv, u32 function, u32 parm, u32 *parm_out) { struct opregion_swsci *swsci = dev_priv->opregion.swsci; - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u32 main_function, sub_function, scic; u16 swsci_val; u32 dslp; @@ -807,7 +807,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) if (!name || !*name) return -ENOENT; - ret = request_firmware(&fw, name, &dev_priv->drm.pdev->dev); + ret = request_firmware(&fw, name, dev_priv->drm.dev); if (ret) { drm_err(&dev_priv->drm, "Requesting VBT firmware \"%s\" failed (%d)\n", @@ -840,7 +840,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) int intel_opregion_setup(struct drm_i915_private *dev_priv) { struct intel_opregion *opregion = &dev_priv->opregion; - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u32 asls, mboxes; char buf[sizeof(OPREGION_SIGNATURE)]; int err = 0; diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 6be5d8946c697..cd1eb71d6e358 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -202,7 +202,7 @@ struct intel_overlay { static void i830_overlay_clock_gating(struct drm_i915_private *dev_priv, bool enable) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u8 val; /* WA_OVERLAY_CLKGATE:alm */ diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 7a4239d1c241f..37bc7dad04505 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -557,7 +557,7 @@ static u32 i9xx_get_backlight(struct intel_connector *connector) if (panel->backlight.combination_mode) { u8 lbpc; - pci_read_config_byte(dev_priv->drm.pdev, LBPC, &lbpc); + pci_read_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, &lbpc); val *= lbpc; } @@ -631,7 +631,7 @@ static void i9xx_set_backlight(const struct drm_connector_state *conn_state, u32 lbpc = level * 0xfe / panel->backlight.max + 1; level /= lbpc; - pci_write_config_byte(dev_priv->drm.pdev, LBPC, lbpc); + pci_write_config_byte(to_pci_dev(dev_priv->drm.dev), LBPC, lbpc); } if (IS_GEN(dev_priv, 4)) { diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c index 46beb155d835f..98dd787b00e39 100644 --- a/drivers/gpu/drm/i915/display/intel_quirks.c +++ b/drivers/gpu/drm/i915/display/intel_quirks.c @@ -160,7 +160,7 @@ static struct intel_quirk intel_quirks[] = { void intel_init_quirks(struct drm_i915_private *i915) { - struct pci_dev *d = i915->drm.pdev; + struct pci_dev *d = to_pci_dev(i915->drm.dev); int i; for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) { diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index 4eaa4aa86ecdf..3fac60899d8e7 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -3281,7 +3281,7 @@ static bool intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); sdvo->ddc.owner = THIS_MODULE; sdvo->ddc.class = I2C_CLASS_DDC; diff --git a/drivers/gpu/drm/i915/display/intel_vga.c b/drivers/gpu/drm/i915/display/intel_vga.c index be333699c515b..5f8e4f53649d4 100644 --- a/drivers/gpu/drm/i915/display/intel_vga.c +++ b/drivers/gpu/drm/i915/display/intel_vga.c @@ -25,7 +25,7 @@ static i915_reg_t intel_vga_cntrl_reg(struct drm_i915_private *i915) /* Disable the VGA plane that we never use */ void intel_vga_disable(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); i915_reg_t vga_reg = intel_vga_cntrl_reg(dev_priv); u8 sr1; @@ -76,7 +76,7 @@ void intel_vga_redisable(struct drm_i915_private *i915) void intel_vga_reset_io_mem(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); /* * After we re-enable the power well, if we touch VGA register 0x3d5 @@ -136,7 +136,7 @@ intel_vga_set_decode(void *cookie, bool enable_decode) int intel_vga_register(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int ret; /* @@ -156,7 +156,7 @@ int intel_vga_register(struct drm_i915_private *i915) void intel_vga_unregister(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); vga_client_register(pdev, NULL, NULL, NULL); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c index 3a4dfe2ef1da5..f47dafdda539b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -35,7 +35,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) * to handle all possible callers, and given typical object sizes, * the alignment of the buddy allocation will naturally match. */ - vaddr = dma_alloc_coherent(&obj->base.dev->pdev->dev, + vaddr = dma_alloc_coherent(obj->base.dev->dev, roundup_pow_of_two(obj->base.size), &dma, GFP_KERNEL); if (!vaddr) @@ -83,7 +83,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) err_st: kfree(st); err_pci: - dma_free_coherent(&obj->base.dev->pdev->dev, + dma_free_coherent(obj->base.dev->dev, roundup_pow_of_two(obj->base.size), vaddr, dma); return -ENOMEM; @@ -129,7 +129,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, sg_free_table(pages); kfree(pages); - dma_free_coherent(&obj->base.dev->pdev->dev, + dma_free_coherent(obj->base.dev->dev, roundup_pow_of_two(obj->base.size), vaddr, dma); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 75e8b71c18b92..08c9c25f11097 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -172,7 +172,7 @@ static int shmem_get_pages(struct drm_i915_gem_object *obj) max_segment = PAGE_SIZE; goto rebuild_st; } else { - dev_warn(&i915->drm.pdev->dev, + dev_warn(i915->drm.dev, "Failed to DMA remap %lu pages\n", page_count); goto err_pages; diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index 83992312a34bf..421493eb57887 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -26,12 +26,12 @@ static int init_fake_lmem_bar(struct intel_memory_region *mem) if (ret) return ret; - mem->remap_addr = dma_map_resource(&i915->drm.pdev->dev, + mem->remap_addr = dma_map_resource(i915->drm.dev, mem->region.start, mem->fake_mappable.size, PCI_DMA_BIDIRECTIONAL, DMA_ATTR_FORCE_CONTIGUOUS); - if (dma_mapping_error(&i915->drm.pdev->dev, mem->remap_addr)) { + if (dma_mapping_error(i915->drm.dev, mem->remap_addr)) { drm_mm_remove_node(&mem->fake_mappable); return -EINVAL; } @@ -56,7 +56,7 @@ static void release_fake_lmem_bar(struct intel_memory_region *mem) drm_mm_remove_node(&mem->fake_mappable); - dma_unmap_resource(&mem->i915->drm.pdev->dev, + dma_unmap_resource(mem->i915->drm.dev, mem->remap_addr, mem->fake_mappable.size, PCI_DMA_BIDIRECTIONAL, @@ -104,7 +104,7 @@ static const struct intel_memory_region_ops intel_region_lmem_ops = { struct intel_memory_region * intel_setup_fake_lmem(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct intel_memory_region *mem; resource_size_t mappable_end; resource_size_t io_start; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index de8e0e44cfb6a..1bfb740a3d1e1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -819,7 +819,7 @@ static int i915_rps_boost_info(struct seq_file *m, void *data) static int i915_runtime_pm_status(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); if (!HAS_RUNTIME_PM(dev_priv)) seq_puts(m, "Runtime power management not supported\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f5666b44ea9da..3672a33f1b897 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -91,7 +91,7 @@ static const struct drm_driver driver; static int i915_get_bridge_dev(struct drm_i915_private *dev_priv) { - int domain = pci_domain_nr(dev_priv->drm.pdev->bus); + int domain = pci_domain_nr(to_pci_dev(dev_priv->drm.dev)->bus); dev_priv->bridge_dev = pci_get_domain_bus_and_slot(domain, 0, PCI_DEVFN(0, 0)); @@ -459,7 +459,6 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) */ static int i915_set_dma_info(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; unsigned int mask_size = INTEL_INFO(i915)->dma_mask_size; int ret; @@ -469,9 +468,9 @@ static int i915_set_dma_info(struct drm_i915_private *i915) * We don't have a max segment size, so set it to the max so sg's * debugging layer doesn't complain */ - dma_set_max_seg_size(&pdev->dev, UINT_MAX); + dma_set_max_seg_size(i915->drm.dev, UINT_MAX); - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(mask_size)); + ret = dma_set_mask(i915->drm.dev, DMA_BIT_MASK(mask_size)); if (ret) goto mask_err; @@ -491,7 +490,7 @@ static int i915_set_dma_info(struct drm_i915_private *i915) if (IS_I965G(i915) || IS_I965GM(i915)) mask_size = 32; - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(mask_size)); + ret = dma_set_coherent_mask(i915->drm.dev, DMA_BIT_MASK(mask_size)); if (ret) goto mask_err; @@ -511,7 +510,7 @@ static int i915_set_dma_info(struct drm_i915_private *i915) */ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); int ret; if (i915_inject_probe_failure(dev_priv)) @@ -638,7 +637,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) */ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); i915_perf_fini(dev_priv); @@ -1091,7 +1090,7 @@ static int i915_drm_prepare(struct drm_device *dev) static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); pci_power_t opregion_target_state; disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); @@ -1148,7 +1147,7 @@ get_suspend_mode(struct drm_i915_private *dev_priv, bool hibernate) static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) { struct drm_i915_private *dev_priv = to_i915(dev); - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); struct intel_runtime_pm *rpm = &dev_priv->runtime_pm; int ret; @@ -1278,7 +1277,7 @@ static int i915_drm_resume(struct drm_device *dev) static int i915_drm_resume_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); int ret; /* diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 548344ef1e8b8..4610ea8c7c44c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1289,7 +1289,7 @@ static inline struct drm_i915_private *pdev_to_i915(struct pci_dev *pdev) #define INTEL_DEVID(dev_priv) (RUNTIME_INFO(dev_priv)->device_id) #define REVID_FOREVER 0xff -#define INTEL_REVID(dev_priv) ((dev_priv)->drm.pdev->revision) +#define INTEL_REVID(dev_priv) (to_pci_dev((dev_priv)->drm.dev)->revision) #define INTEL_GEN_MASK(s, e) ( \ BUILD_BUG_ON_ZERO(!__builtin_constant_p(s)) + \ diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 3ee2f682eff61..486c9953e5b65 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,7 +28,7 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) { do { - if (dma_map_sg_attrs(&obj->base.dev->pdev->dev, + if (dma_map_sg_attrs(obj->base.dev->dev, pages->sgl, pages->nents, PCI_DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC | @@ -63,8 +63,7 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj, /* Wait a bit, in the hope it avoids the hang */ usleep_range(100, 250); - dma_unmap_sg(&i915->drm.pdev->dev, - pages->sgl, pages->nents, + dma_unmap_sg(i915->drm.dev, pages->sgl, pages->nents, PCI_DMA_BIDIRECTIONAL); } diff --git a/drivers/gpu/drm/i915/i915_getparam.c b/drivers/gpu/drm/i915/i915_getparam.c index 75c3bfc2486e4..24e18219eb505 100644 --- a/drivers/gpu/drm/i915/i915_getparam.c +++ b/drivers/gpu/drm/i915/i915_getparam.c @@ -12,6 +12,7 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_private *i915 = to_i915(dev); + struct pci_dev *pdev = to_pci_dev(dev->dev); const struct sseu_dev_info *sseu = &i915->gt.info.sseu; drm_i915_getparam_t *param = data; int value; @@ -24,10 +25,10 @@ int i915_getparam_ioctl(struct drm_device *dev, void *data, /* Reject all old ums/dri params. */ return -ENODEV; case I915_PARAM_CHIPSET_ID: - value = i915->drm.pdev->device; + value = pdev->device; break; case I915_PARAM_REVISION: - value = i915->drm.pdev->revision; + value = pdev->revision; break; case I915_PARAM_NUM_FENCES_AVAIL: value = i915->ggtt.num_fences; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 8b163ee1b86d8..e3068ce50b427 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -644,7 +644,7 @@ static void err_print_params(struct drm_i915_error_state_buf *m, static void err_print_pciid(struct drm_i915_error_state_buf *m, struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); err_printf(m, "PCI ID: 0x%04x\n", pdev->device); err_printf(m, "PCI Revision: 0x%02x\n", pdev->revision); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 75389f8ca1ed8..31120e3abed96 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4377,7 +4377,7 @@ static void intel_irq_postinstall(struct drm_i915_private *dev_priv) */ int intel_irq_install(struct drm_i915_private *dev_priv) { - int irq = dev_priv->drm.pdev->irq; + int irq = to_pci_dev(dev_priv->drm.dev)->irq; int ret; /* @@ -4412,7 +4412,7 @@ int intel_irq_install(struct drm_i915_private *dev_priv) */ void intel_irq_uninstall(struct drm_i915_private *dev_priv) { - int irq = dev_priv->drm.pdev->irq; + int irq = to_pci_dev(dev_priv->drm.dev)->irq; /* * FIXME we can get called twice during driver probe @@ -4472,5 +4472,5 @@ bool intel_irqs_enabled(struct drm_i915_private *dev_priv) void intel_synchronize_irq(struct drm_i915_private *i915) { - synchronize_irq(i915->drm.pdev->irq); + synchronize_irq(to_pci_dev(i915->drm.dev)->irq); } diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index 2b88c0baa1bf5..41651ac255fab 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -1124,7 +1124,7 @@ static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu) static bool is_igp(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); /* IGP is 0000:00:02.0 */ return pci_domain_nr(pdev->bus) == 0 && diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 63212df33c9ec..0bc7b49f843cc 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -85,7 +85,7 @@ static void intel_restore_swf(struct drm_i915_private *dev_priv) void i915_save_display(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); /* Display arbitration control */ if (INTEL_GEN(dev_priv) <= 4) @@ -100,7 +100,7 @@ void i915_save_display(struct drm_i915_private *dev_priv) void i915_restore_display(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); intel_restore_swf(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_switcheroo.c b/drivers/gpu/drm/i915/i915_switcheroo.c index b3a24eac21f16..de0e224b56ce3 100644 --- a/drivers/gpu/drm/i915/i915_switcheroo.c +++ b/drivers/gpu/drm/i915/i915_switcheroo.c @@ -54,14 +54,14 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { int i915_switcheroo_register(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); return vga_switcheroo_register_client(pdev, &i915_switcheroo_ops, false); } void i915_switcheroo_unregister(struct drm_i915_private *i915) { - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); vga_switcheroo_unregister_client(pdev); } diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index 70fca72f5162e..172799277dd5b 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -61,7 +61,7 @@ */ void intel_vgpu_detect(struct drm_i915_private *dev_priv) { - struct pci_dev *pdev = dev_priv->drm.pdev; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); u64 magic; u16 version_major; void __iomem *shared_area; diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c index db76d9c10bd4d..8aaa0f8f6cfd5 100644 --- a/drivers/gpu/drm/i915/intel_device_info.c +++ b/drivers/gpu/drm/i915/intel_device_info.c @@ -205,7 +205,7 @@ void intel_device_info_subplatform_init(struct drm_i915_private *i915) } if (IS_TIGERLAKE(i915)) { - struct pci_dev *root, *pdev = i915->drm.pdev; + struct pci_dev *root, *pdev = to_pci_dev(i915->drm.dev); root = list_first_entry(&pdev->bus->devices, typeof(*root), bus_list); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 153ca9e65382e..4970ef0843dcd 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -625,7 +625,7 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) { struct drm_i915_private *i915 = container_of(rpm, struct drm_i915_private, runtime_pm); - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct device *kdev = &pdev->dev; rpm->kdev = kdev; diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 9ac501bcfdadb..5098f95d71b03 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1780,7 +1780,7 @@ static int i915_pmic_bus_access_notifier(struct notifier_block *nb, static int uncore_mmio_setup(struct intel_uncore *uncore) { struct drm_i915_private *i915 = uncore->i915; - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); int mmio_bar; int mmio_size; @@ -1812,7 +1812,7 @@ static int uncore_mmio_setup(struct intel_uncore *uncore) static void uncore_mmio_cleanup(struct intel_uncore *uncore) { - struct pci_dev *pdev = uncore->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(uncore->i915->drm.dev); pci_iounmap(pdev, uncore->regs); } diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index 7270fc8ca801a..5c7ae40bba634 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -74,7 +74,7 @@ struct i915_ppgtt *mock_ppgtt(struct drm_i915_private *i915, const char *name) ppgtt->vm.i915 = i915; ppgtt->vm.total = round_down(U64_MAX, PAGE_SIZE); ppgtt->vm.file = ERR_PTR(-ENODEV); - ppgtt->vm.dma = &i915->drm.pdev->dev; + ppgtt->vm.dma = i915->drm.dev; i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT); From e322551f47d2305965a41a19d7a4bc7032a567c9 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 28 Jan 2021 14:31:24 +0100 Subject: [PATCH 029/142] drm/i915/gt: Remove references to struct drm_device.pdev Using struct drm_device.pdev is deprecated. Convert i915 to struct drm_device.dev. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Chris Wilson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210128133127.2311-3-tzimmermann@suse.de --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 2 +- drivers/gpu/drm/i915/gt/intel_ggtt.c | 10 +++++----- drivers/gpu/drm/i915/gt/intel_ppgtt.c | 2 +- drivers/gpu/drm/i915/gt/intel_rc6.c | 4 ++-- drivers/gpu/drm/i915/gt/intel_reset.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index fa76602f98524..8eea3da195648 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -1269,7 +1269,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) /* Waiting to drain ELSP? */ if (execlists_active(&engine->execlists)) { - synchronize_hardirq(engine->i915->drm.pdev->irq); + synchronize_hardirq(to_pci_dev(engine->i915->drm.dev)->irq); intel_engine_flush_submission(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index eece0844fbe97..fd6c8fa54812b 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -769,7 +769,7 @@ static unsigned int chv_get_total_gtt_size(u16 gmch_ctrl) static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size) { struct drm_i915_private *i915 = ggtt->vm.i915; - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); phys_addr_t phys_addr; int ret; @@ -839,7 +839,7 @@ static struct resource pci_resource(struct pci_dev *pdev, int bar) static int gen8_gmch_probe(struct i915_ggtt *ggtt) { struct drm_i915_private *i915 = ggtt->vm.i915; - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); unsigned int size; u16 snb_gmch_ctl; @@ -983,7 +983,7 @@ static u64 iris_pte_encode(dma_addr_t addr, static int gen6_gmch_probe(struct i915_ggtt *ggtt) { struct drm_i915_private *i915 = ggtt->vm.i915; - struct pci_dev *pdev = i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(i915->drm.dev); unsigned int size; u16 snb_gmch_ctl; @@ -1046,7 +1046,7 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt) phys_addr_t gmadr_base; int ret; - ret = intel_gmch_probe(i915->bridge_dev, i915->drm.pdev, NULL); + ret = intel_gmch_probe(i915->bridge_dev, to_pci_dev(i915->drm.dev), NULL); if (!ret) { drm_err(&i915->drm, "failed to set up gmch\n"); return -EIO; @@ -1091,7 +1091,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt) ggtt->vm.gt = gt; ggtt->vm.i915 = i915; - ggtt->vm.dma = &i915->drm.pdev->dev; + ggtt->vm.dma = i915->drm.dev; if (INTEL_GEN(i915) <= 5) ret = i915_gmch_probe(ggtt); diff --git a/drivers/gpu/drm/i915/gt/intel_ppgtt.c b/drivers/gpu/drm/i915/gt/intel_ppgtt.c index 46d9aceda64cd..01b7d08532f24 100644 --- a/drivers/gpu/drm/i915/gt/intel_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ppgtt.c @@ -301,7 +301,7 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt) ppgtt->vm.gt = gt; ppgtt->vm.i915 = i915; - ppgtt->vm.dma = &i915->drm.pdev->dev; + ppgtt->vm.dma = i915->drm.dev; ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size); i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT); diff --git a/drivers/gpu/drm/i915/gt/intel_rc6.c b/drivers/gpu/drm/i915/gt/intel_rc6.c index d7b8e4457fc28..cce53fb9589c8 100644 --- a/drivers/gpu/drm/i915/gt/intel_rc6.c +++ b/drivers/gpu/drm/i915/gt/intel_rc6.c @@ -485,14 +485,14 @@ static bool rc6_supported(struct intel_rc6 *rc6) static void rpm_get(struct intel_rc6 *rc6) { GEM_BUG_ON(rc6->wakeref); - pm_runtime_get_sync(&rc6_to_i915(rc6)->drm.pdev->dev); + pm_runtime_get_sync(rc6_to_i915(rc6)->drm.dev); rc6->wakeref = true; } static void rpm_put(struct intel_rc6 *rc6) { GEM_BUG_ON(!rc6->wakeref); - pm_runtime_put(&rc6_to_i915(rc6)->drm.pdev->dev); + pm_runtime_put(rc6_to_i915(rc6)->drm.dev); rc6->wakeref = false; } diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c index 9d177297db794..d5614e195b817 100644 --- a/drivers/gpu/drm/i915/gt/intel_reset.c +++ b/drivers/gpu/drm/i915/gt/intel_reset.c @@ -179,7 +179,7 @@ static int i915_do_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask, unsigned int retry) { - struct pci_dev *pdev = gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); int err; /* Assert reset for at least 20 usec, and wait for acknowledgement. */ @@ -208,7 +208,7 @@ static int g33_do_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask, unsigned int retry) { - struct pci_dev *pdev = gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE); return wait_for_atomic(g4x_reset_complete(pdev), 50); @@ -218,7 +218,7 @@ static int g4x_do_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask, unsigned int retry) { - struct pci_dev *pdev = gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev); struct intel_uncore *uncore = gt->uncore; int ret; From 9ff06c38530099b197b6389193e8cc34ab60288f Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 28 Jan 2021 14:31:25 +0100 Subject: [PATCH 030/142] drm/i915/gvt: Remove references to struct drm_device.pdev Using struct drm_device.pdev is deprecated. Convert i915 to struct drm_device.dev. No functional changes. Signed-off-by: Thomas Zimmermann Reviewed-by: Chris Wilson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210128133127.2311-4-tzimmermann@suse.de --- drivers/gpu/drm/i915/gvt/cfg_space.c | 5 +++-- drivers/gpu/drm/i915/gvt/firmware.c | 10 +++++----- drivers/gpu/drm/i915/gvt/gtt.c | 12 ++++++------ drivers/gpu/drm/i915/gvt/gvt.c | 6 +++--- drivers/gpu/drm/i915/gvt/kvmgt.c | 4 ++-- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index ad86c5eb5bba0..b490e3db2e382 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -374,6 +374,7 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, bool primary) { struct intel_gvt *gvt = vgpu->gvt; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); const struct intel_gvt_device_info *info = &gvt->device_info; u16 *gmch_ctl; u8 next; @@ -407,9 +408,9 @@ void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4); vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size = - pci_resource_len(gvt->gt->i915->drm.pdev, 0); + pci_resource_len(pdev, 0); vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size = - pci_resource_len(gvt->gt->i915->drm.pdev, 2); + pci_resource_len(pdev, 2); memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4); diff --git a/drivers/gpu/drm/i915/gvt/firmware.c b/drivers/gpu/drm/i915/gvt/firmware.c index 990a181094e3d..1a8274a3f4b10 100644 --- a/drivers/gpu/drm/i915/gvt/firmware.c +++ b/drivers/gpu/drm/i915/gvt/firmware.c @@ -76,7 +76,7 @@ static int mmio_snapshot_handler(struct intel_gvt *gvt, u32 offset, void *data) static int expose_firmware_sysfs(struct intel_gvt *gvt) { struct intel_gvt_device_info *info = &gvt->device_info; - struct pci_dev *pdev = gvt->gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); struct gvt_firmware_header *h; void *firmware; void *p; @@ -127,7 +127,7 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt) static void clean_firmware_sysfs(struct intel_gvt *gvt) { - struct pci_dev *pdev = gvt->gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); device_remove_bin_file(&pdev->dev, &firmware_attr); vfree(firmware_attr.private); @@ -151,7 +151,7 @@ static int verify_firmware(struct intel_gvt *gvt, const struct firmware *fw) { struct intel_gvt_device_info *info = &gvt->device_info; - struct pci_dev *pdev = gvt->gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); struct gvt_firmware_header *h; unsigned long id, crc32_start; const void *mem; @@ -205,7 +205,7 @@ static int verify_firmware(struct intel_gvt *gvt, int intel_gvt_load_firmware(struct intel_gvt *gvt) { struct intel_gvt_device_info *info = &gvt->device_info; - struct pci_dev *pdev = gvt->gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); struct intel_gvt_firmware *firmware = &gvt->firmware; struct gvt_firmware_header *h; const struct firmware *fw; @@ -240,7 +240,7 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt) gvt_dbg_core("request hw state firmware %s...\n", path); - ret = request_firmware(&fw, path, &gvt->gt->i915->drm.pdev->dev); + ret = request_firmware(&fw, path, gvt->gt->i915->drm.dev); kfree(path); if (ret) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 897c007ea96a1..6d12a5a401f6c 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -746,7 +746,7 @@ static int detach_oos_page(struct intel_vgpu *vgpu, static void ppgtt_free_spt(struct intel_vgpu_ppgtt_spt *spt) { - struct device *kdev = &spt->vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *kdev = spt->vgpu->gvt->gt->i915->drm.dev; trace_spt_free(spt->vgpu->id, spt, spt->guest_page.type); @@ -831,7 +831,7 @@ static int reclaim_one_ppgtt_mm(struct intel_gvt *gvt); static struct intel_vgpu_ppgtt_spt *ppgtt_alloc_spt( struct intel_vgpu *vgpu, enum intel_gvt_gtt_type type) { - struct device *kdev = &vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *kdev = vgpu->gvt->gt->i915->drm.dev; struct intel_vgpu_ppgtt_spt *spt = NULL; dma_addr_t daddr; int ret; @@ -2402,7 +2402,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, vgpu->gvt->device_info.gtt_entry_size_shift; void *scratch_pt; int i; - struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *dev = vgpu->gvt->gt->i915->drm.dev; dma_addr_t daddr; if (drm_WARN_ON(&i915->drm, @@ -2460,7 +2460,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, static int release_scratch_page_tree(struct intel_vgpu *vgpu) { int i; - struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *dev = vgpu->gvt->gt->i915->drm.dev; dma_addr_t daddr; for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) { @@ -2732,7 +2732,7 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) { int ret; void *page; - struct device *dev = &gvt->gt->i915->drm.pdev->dev; + struct device *dev = gvt->gt->i915->drm.dev; dma_addr_t daddr; gvt_dbg_core("init gtt\n"); @@ -2781,7 +2781,7 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) */ void intel_gvt_clean_gtt(struct intel_gvt *gvt) { - struct device *dev = &gvt->gt->i915->drm.pdev->dev; + struct device *dev = gvt->gt->i915->drm.dev; dma_addr_t daddr = (dma_addr_t)(gvt->gtt.scratch_mfn << I915_GTT_PAGE_SHIFT); diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index d1d8ee4a5f16a..aa7fc0dd1db5d 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -50,7 +50,7 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt, const char *name) { const char *driver_name = - dev_driver_string(&gvt->gt->i915->drm.pdev->dev); + dev_driver_string(gvt->gt->i915->drm.dev); int i; name += strlen(driver_name) + 1; @@ -189,7 +189,7 @@ static const struct intel_gvt_ops intel_gvt_ops = { static void init_device_info(struct intel_gvt *gvt) { struct intel_gvt_device_info *info = &gvt->device_info; - struct pci_dev *pdev = gvt->gt->i915->drm.pdev; + struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev); info->max_support_vgpus = 8; info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE; @@ -376,7 +376,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915) intel_gvt_debugfs_init(gvt); gvt_dbg_core("gvt device initialization is done\n"); - intel_gvt_host.dev = &i915->drm.pdev->dev; + intel_gvt_host.dev = i915->drm.dev; intel_gvt_host.initialized = true; return 0; diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 60f1a386dd060..551f00024e994 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -221,7 +221,7 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, dma_addr_t *dma_addr, unsigned long size) { - struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *dev = vgpu->gvt->gt->i915->drm.dev; struct page *page = NULL; int ret; @@ -244,7 +244,7 @@ static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn, static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn, dma_addr_t dma_addr, unsigned long size) { - struct device *dev = &vgpu->gvt->gt->i915->drm.pdev->dev; + struct device *dev = vgpu->gvt->gt->i915->drm.dev; dma_unmap_page(dev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); gvt_unpin_guest_page(vgpu, gfn, size); From 58a92bcec33b82d79d051214310cc9b8d3901dc7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Feb 2021 11:08:03 +0000 Subject: [PATCH 031/142] drm/i915/display: fix spelling mistake "Couldnt" -> "Couldn't" There is a spelling mistake in a drm_dbg message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210203110803.17894-1-colin.king@canonical.com --- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 8c12d5375607a..a338720cee2ef 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2650,7 +2650,7 @@ void intel_dp_check_frl_training(struct intel_dp *intel_dp) if (intel_dp_pcon_start_frl_training(intel_dp) < 0) { int ret, mode; - drm_dbg(&dev_priv->drm, "Couldnt set FRL mode, continuing with TMDS mode\n"); + drm_dbg(&dev_priv->drm, "Couldn't set FRL mode, continuing with TMDS mode\n"); ret = drm_dp_pcon_reset_frl_config(&intel_dp->aux); mode = drm_dp_pcon_hdmi_link_mode(&intel_dp->aux, NULL); From 7962893ecb853aa7c8925ce237ab6c4274cfc1c7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 27 Jan 2021 20:19:09 +0200 Subject: [PATCH 032/142] drm/i915: Disable runtime power management during shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on some TGL platforms PUNIT wants to access some display HW registers, but it doesn't handle display power management (disabling DC states as required) and so this register access will lead to a hang. To prevent this disable runtime power management for poweroff and reboot. v2: - Add code comment clarifying the requirement of display power states. (Ville) Reported-and-tested-by: Khaled Almahallawy Signed-off-by: Imre Deak Reviewed-by: Khaled Almahallawy Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210127181909.128094-1-imre.deak@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index df165dba7c0bb..57d693eb24f36 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1047,6 +1047,8 @@ static void intel_shutdown_encoders(struct drm_i915_private *dev_priv) void i915_driver_shutdown(struct drm_i915_private *i915) { disable_rpm_wakeref_asserts(&i915->runtime_pm); + intel_runtime_pm_disable(&i915->runtime_pm); + intel_power_domains_disable(i915); i915_gem_suspend(i915); @@ -1062,7 +1064,15 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_suspend_encoders(i915); intel_shutdown_encoders(i915); + /* + * The only requirement is to reboot with display DC states disabled, + * for now leaving all display power wells in the INIT power domain + * enabled matching the driver reload sequence. + */ + intel_power_domains_driver_remove(i915); enable_rpm_wakeref_asserts(&i915->runtime_pm); + + intel_runtime_pm_driver_release(&i915->runtime_pm); } static bool suspend_to_idle(struct drm_i915_private *dev_priv) From 41751b3e5c1ac656a86f8d45a8891115281b729e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Feb 2021 11:30:44 +0200 Subject: [PATCH 033/142] drm/i915: Reject 446-480MHz HDMI clock on GLK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BXT/GLK DPLL can't generate certain frequencies. We already reject the 233-240MHz range on both. But on GLK the DPLL max frequency was bumped from 300MHz to 594MHz, so now we get to also worry about the 446-480MHz range (double the original problem range). Reject any frequency within the higher problematic range as well. Cc: stable@vger.kernel.org Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/3000 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210203093044.30532-1-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_hdmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 66e1ac3887c65..b593a71e65172 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2218,7 +2218,11 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, has_hdmi_sink)) return MODE_CLOCK_HIGH; - /* BXT DPLL can't generate 223-240 MHz */ + /* GLK DPLL can't generate 446-480 MHz */ + if (IS_GEMINILAKE(dev_priv) && clock > 446666 && clock < 480000) + return MODE_CLOCK_RANGE; + + /* BXT/GLK DPLL can't generate 223-240 MHz */ if (IS_GEN9_LP(dev_priv) && clock > 223333 && clock < 240000) return MODE_CLOCK_RANGE; From 1f1257a67ca34deb9708814c491053be8520644b Mon Sep 17 00:00:00 2001 From: Clint Taylor Date: Thu, 4 Feb 2021 12:04:58 -0800 Subject: [PATCH 034/142] drm/i915/display: support ddr5 mem types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add DDR5 and LPDDR5 return values from punit fw. BSPEC: 54023 Cc: Matt Roper Cc: José Roberto de Souza Signed-off-by: Clint Taylor Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210204200458.21875-1-clinton.a.taylor@intel.com --- drivers/gpu/drm/i915/display/intel_bw.c | 12 +++++++++++- drivers/gpu/drm/i915/i915_drv.h | 4 +++- drivers/gpu/drm/i915/intel_dram.c | 6 ++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index ba9e713585e71..d122b99655323 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -78,7 +78,17 @@ static int icl_get_qgv_points(struct drm_i915_private *dev_priv, qi->num_points = dram_info->num_qgv_points; if (IS_GEN(dev_priv, 12)) - qi->t_bl = dev_priv->dram_info.type == INTEL_DRAM_DDR4 ? 4 : 16; + switch (dram_info->type) { + case INTEL_DRAM_DDR4: + qi->t_bl = 4; + break; + case INTEL_DRAM_DDR5: + qi->t_bl = 8; + break; + default: + qi->t_bl = 16; + break; + } else if (IS_GEN(dev_priv, 11)) qi->t_bl = dev_priv->dram_info.type == INTEL_DRAM_DDR4 ? 4 : 8; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 105109bc84dad..60c52588d552a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1133,7 +1133,9 @@ struct drm_i915_private { INTEL_DRAM_DDR3, INTEL_DRAM_DDR4, INTEL_DRAM_LPDDR3, - INTEL_DRAM_LPDDR4 + INTEL_DRAM_LPDDR4, + INTEL_DRAM_DDR5, + INTEL_DRAM_LPDDR5, } type; u8 num_qgv_points; } dram_info; diff --git a/drivers/gpu/drm/i915/intel_dram.c b/drivers/gpu/drm/i915/intel_dram.c index 73d256fc68306..1e53c017c30d4 100644 --- a/drivers/gpu/drm/i915/intel_dram.c +++ b/drivers/gpu/drm/i915/intel_dram.c @@ -427,6 +427,12 @@ static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv) case 0: dram_info->type = INTEL_DRAM_DDR4; break; + case 1: + dram_info->type = INTEL_DRAM_DDR5; + break; + case 2: + dram_info->type = INTEL_DRAM_LPDDR5; + break; case 3: dram_info->type = INTEL_DRAM_LPDDR4; break; From b64d6c51380b7dea17d5503a250ca9cc84025453 Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Thu, 4 Feb 2021 15:40:14 +0200 Subject: [PATCH 035/142] drm/i915/display: Support PSR Multiple Instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is a preliminary work for supporting multiple EDP PSR and DP PanelReplay. And it refactors singleton PSR to Multi Transcoder supportable PSR. And this moves and renames the i915_psr structure of drm_i915_private's to intel_dp's intel_psr structure. It also causes changes in PSR interrupt handling routine for supporting multiple transcoders. But it does not change the scenario and timing of enabling and disabling PSR. And it not support multiple pipes with a single transcoder PSR case yet. v2: Fix indentation and add comments v3: Remove Blank line v4: Rebased v5: Rebased and Addressed Anshuman's review comment. - Move calling of intel_psr_init() to intel_dp_init_connector() v6: Address Anshuman's review comments - Remove wrong comments and add comments for a limit of supporting of a single pipe PSR v7: Update intel_psr_compute_config() for supporting multiple transcoder PSR on BDW+ v8: Address Anshuman's review comments - Replace DRM_DEBUG_KMS with drm_dbg_kms() / DRM_WARN with drm_warn() v9: Fix commit message v10: Rebased v11: Address Jose's review comment. - Reorder calling order of intel_psr2_program_trans_man_trk_ctl(). - In order to reduce changes keep the old name for drm_i915_private. - Change restrictions of multiple instances of PSR. v12: Address Jose's review comment. - Change the calling of intel_psr2_program_trans_man_trk_ctl() into commit_pipe_config(). - Change a checking order of CAN_PSR() and connector_status to original on i915_psr_sink_status_show(). - Drop unneeded intel_dp_update_pipe() function. - In order to wait a specific encoder which belong to crtc_state on intel_psr_wait_for_idle(), add checking of encoder. - Add an whitespace to comments. v13: Rebased and Address Jose's review comment. - Add and use for_each_intel_psr_enabled_encoder() macro. - In order to use correct frontbuffer_bit for each pipe, fix intel_psr_invalidate() and intel_psr_flush(). - Remove redundant or unneeded codes. - Update comments. v14: Address Jose's review comment - Add and use for_each_intel_encoder_can_psr() macro and for_each_intel_encoder_mask_can_psr() macro. - Add source_support member variable into intel_psr structure. - Update CAN_PSR() macro that checks source_support. - Move encoder's PSR availity check to psr_init() from psr_compute_config(). - Remove redundant or unneeded codes. v15: Remove wrong mutex lock/unlock of PSR from intel_psr2_program_trans_man_trk_ctl() Signed-off-by: Gwan-gyeong Mun Cc: José Roberto de Souza Cc: Juha-Pekka Heikkila Cc: Anshuman Gupta Reviewed-by: Anshuman Gupta Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210204134015.419036-1-gwan-gyeong.mun@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 2 - drivers/gpu/drm/i915/display/intel_display.h | 9 + .../drm/i915/display/intel_display_debugfs.c | 95 ++- .../drm/i915/display/intel_display_types.h | 51 ++ drivers/gpu/drm/i915/display/intel_dp.c | 10 +- drivers/gpu/drm/i915/display/intel_psr.c | 600 ++++++++++-------- drivers/gpu/drm/i915/display/intel_psr.h | 10 +- drivers/gpu/drm/i915/display/intel_sprite.c | 6 +- drivers/gpu/drm/i915/i915_drv.h | 38 -- drivers/gpu/drm/i915/i915_irq.c | 42 +- 10 files changed, 487 insertions(+), 376 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c290339dc022d..5a36575ba3705 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -14155,8 +14155,6 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_dvo_init(dev_priv); } - intel_psr_init(dev_priv); - for_each_intel_encoder(&dev_priv->drm, encoder) { encoder->base.possible_crtcs = intel_encoder_possible_crtcs(encoder); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 64ffa34544a7d..c72e41b613495 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -417,10 +417,19 @@ enum phy_fia { for_each_if((encoder_mask) & \ drm_encoder_mask(&intel_encoder->base)) +#define for_each_intel_encoder_mask_can_psr(dev, intel_encoder, encoder_mask) \ + list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ + for_each_if(((encoder_mask) & drm_encoder_mask(&(intel_encoder)->base)) && \ + intel_encoder_can_psr(intel_encoder)) + #define for_each_intel_dp(dev, intel_encoder) \ for_each_intel_encoder(dev, intel_encoder) \ for_each_if(intel_encoder_is_dp(intel_encoder)) +#define for_each_intel_encoder_can_psr(dev, intel_encoder) \ + for_each_intel_encoder((dev), (intel_encoder)) \ + for_each_if(intel_encoder_can_psr(intel_encoder)) + #define for_each_intel_connector_iter(intel_connector, iter) \ while ((intel_connector = to_intel_connector(drm_connector_list_iter_next(iter)))) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index d62b18d5ecd80..b1bda1f5ef16b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -249,12 +249,11 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) "sink internal error", }; struct drm_connector *connector = m->private; - struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_dp *intel_dp = intel_attached_dp(to_intel_connector(connector)); int ret; - if (!CAN_PSR(dev_priv)) { + if (!CAN_PSR(intel_dp)) { seq_puts(m, "PSR Unsupported\n"); return -ENODEV; } @@ -280,12 +279,13 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) DEFINE_SHOW_ATTRIBUTE(i915_psr_sink_status); static void -psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) +psr_source_status(struct intel_dp *intel_dp, struct seq_file *m) { - u32 val, status_val; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const char *status = "unknown"; + u32 val, status_val; - if (dev_priv->psr.psr2_enabled) { + if (intel_dp->psr.psr2_enabled) { static const char * const live_status[] = { "IDLE", "CAPTURE", @@ -300,7 +300,7 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) "TG_ON" }; val = intel_de_read(dev_priv, - EDP_PSR2_STATUS(dev_priv->psr.transcoder)); + EDP_PSR2_STATUS(intel_dp->psr.transcoder)); status_val = (val & EDP_PSR2_STATUS_STATE_MASK) >> EDP_PSR2_STATUS_STATE_SHIFT; if (status_val < ARRAY_SIZE(live_status)) @@ -317,7 +317,7 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) "SRDENT_ON", }; val = intel_de_read(dev_priv, - EDP_PSR_STATUS(dev_priv->psr.transcoder)); + EDP_PSR_STATUS(intel_dp->psr.transcoder)); status_val = (val & EDP_PSR_STATUS_STATE_MASK) >> EDP_PSR_STATUS_STATE_SHIFT; if (status_val < ARRAY_SIZE(live_status)) @@ -327,21 +327,18 @@ psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m) seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val); } -static int i915_edp_psr_status(struct seq_file *m, void *data) +static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = node_to_i915(m->private); - struct i915_psr *psr = &dev_priv->psr; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct intel_psr *psr = &intel_dp->psr; intel_wakeref_t wakeref; const char *status; bool enabled; u32 val; - if (!HAS_PSR(dev_priv)) - return -ENODEV; - seq_printf(m, "Sink support: %s", yesno(psr->sink_support)); - if (psr->dp) - seq_printf(m, " [0x%02x]", psr->dp->psr_dpcd[0]); + if (psr->sink_support) + seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]); seq_puts(m, "\n"); if (!psr->sink_support) @@ -365,16 +362,16 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) if (psr->psr2_enabled) { val = intel_de_read(dev_priv, - EDP_PSR2_CTL(dev_priv->psr.transcoder)); + EDP_PSR2_CTL(intel_dp->psr.transcoder)); enabled = val & EDP_PSR2_ENABLE; } else { val = intel_de_read(dev_priv, - EDP_PSR_CTL(dev_priv->psr.transcoder)); + EDP_PSR_CTL(intel_dp->psr.transcoder)); enabled = val & EDP_PSR_ENABLE; } seq_printf(m, "Source PSR ctl: %s [0x%08x]\n", enableddisabled(enabled), val); - psr_source_status(dev_priv, m); + psr_source_status(intel_dp, m); seq_printf(m, "Busy frontbuffer bits: 0x%08x\n", psr->busy_frontbuffer_bits); @@ -383,7 +380,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) */ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { val = intel_de_read(dev_priv, - EDP_PSR_PERF_CNT(dev_priv->psr.transcoder)); + EDP_PSR_PERF_CNT(intel_dp->psr.transcoder)); val &= EDP_PSR_PERF_CNT_MASK; seq_printf(m, "Performance counter: %u\n", val); } @@ -404,7 +401,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) */ for (frame = 0; frame < PSR2_SU_STATUS_FRAMES; frame += 3) { val = intel_de_read(dev_priv, - PSR2_SU_STATUS(dev_priv->psr.transcoder, frame)); + PSR2_SU_STATUS(intel_dp->psr.transcoder, frame)); su_frames_val[frame / 3] = val; } @@ -430,23 +427,50 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) return 0; } +static int i915_edp_psr_status(struct seq_file *m, void *data) +{ + struct drm_i915_private *dev_priv = node_to_i915(m->private); + struct intel_dp *intel_dp = NULL; + struct intel_encoder *encoder; + + if (!HAS_PSR(dev_priv)) + return -ENODEV; + + /* Find the first EDP which supports PSR */ + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + intel_dp = enc_to_intel_dp(encoder); + break; + } + + if (!intel_dp) + return -ENODEV; + + return intel_psr_status(m, intel_dp); +} + static int i915_edp_psr_debug_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; + struct intel_encoder *encoder; intel_wakeref_t wakeref; - int ret; + int ret = -ENODEV; - if (!CAN_PSR(dev_priv)) - return -ENODEV; + if (!HAS_PSR(dev_priv)) + return ret; - drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val); + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); + drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val); - ret = intel_psr_debug_set(dev_priv, val); + wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); + // TODO: split to each transcoder's PSR debug state + ret = intel_psr_debug_set(intel_dp, val); + + intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); + } return ret; } @@ -455,12 +479,20 @@ static int i915_edp_psr_debug_get(void *data, u64 *val) { struct drm_i915_private *dev_priv = data; + struct intel_encoder *encoder; - if (!CAN_PSR(dev_priv)) + if (!HAS_PSR(dev_priv)) return -ENODEV; - *val = READ_ONCE(dev_priv->psr.debug); - return 0; + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + // TODO: split to each transcoder's PSR debug state + *val = READ_ONCE(intel_dp->psr.debug); + return 0; + } + + return -ENODEV; } DEFINE_SIMPLE_ATTRIBUTE(i915_edp_psr_debug_fops, @@ -1233,9 +1265,6 @@ static void drrs_status_per_crtc(struct seq_file *m, /* disable_drrs() will make drrs->dp NULL */ if (!drrs->dp) { seq_puts(m, "Idleness DRRS: Disabled\n"); - if (dev_priv->psr.enabled) - seq_puts(m, - "\tAs PSR is enabled, DRRS is not enabled\n"); mutex_unlock(&drrs->mutex); return; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 39397748b4b0c..307ff4b771f44 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1415,6 +1415,43 @@ struct intel_pps { struct edp_power_seq pps_delays; }; +struct intel_psr { + /* Mutex for PSR state of the transcoder */ + struct mutex lock; + +#define I915_PSR_DEBUG_MODE_MASK 0x0f +#define I915_PSR_DEBUG_DEFAULT 0x00 +#define I915_PSR_DEBUG_DISABLE 0x01 +#define I915_PSR_DEBUG_ENABLE 0x02 +#define I915_PSR_DEBUG_FORCE_PSR1 0x03 +#define I915_PSR_DEBUG_IRQ 0x10 + + u32 debug; + bool sink_support; + bool source_support; + bool enabled; + enum pipe pipe; + enum transcoder transcoder; + bool active; + struct work_struct work; + unsigned int busy_frontbuffer_bits; + bool sink_psr2_support; + bool link_standby; + bool colorimetry_support; + bool psr2_enabled; + bool psr2_sel_fetch_enabled; + u8 sink_sync_latency; + ktime_t last_entry_attempt; + ktime_t last_exit; + bool sink_not_reliable; + bool irq_aux_error; + u16 su_x_granularity; + bool dc3co_enabled; + u32 dc3co_exit_delay; + struct delayed_work dc3co_work; + struct drm_dp_vsc_sdp vsc; +}; + struct intel_dp { i915_reg_t output_reg; u32 DP; @@ -1517,6 +1554,8 @@ struct intel_dp { bool hobl_active; struct intel_dp_pcon_frl frl; + + struct intel_psr psr; }; enum lspcon_vendor { @@ -1753,6 +1792,18 @@ dp_to_i915(struct intel_dp *intel_dp) return to_i915(dp_to_dig_port(intel_dp)->base.base.dev); } +#define CAN_PSR(intel_dp) (HAS_PSR(dp_to_i915(intel_dp)) && \ + (intel_dp)->psr.sink_support && \ + (intel_dp)->psr.source_support) + +static inline bool intel_encoder_can_psr(struct intel_encoder *encoder) +{ + if (!intel_encoder_is_dp(encoder)) + return false; + + return CAN_PSR(enc_to_intel_dp(encoder)); +} + static inline struct intel_digital_port * hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index a338720cee2ef..96789fbd4c06e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1663,12 +1663,10 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, const struct drm_connector_state *conn_state, struct drm_dp_vsc_sdp *vsc) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - vsc->sdp_type = DP_SDP_VSC; - if (dev_priv->psr.psr2_enabled) { - if (dev_priv->psr.colorimetry_support && + if (intel_dp->psr.psr2_enabled) { + if (intel_dp->psr.colorimetry_support && intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { /* [PSR2, +Colorimetry] */ intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, @@ -2359,7 +2357,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, return false; } - if (CAN_PSR(i915) && intel_dp_is_edp(intel_dp)) { + if (CAN_PSR(intel_dp) && intel_dp_is_edp(intel_dp)) { drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n"); crtc_state->uapi.mode_changed = true; return false; @@ -6641,6 +6639,8 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, intel_dp->frl.is_trained = false; intel_dp->frl.trained_rate_gbps = 0; + intel_psr_init(intel_dp); + return true; fail: diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 2c365b778f74b..bf48eb4e1a847 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -80,9 +80,11 @@ * use page flips. */ -static bool psr_global_enabled(struct drm_i915_private *i915) +static bool psr_global_enabled(struct intel_dp *intel_dp) { - switch (i915->psr.debug & I915_PSR_DEBUG_MODE_MASK) { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DEFAULT: return i915->params.enable_psr; case I915_PSR_DEBUG_DISABLE: @@ -92,9 +94,9 @@ static bool psr_global_enabled(struct drm_i915_private *i915) } } -static bool psr2_global_enabled(struct drm_i915_private *dev_priv) +static bool psr2_global_enabled(struct intel_dp *intel_dp) { - switch (dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK) { + switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DISABLE: case I915_PSR_DEBUG_FORCE_PSR1: return false; @@ -103,11 +105,12 @@ static bool psr2_global_enabled(struct drm_i915_private *dev_priv) } } -static void psr_irq_control(struct drm_i915_private *dev_priv) +static void psr_irq_control(struct intel_dp *intel_dp) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum transcoder trans_shift; - u32 mask, val; i915_reg_t imr_reg; + u32 mask, val; /* * gen12+ has registers relative to transcoder and one per transcoder @@ -116,14 +119,14 @@ static void psr_irq_control(struct drm_i915_private *dev_priv) */ if (INTEL_GEN(dev_priv) >= 12) { trans_shift = 0; - imr_reg = TRANS_PSR_IMR(dev_priv->psr.transcoder); + imr_reg = TRANS_PSR_IMR(intel_dp->psr.transcoder); } else { - trans_shift = dev_priv->psr.transcoder; + trans_shift = intel_dp->psr.transcoder; imr_reg = EDP_PSR_IMR; } mask = EDP_PSR_ERROR(trans_shift); - if (dev_priv->psr.debug & I915_PSR_DEBUG_IRQ) + if (intel_dp->psr.debug & I915_PSR_DEBUG_IRQ) mask |= EDP_PSR_POST_EXIT(trans_shift) | EDP_PSR_PRE_ENTRY(trans_shift); @@ -172,30 +175,31 @@ static void psr_event_print(struct drm_i915_private *i915, drm_dbg_kms(&i915->drm, "\tPSR disabled\n"); } -void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) +void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir) { - enum transcoder cpu_transcoder = dev_priv->psr.transcoder; + enum transcoder cpu_transcoder = intel_dp->psr.transcoder; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + ktime_t time_ns = ktime_get(); enum transcoder trans_shift; i915_reg_t imr_reg; - ktime_t time_ns = ktime_get(); if (INTEL_GEN(dev_priv) >= 12) { trans_shift = 0; - imr_reg = TRANS_PSR_IMR(dev_priv->psr.transcoder); + imr_reg = TRANS_PSR_IMR(intel_dp->psr.transcoder); } else { - trans_shift = dev_priv->psr.transcoder; + trans_shift = intel_dp->psr.transcoder; imr_reg = EDP_PSR_IMR; } if (psr_iir & EDP_PSR_PRE_ENTRY(trans_shift)) { - dev_priv->psr.last_entry_attempt = time_ns; + intel_dp->psr.last_entry_attempt = time_ns; drm_dbg_kms(&dev_priv->drm, "[transcoder %s] PSR entry attempt in 2 vblanks\n", transcoder_name(cpu_transcoder)); } if (psr_iir & EDP_PSR_POST_EXIT(trans_shift)) { - dev_priv->psr.last_exit = time_ns; + intel_dp->psr.last_exit = time_ns; drm_dbg_kms(&dev_priv->drm, "[transcoder %s] PSR exit completed\n", transcoder_name(cpu_transcoder)); @@ -203,7 +207,7 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) if (INTEL_GEN(dev_priv) >= 9) { u32 val = intel_de_read(dev_priv, PSR_EVENT(cpu_transcoder)); - bool psr2_enabled = dev_priv->psr.psr2_enabled; + bool psr2_enabled = intel_dp->psr.psr2_enabled; intel_de_write(dev_priv, PSR_EVENT(cpu_transcoder), val); @@ -217,7 +221,7 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) drm_warn(&dev_priv->drm, "[transcoder %s] PSR aux error\n", transcoder_name(cpu_transcoder)); - dev_priv->psr.irq_aux_error = true; + intel_dp->psr.irq_aux_error = true; /* * If this interruption is not masked it will keep @@ -231,7 +235,7 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) val |= EDP_PSR_ERROR(trans_shift); intel_de_write(dev_priv, imr_reg, val); - schedule_work(&dev_priv->psr.work); + schedule_work(&intel_dp->psr.work); } } @@ -292,12 +296,6 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = to_i915(dp_to_dig_port(intel_dp)->base.base.dev); - if (dev_priv->psr.dp) { - drm_warn(&dev_priv->drm, - "More than one eDP panel found, PSR support should be extended\n"); - return; - } - drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, sizeof(intel_dp->psr_dpcd)); @@ -318,12 +316,10 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) return; } - dev_priv->psr.sink_support = true; - dev_priv->psr.sink_sync_latency = + intel_dp->psr.sink_support = true; + intel_dp->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); - dev_priv->psr.dp = intel_dp; - if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { bool y_req = intel_dp->psr_dpcd[1] & @@ -341,14 +337,14 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * Y-coordinate requirement panels we would need to enable * GTC first. */ - dev_priv->psr.sink_psr2_support = y_req && alpm; + intel_dp->psr.sink_psr2_support = y_req && alpm; drm_dbg_kms(&dev_priv->drm, "PSR2 %ssupported\n", - dev_priv->psr.sink_psr2_support ? "" : "not "); + intel_dp->psr.sink_psr2_support ? "" : "not "); - if (dev_priv->psr.sink_psr2_support) { - dev_priv->psr.colorimetry_support = + if (intel_dp->psr.sink_psr2_support) { + intel_dp->psr.colorimetry_support = intel_dp_get_colorimetry_status(intel_dp); - dev_priv->psr.su_x_granularity = + intel_dp->psr.su_x_granularity = intel_dp_get_su_x_granulartiy(intel_dp); } } @@ -374,7 +370,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) BUILD_BUG_ON(sizeof(aux_msg) > 20); for (i = 0; i < sizeof(aux_msg); i += 4) intel_de_write(dev_priv, - EDP_PSR_AUX_DATA(dev_priv->psr.transcoder, i >> 2), + EDP_PSR_AUX_DATA(intel_dp->psr.transcoder, i >> 2), intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0); @@ -385,7 +381,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) /* Select only valid bits for SRD_AUX_CTL */ aux_ctl &= psr_aux_mask; - intel_de_write(dev_priv, EDP_PSR_AUX_CTL(dev_priv->psr.transcoder), + intel_de_write(dev_priv, EDP_PSR_AUX_CTL(intel_dp->psr.transcoder), aux_ctl); } @@ -395,14 +391,14 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) u8 dpcd_val = DP_PSR_ENABLE; /* Enable ALPM at sink for psr2 */ - if (dev_priv->psr.psr2_enabled) { + if (intel_dp->psr.psr2_enabled) { drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE); dpcd_val |= DP_PSR_ENABLE_PSR2 | DP_PSR_IRQ_HPD_WITH_CRC_ERRORS; } else { - if (dev_priv->psr.link_standby) + if (intel_dp->psr.link_standby) dpcd_val |= DP_PSR_MAIN_LINK_ACTIVE; if (INTEL_GEN(dev_priv) >= 8) @@ -465,7 +461,7 @@ static u8 psr_compute_idle_frames(struct intel_dp *intel_dp) * off-by-one issue that HW has in some cases. */ idle_frames = max(6, dev_priv->vbt.psr.idle_frames); - idle_frames = max(idle_frames, dev_priv->psr.sink_sync_latency + 1); + idle_frames = max(idle_frames, intel_dp->psr.sink_sync_latency + 1); if (drm_WARN_ON(&dev_priv->drm, idle_frames > 0xf)) idle_frames = 0xf; @@ -485,7 +481,7 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (IS_HASWELL(dev_priv)) val |= EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; - if (dev_priv->psr.link_standby) + if (intel_dp->psr.link_standby) val |= EDP_PSR_LINK_STANDBY; val |= intel_psr1_get_tp_time(intel_dp); @@ -493,9 +489,9 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (INTEL_GEN(dev_priv) >= 8) val |= EDP_PSR_CRC_ENABLE; - val |= (intel_de_read(dev_priv, EDP_PSR_CTL(dev_priv->psr.transcoder)) & + val |= (intel_de_read(dev_priv, EDP_PSR_CTL(intel_dp->psr.transcoder)) & EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK); - intel_de_write(dev_priv, EDP_PSR_CTL(dev_priv->psr.transcoder), val); + intel_de_write(dev_priv, EDP_PSR_CTL(intel_dp->psr.transcoder), val); } static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) @@ -530,7 +526,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) val |= EDP_Y_COORDINATE_ENABLE; - val |= EDP_PSR2_FRAME_BEFORE_SU(dev_priv->psr.sink_sync_latency + 1); + val |= EDP_PSR2_FRAME_BEFORE_SU(intel_dp->psr.sink_sync_latency + 1); val |= intel_psr2_get_tp_time(intel_dp); if (INTEL_GEN(dev_priv) >= 12) { @@ -549,7 +545,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) val |= EDP_PSR2_FAST_WAKE(7); } - if (dev_priv->psr.psr2_sel_fetch_enabled) { + if (intel_dp->psr.psr2_sel_fetch_enabled) { /* WA 1408330847 */ if (IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_A0) || IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0)) @@ -558,20 +554,20 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) DIS_RAM_BYPASS_PSR2_MAN_TRACK); intel_de_write(dev_priv, - PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), + PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), PSR2_MAN_TRK_CTL_ENABLE); } else if (HAS_PSR2_SEL_FETCH(dev_priv)) { intel_de_write(dev_priv, - PSR2_MAN_TRK_CTL(dev_priv->psr.transcoder), 0); + PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0); } /* * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. */ - intel_de_write(dev_priv, EDP_PSR_CTL(dev_priv->psr.transcoder), 0); + intel_de_write(dev_priv, EDP_PSR_CTL(intel_dp->psr.transcoder), 0); - intel_de_write(dev_priv, EDP_PSR2_CTL(dev_priv->psr.transcoder), val); + intel_de_write(dev_priv, EDP_PSR2_CTL(intel_dp->psr.transcoder), val); } static bool @@ -594,55 +590,58 @@ static u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate) drm_mode_vrefresh(&cstate->hw.adjusted_mode)); } -static void psr2_program_idle_frames(struct drm_i915_private *dev_priv, +static void psr2_program_idle_frames(struct intel_dp *intel_dp, u32 idle_frames) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 val; idle_frames <<= EDP_PSR2_IDLE_FRAME_SHIFT; - val = intel_de_read(dev_priv, EDP_PSR2_CTL(dev_priv->psr.transcoder)); + val = intel_de_read(dev_priv, EDP_PSR2_CTL(intel_dp->psr.transcoder)); val &= ~EDP_PSR2_IDLE_FRAME_MASK; val |= idle_frames; - intel_de_write(dev_priv, EDP_PSR2_CTL(dev_priv->psr.transcoder), val); + intel_de_write(dev_priv, EDP_PSR2_CTL(intel_dp->psr.transcoder), val); } -static void tgl_psr2_enable_dc3co(struct drm_i915_private *dev_priv) +static void tgl_psr2_enable_dc3co(struct intel_dp *intel_dp) { - psr2_program_idle_frames(dev_priv, 0); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + psr2_program_idle_frames(intel_dp, 0); intel_display_power_set_target_dc_state(dev_priv, DC_STATE_EN_DC3CO); } -static void tgl_psr2_disable_dc3co(struct drm_i915_private *dev_priv) +static void tgl_psr2_disable_dc3co(struct intel_dp *intel_dp) { - struct intel_dp *intel_dp = dev_priv->psr.dp; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); intel_display_power_set_target_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); - psr2_program_idle_frames(dev_priv, psr_compute_idle_frames(intel_dp)); + psr2_program_idle_frames(intel_dp, psr_compute_idle_frames(intel_dp)); } static void tgl_dc3co_disable_work(struct work_struct *work) { - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), psr.dc3co_work.work); + struct intel_dp *intel_dp = + container_of(work, typeof(*intel_dp), psr.dc3co_work.work); - mutex_lock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); /* If delayed work is pending, it is not idle */ - if (delayed_work_pending(&dev_priv->psr.dc3co_work)) + if (delayed_work_pending(&intel_dp->psr.dc3co_work)) goto unlock; - tgl_psr2_disable_dc3co(dev_priv); + tgl_psr2_disable_dc3co(intel_dp); unlock: - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); } -static void tgl_disallow_dc3co_on_psr2_exit(struct drm_i915_private *dev_priv) +static void tgl_disallow_dc3co_on_psr2_exit(struct intel_dp *intel_dp) { - if (!dev_priv->psr.dc3co_enabled) + if (!intel_dp->psr.dc3co_enabled) return; - cancel_delayed_work(&dev_priv->psr.dc3co_work); + cancel_delayed_work(&intel_dp->psr.dc3co_work); /* Before PSR2 exit disallow dc3co*/ - tgl_psr2_disable_dc3co(dev_priv); + tgl_psr2_disable_dc3co(intel_dp); } static void @@ -715,7 +714,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, int crtc_vdisplay = crtc_state->hw.adjusted_mode.crtc_vdisplay; int psr_max_h = 0, psr_max_v = 0, max_bpp = 0; - if (!dev_priv->psr.sink_psr2_support) + if (!intel_dp->psr.sink_psr2_support) return false; if (!transcoder_has_psr2(dev_priv, crtc_state->cpu_transcoder)) { @@ -725,7 +724,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - if (!psr2_global_enabled(dev_priv)) { + if (!psr2_global_enabled(intel_dp)) { drm_dbg_kms(&dev_priv->drm, "PSR2 disabled by flag\n"); return false; } @@ -774,10 +773,10 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * only need to validate the SU block width is a multiple of * x granularity. */ - if (crtc_hdisplay % dev_priv->psr.su_x_granularity) { + if (crtc_hdisplay % intel_dp->psr.su_x_granularity) { drm_dbg_kms(&dev_priv->drm, "PSR2 not enabled, hdisplay(%d) not multiple of %d\n", - crtc_hdisplay, dev_priv->psr.su_x_granularity); + crtc_hdisplay, intel_dp->psr.su_x_granularity); return false; } @@ -806,7 +805,6 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; @@ -819,30 +817,15 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, if (crtc_state->vrr.enable) return; - if (!CAN_PSR(dev_priv)) + if (!CAN_PSR(intel_dp)) return; - if (intel_dp != dev_priv->psr.dp) - return; - - if (!psr_global_enabled(dev_priv)) { + if (!psr_global_enabled(intel_dp)) { drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n"); return; } - /* - * HSW spec explicitly says PSR is tied to port A. - * BDW+ platforms have a instance of PSR registers per transcoder but - * for now it only supports one instance of PSR, so lets keep it - * hardcoded to PORT_A - */ - if (dig_port->base.port != PORT_A) { - drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: Port not supported\n"); - return; - } - - if (dev_priv->psr.sink_not_reliable) { + if (intel_dp->psr.sink_not_reliable) { drm_dbg_kms(&dev_priv->drm, "PSR sink implementation is not reliable\n"); return; @@ -878,23 +861,24 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, static void intel_psr_activate(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + enum transcoder transcoder = intel_dp->psr.transcoder; - if (transcoder_has_psr2(dev_priv, dev_priv->psr.transcoder)) + if (transcoder_has_psr2(dev_priv, transcoder)) drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, EDP_PSR2_CTL(dev_priv->psr.transcoder)) & EDP_PSR2_ENABLE); + intel_de_read(dev_priv, EDP_PSR2_CTL(transcoder)) & EDP_PSR2_ENABLE); drm_WARN_ON(&dev_priv->drm, - intel_de_read(dev_priv, EDP_PSR_CTL(dev_priv->psr.transcoder)) & EDP_PSR_ENABLE); - drm_WARN_ON(&dev_priv->drm, dev_priv->psr.active); - lockdep_assert_held(&dev_priv->psr.lock); + intel_de_read(dev_priv, EDP_PSR_CTL(transcoder)) & EDP_PSR_ENABLE); + drm_WARN_ON(&dev_priv->drm, intel_dp->psr.active); + lockdep_assert_held(&intel_dp->psr.lock); /* psr1 and psr2 are mutually exclusive.*/ - if (dev_priv->psr.psr2_enabled) + if (intel_dp->psr.psr2_enabled) hsw_activate_psr2(intel_dp); else hsw_activate_psr1(intel_dp); - dev_priv->psr.active = true; + intel_dp->psr.active = true; } static void intel_psr_enable_source(struct intel_dp *intel_dp, @@ -910,7 +894,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_psr_setup_aux(intel_dp); - if (dev_priv->psr.psr2_enabled && (IS_GEN(dev_priv, 9) && + if (intel_dp->psr.psr2_enabled && (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv))) { i915_reg_t reg = CHICKEN_TRANS(cpu_transcoder); u32 chicken = intel_de_read(dev_priv, reg); @@ -934,10 +918,10 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, if (INTEL_GEN(dev_priv) < 11) mask |= EDP_PSR_DEBUG_MASK_DISP_REG_WRITE; - intel_de_write(dev_priv, EDP_PSR_DEBUG(dev_priv->psr.transcoder), + intel_de_write(dev_priv, EDP_PSR_DEBUG(intel_dp->psr.transcoder), mask); - psr_irq_control(dev_priv); + psr_irq_control(intel_dp); if (crtc_state->dc3co_exitline) { u32 val; @@ -955,30 +939,30 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, if (HAS_PSR_HW_TRACKING(dev_priv) && HAS_PSR2_SEL_FETCH(dev_priv)) intel_de_rmw(dev_priv, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING, - dev_priv->psr.psr2_sel_fetch_enabled ? + intel_dp->psr.psr2_sel_fetch_enabled ? IGNORE_PSR2_HW_TRACKING : 0); } -static void intel_psr_enable_locked(struct drm_i915_private *dev_priv, +static void intel_psr_enable_locked(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { - struct intel_dp *intel_dp = dev_priv->psr.dp; struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_encoder *encoder = &dig_port->base; u32 val; - drm_WARN_ON(&dev_priv->drm, dev_priv->psr.enabled); + drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled); - dev_priv->psr.psr2_enabled = crtc_state->has_psr2; - dev_priv->psr.busy_frontbuffer_bits = 0; - dev_priv->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - dev_priv->psr.dc3co_enabled = !!crtc_state->dc3co_exitline; - dev_priv->psr.transcoder = crtc_state->cpu_transcoder; + intel_dp->psr.psr2_enabled = crtc_state->has_psr2; + intel_dp->psr.busy_frontbuffer_bits = 0; + intel_dp->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; + intel_dp->psr.dc3co_enabled = !!crtc_state->dc3co_exitline; + intel_dp->psr.transcoder = crtc_state->cpu_transcoder; /* DC5/DC6 requires at least 6 idle frames */ val = usecs_to_jiffies(intel_get_frame_time_us(crtc_state) * 6); - dev_priv->psr.dc3co_exit_delay = val; - dev_priv->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch; + intel_dp->psr.dc3co_exit_delay = val; + intel_dp->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch; /* * If a PSR error happened and the driver is reloaded, the EDP_PSR_IIR @@ -990,27 +974,27 @@ static void intel_psr_enable_locked(struct drm_i915_private *dev_priv, */ if (INTEL_GEN(dev_priv) >= 12) { val = intel_de_read(dev_priv, - TRANS_PSR_IIR(dev_priv->psr.transcoder)); + TRANS_PSR_IIR(intel_dp->psr.transcoder)); val &= EDP_PSR_ERROR(0); } else { val = intel_de_read(dev_priv, EDP_PSR_IIR); - val &= EDP_PSR_ERROR(dev_priv->psr.transcoder); + val &= EDP_PSR_ERROR(intel_dp->psr.transcoder); } if (val) { - dev_priv->psr.sink_not_reliable = true; + intel_dp->psr.sink_not_reliable = true; drm_dbg_kms(&dev_priv->drm, "PSR interruption error set, not enabling PSR\n"); return; } drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", - dev_priv->psr.psr2_enabled ? "2" : "1"); + intel_dp->psr.psr2_enabled ? "2" : "1"); intel_dp_compute_psr_vsc_sdp(intel_dp, crtc_state, conn_state, - &dev_priv->psr.vsc); - intel_write_dp_vsc_sdp(encoder, crtc_state, &dev_priv->psr.vsc); + &intel_dp->psr.vsc); + intel_write_dp_vsc_sdp(encoder, crtc_state, &intel_dp->psr.vsc); intel_psr_enable_sink(intel_dp); intel_psr_enable_source(intel_dp, crtc_state); - dev_priv->psr.enabled = true; + intel_dp->psr.enabled = true; intel_psr_activate(intel_dp); } @@ -1029,7 +1013,7 @@ void intel_psr_enable(struct intel_dp *intel_dp, { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (!CAN_PSR(dev_priv) || dev_priv->psr.dp != intel_dp) + if (!CAN_PSR(intel_dp)) return; if (!crtc_state->has_psr) @@ -1037,46 +1021,47 @@ void intel_psr_enable(struct intel_dp *intel_dp, drm_WARN_ON(&dev_priv->drm, dev_priv->drrs.dp); - mutex_lock(&dev_priv->psr.lock); - intel_psr_enable_locked(dev_priv, crtc_state, conn_state); - mutex_unlock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); + intel_psr_enable_locked(intel_dp, crtc_state, conn_state); + mutex_unlock(&intel_dp->psr.lock); } -static void intel_psr_exit(struct drm_i915_private *dev_priv) +static void intel_psr_exit(struct intel_dp *intel_dp) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 val; - if (!dev_priv->psr.active) { - if (transcoder_has_psr2(dev_priv, dev_priv->psr.transcoder)) { + if (!intel_dp->psr.active) { + if (transcoder_has_psr2(dev_priv, intel_dp->psr.transcoder)) { val = intel_de_read(dev_priv, - EDP_PSR2_CTL(dev_priv->psr.transcoder)); + EDP_PSR2_CTL(intel_dp->psr.transcoder)); drm_WARN_ON(&dev_priv->drm, val & EDP_PSR2_ENABLE); } val = intel_de_read(dev_priv, - EDP_PSR_CTL(dev_priv->psr.transcoder)); + EDP_PSR_CTL(intel_dp->psr.transcoder)); drm_WARN_ON(&dev_priv->drm, val & EDP_PSR_ENABLE); return; } - if (dev_priv->psr.psr2_enabled) { - tgl_disallow_dc3co_on_psr2_exit(dev_priv); + if (intel_dp->psr.psr2_enabled) { + tgl_disallow_dc3co_on_psr2_exit(intel_dp); val = intel_de_read(dev_priv, - EDP_PSR2_CTL(dev_priv->psr.transcoder)); + EDP_PSR2_CTL(intel_dp->psr.transcoder)); drm_WARN_ON(&dev_priv->drm, !(val & EDP_PSR2_ENABLE)); val &= ~EDP_PSR2_ENABLE; intel_de_write(dev_priv, - EDP_PSR2_CTL(dev_priv->psr.transcoder), val); + EDP_PSR2_CTL(intel_dp->psr.transcoder), val); } else { val = intel_de_read(dev_priv, - EDP_PSR_CTL(dev_priv->psr.transcoder)); + EDP_PSR_CTL(intel_dp->psr.transcoder)); drm_WARN_ON(&dev_priv->drm, !(val & EDP_PSR_ENABLE)); val &= ~EDP_PSR_ENABLE; intel_de_write(dev_priv, - EDP_PSR_CTL(dev_priv->psr.transcoder), val); + EDP_PSR_CTL(intel_dp->psr.transcoder), val); } - dev_priv->psr.active = false; + intel_dp->psr.active = false; } static void intel_psr_disable_locked(struct intel_dp *intel_dp) @@ -1085,21 +1070,21 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) i915_reg_t psr_status; u32 psr_status_mask; - lockdep_assert_held(&dev_priv->psr.lock); + lockdep_assert_held(&intel_dp->psr.lock); - if (!dev_priv->psr.enabled) + if (!intel_dp->psr.enabled) return; drm_dbg_kms(&dev_priv->drm, "Disabling PSR%s\n", - dev_priv->psr.psr2_enabled ? "2" : "1"); + intel_dp->psr.psr2_enabled ? "2" : "1"); - intel_psr_exit(dev_priv); + intel_psr_exit(intel_dp); - if (dev_priv->psr.psr2_enabled) { - psr_status = EDP_PSR2_STATUS(dev_priv->psr.transcoder); + if (intel_dp->psr.psr2_enabled) { + psr_status = EDP_PSR2_STATUS(intel_dp->psr.transcoder); psr_status_mask = EDP_PSR2_STATUS_STATE_MASK; } else { - psr_status = EDP_PSR_STATUS(dev_priv->psr.transcoder); + psr_status = EDP_PSR_STATUS(intel_dp->psr.transcoder); psr_status_mask = EDP_PSR_STATUS_STATE_MASK; } @@ -1109,7 +1094,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) drm_err(&dev_priv->drm, "Timed out waiting PSR idle state\n"); /* WA 1408330847 */ - if (dev_priv->psr.psr2_sel_fetch_enabled && + if (intel_dp->psr.psr2_sel_fetch_enabled && (IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_A0) || IS_RKL_REVID(dev_priv, RKL_REVID_A0, RKL_REVID_A0))) intel_de_rmw(dev_priv, CHICKEN_PAR1_1, @@ -1118,10 +1103,10 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) /* Disable PSR on Sink */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); - if (dev_priv->psr.psr2_enabled) + if (intel_dp->psr.psr2_enabled) drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, 0); - dev_priv->psr.enabled = false; + intel_dp->psr.enabled = false; } /** @@ -1139,20 +1124,22 @@ void intel_psr_disable(struct intel_dp *intel_dp, if (!old_crtc_state->has_psr) return; - if (drm_WARN_ON(&dev_priv->drm, !CAN_PSR(dev_priv))) + if (drm_WARN_ON(&dev_priv->drm, !CAN_PSR(intel_dp))) return; - mutex_lock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); intel_psr_disable_locked(intel_dp); - mutex_unlock(&dev_priv->psr.lock); - cancel_work_sync(&dev_priv->psr.work); - cancel_delayed_work_sync(&dev_priv->psr.dc3co_work); + mutex_unlock(&intel_dp->psr.lock); + cancel_work_sync(&intel_dp->psr.work); + cancel_delayed_work_sync(&intel_dp->psr.dc3co_work); } -static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv) +static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + if (IS_TIGERLAKE(dev_priv)) /* * Writes to CURSURFLIVE in TGL are causing IOMMU errors and @@ -1166,7 +1153,7 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv) * So using this workaround until this issue is root caused * and a better fix is found. */ - intel_psr_exit(dev_priv); + intel_psr_exit(intel_dp); else if (INTEL_GEN(dev_priv) >= 9) /* * Display WA #0884: skl+ @@ -1177,13 +1164,13 @@ static void psr_force_hw_tracking_exit(struct drm_i915_private *dev_priv) * but it makes more sense write to the current active * pipe. */ - intel_de_write(dev_priv, CURSURFLIVE(dev_priv->psr.pipe), 0); + intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); else /* * A write to CURSURFLIVE do not cause HW tracking to exit PSR * on older gens so doing the manual exit instead. */ - intel_psr_exit(dev_priv); + intel_psr_exit(intel_dp); } void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, @@ -1231,16 +1218,24 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, void intel_psr2_program_trans_man_trk_ctl(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 i915_psr *psr = &dev_priv->psr; + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + struct intel_encoder *encoder; if (!HAS_PSR2_SEL_FETCH(dev_priv) || !crtc_state->enable_psr2_sel_fetch) return; - intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(psr->transcoder), - crtc_state->psr2_man_track_ctl); + for_each_intel_encoder_mask_can_psr(&dev_priv->drm, encoder, + crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (!intel_dp->psr.enabled) + continue; + + intel_de_write(dev_priv, + PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), + crtc_state->psr2_man_track_ctl); + } } static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, @@ -1435,13 +1430,13 @@ void intel_psr_update(struct intel_dp *intel_dp, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - struct i915_psr *psr = &dev_priv->psr; + struct intel_psr *psr = &intel_dp->psr; bool enable, psr2_enable; - if (!CAN_PSR(dev_priv) || READ_ONCE(psr->dp) != intel_dp) + if (!CAN_PSR(intel_dp)) return; - mutex_lock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); enable = crtc_state->has_psr; psr2_enable = crtc_state->has_psr2; @@ -1449,15 +1444,15 @@ void intel_psr_update(struct intel_dp *intel_dp, if (enable == psr->enabled && psr2_enable == psr->psr2_enabled) { /* Force a PSR exit when enabling CRC to avoid CRC timeouts */ if (crtc_state->crc_enabled && psr->enabled) - psr_force_hw_tracking_exit(dev_priv); + psr_force_hw_tracking_exit(intel_dp); else if (INTEL_GEN(dev_priv) < 9 && psr->enabled) { /* * Activate PSR again after a force exit when enabling * CRC in older gens */ - if (!dev_priv->psr.active && - !dev_priv->psr.busy_frontbuffer_bits) - schedule_work(&dev_priv->psr.work); + if (!intel_dp->psr.active && + !intel_dp->psr.busy_frontbuffer_bits) + schedule_work(&intel_dp->psr.work); } goto unlock; @@ -1467,34 +1462,23 @@ void intel_psr_update(struct intel_dp *intel_dp, intel_psr_disable_locked(intel_dp); if (enable) - intel_psr_enable_locked(dev_priv, crtc_state, conn_state); + intel_psr_enable_locked(intel_dp, crtc_state, conn_state); unlock: - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); } /** - * intel_psr_wait_for_idle - wait for PSR1 to idle - * @new_crtc_state: new CRTC state + * psr_wait_for_idle - wait for PSR1 to idle + * @intel_dp: Intel DP * @out_value: PSR status in case of failure * - * This function is expected to be called from pipe_update_start() where it is - * not expected to race with PSR enable or disable. - * * Returns: 0 on success or -ETIMEOUT if PSR status does not idle. + * */ -int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state, - u32 *out_value) +static int psr_wait_for_idle(struct intel_dp *intel_dp, u32 *out_value) { - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (!dev_priv->psr.enabled || !new_crtc_state->has_psr) - return 0; - - /* FIXME: Update this for PSR2 if we need to wait for idle */ - if (READ_ONCE(dev_priv->psr.psr2_enabled)) - return 0; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); /* * From bspec: Panel Self Refresh (BDW+) @@ -1502,32 +1486,68 @@ int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state, * exit training time + 1.5 ms of aux channel handshake. 50 ms is * defensive enough to cover everything. */ - return __intel_wait_for_register(&dev_priv->uncore, - EDP_PSR_STATUS(dev_priv->psr.transcoder), + EDP_PSR_STATUS(intel_dp->psr.transcoder), EDP_PSR_STATUS_STATE_MASK, EDP_PSR_STATUS_STATE_IDLE, 2, 50, out_value); } -static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv) +/** + * intel_psr_wait_for_idle - wait for PSR1 to idle + * @new_crtc_state: new CRTC state + * + * This function is expected to be called from pipe_update_start() where it is + * not expected to race with PSR enable or disable. + */ +void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev); + struct intel_encoder *encoder; + + if (!new_crtc_state->has_psr) + return; + + for_each_intel_encoder_mask_can_psr(&dev_priv->drm, encoder, + new_crtc_state->uapi.encoder_mask) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + u32 psr_status; + + mutex_lock(&intel_dp->psr.lock); + if (!intel_dp->psr.enabled || + (intel_dp->psr.enabled && intel_dp->psr.psr2_enabled)) { + mutex_unlock(&intel_dp->psr.lock); + continue; + } + + /* when the PSR1 is enabled */ + if (psr_wait_for_idle(intel_dp, &psr_status)) + drm_err(&dev_priv->drm, + "PSR idle timed out 0x%x, atomic update may fail\n", + psr_status); + mutex_unlock(&intel_dp->psr.lock); + } +} + +static bool __psr_wait_for_idle_locked(struct intel_dp *intel_dp) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); i915_reg_t reg; u32 mask; int err; - if (!dev_priv->psr.enabled) + if (!intel_dp->psr.enabled) return false; - if (dev_priv->psr.psr2_enabled) { - reg = EDP_PSR2_STATUS(dev_priv->psr.transcoder); + if (intel_dp->psr.psr2_enabled) { + reg = EDP_PSR2_STATUS(intel_dp->psr.transcoder); mask = EDP_PSR2_STATUS_STATE_MASK; } else { - reg = EDP_PSR_STATUS(dev_priv->psr.transcoder); + reg = EDP_PSR_STATUS(intel_dp->psr.transcoder); mask = EDP_PSR_STATUS_STATE_MASK; } - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); err = intel_de_wait_for_clear(dev_priv, reg, mask, 50); if (err) @@ -1535,8 +1555,8 @@ static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv) "Timed out waiting for PSR Idle for re-enable\n"); /* After the unlocked wait, verify that PSR is still wanted! */ - mutex_lock(&dev_priv->psr.lock); - return err == 0 && dev_priv->psr.enabled; + mutex_lock(&intel_dp->psr.lock); + return err == 0 && intel_dp->psr.enabled; } static int intel_psr_fastset_force(struct drm_i915_private *dev_priv) @@ -1602,8 +1622,9 @@ static int intel_psr_fastset_force(struct drm_i915_private *dev_priv) return err; } -int intel_psr_debug_set(struct drm_i915_private *dev_priv, u64 val) +int intel_psr_debug_set(struct intel_dp *intel_dp, u64 val) { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const u32 mode = val & I915_PSR_DEBUG_MODE_MASK; u32 old_mode; int ret; @@ -1614,21 +1635,21 @@ int intel_psr_debug_set(struct drm_i915_private *dev_priv, u64 val) return -EINVAL; } - ret = mutex_lock_interruptible(&dev_priv->psr.lock); + ret = mutex_lock_interruptible(&intel_dp->psr.lock); if (ret) return ret; - old_mode = dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK; - dev_priv->psr.debug = val; + old_mode = intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK; + intel_dp->psr.debug = val; /* * Do it right away if it's already enabled, otherwise it will be done * when enabling the source. */ - if (dev_priv->psr.enabled) - psr_irq_control(dev_priv); + if (intel_dp->psr.enabled) + psr_irq_control(intel_dp); - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); if (old_mode != mode) ret = intel_psr_fastset_force(dev_priv); @@ -1636,28 +1657,28 @@ int intel_psr_debug_set(struct drm_i915_private *dev_priv, u64 val) return ret; } -static void intel_psr_handle_irq(struct drm_i915_private *dev_priv) +static void intel_psr_handle_irq(struct intel_dp *intel_dp) { - struct i915_psr *psr = &dev_priv->psr; + struct intel_psr *psr = &intel_dp->psr; - intel_psr_disable_locked(psr->dp); + intel_psr_disable_locked(intel_dp); psr->sink_not_reliable = true; /* let's make sure that sink is awaken */ - drm_dp_dpcd_writeb(&psr->dp->aux, DP_SET_POWER, DP_SET_POWER_D0); + drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); } static void intel_psr_work(struct work_struct *work) { - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), psr.work); + struct intel_dp *intel_dp = + container_of(work, typeof(*intel_dp), psr.work); - mutex_lock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); - if (!dev_priv->psr.enabled) + if (!intel_dp->psr.enabled) goto unlock; - if (READ_ONCE(dev_priv->psr.irq_aux_error)) - intel_psr_handle_irq(dev_priv); + if (READ_ONCE(intel_dp->psr.irq_aux_error)) + intel_psr_handle_irq(intel_dp); /* * We have to make sure PSR is ready for re-enable @@ -1665,7 +1686,7 @@ static void intel_psr_work(struct work_struct *work) * PSR might take some time to get fully disabled * and be ready for re-enable. */ - if (!__psr_wait_for_idle_locked(dev_priv)) + if (!__psr_wait_for_idle_locked(intel_dp)) goto unlock; /* @@ -1673,12 +1694,12 @@ static void intel_psr_work(struct work_struct *work) * recheck. Since psr_flush first clears this and then reschedules we * won't ever miss a flush when bailing out here. */ - if (dev_priv->psr.busy_frontbuffer_bits || dev_priv->psr.active) + if (intel_dp->psr.busy_frontbuffer_bits || intel_dp->psr.active) goto unlock; - intel_psr_activate(dev_priv->psr.dp); + intel_psr_activate(intel_dp); unlock: - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); } /** @@ -1697,27 +1718,31 @@ static void intel_psr_work(struct work_struct *work) void intel_psr_invalidate(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin) { - if (!CAN_PSR(dev_priv)) - return; + struct intel_encoder *encoder; if (origin == ORIGIN_FLIP) return; - mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; - } + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + unsigned int pipe_frontbuffer_bits = frontbuffer_bits; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(dev_priv->psr.pipe); - dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits; + mutex_lock(&intel_dp->psr.lock); + if (!intel_dp->psr.enabled) { + mutex_unlock(&intel_dp->psr.lock); + continue; + } - if (frontbuffer_bits) - intel_psr_exit(dev_priv); + pipe_frontbuffer_bits &= + INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe); + intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits; - mutex_unlock(&dev_priv->psr.lock); -} + if (pipe_frontbuffer_bits) + intel_psr_exit(intel_dp); + mutex_unlock(&intel_dp->psr.lock); + } +} /* * When we will be completely rely on PSR2 S/W tracking in future, * intel_psr_flush() will invalidate and flush the PSR for ORIGIN_FLIP @@ -1725,15 +1750,15 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, * accordingly in future. */ static void -tgl_dc3co_flush(struct drm_i915_private *dev_priv, - unsigned int frontbuffer_bits, enum fb_op_origin origin) +tgl_dc3co_flush(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, + enum fb_op_origin origin) { - mutex_lock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); - if (!dev_priv->psr.dc3co_enabled) + if (!intel_dp->psr.dc3co_enabled) goto unlock; - if (!dev_priv->psr.psr2_enabled || !dev_priv->psr.active) + if (!intel_dp->psr.psr2_enabled || !intel_dp->psr.active) goto unlock; /* @@ -1741,15 +1766,15 @@ tgl_dc3co_flush(struct drm_i915_private *dev_priv, * when delayed work schedules that means display has been idle. */ if (!(frontbuffer_bits & - INTEL_FRONTBUFFER_ALL_MASK(dev_priv->psr.pipe))) + INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe))) goto unlock; - tgl_psr2_enable_dc3co(dev_priv); - mod_delayed_work(system_wq, &dev_priv->psr.dc3co_work, - dev_priv->psr.dc3co_exit_delay); + tgl_psr2_enable_dc3co(intel_dp); + mod_delayed_work(system_wq, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); unlock: - mutex_unlock(&dev_priv->psr.lock); + mutex_unlock(&intel_dp->psr.lock); } /** @@ -1768,47 +1793,73 @@ tgl_dc3co_flush(struct drm_i915_private *dev_priv, void intel_psr_flush(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin) { - if (!CAN_PSR(dev_priv)) - return; + struct intel_encoder *encoder; - if (origin == ORIGIN_FLIP) { - tgl_dc3co_flush(dev_priv, frontbuffer_bits, origin); - return; - } + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + unsigned int pipe_frontbuffer_bits = frontbuffer_bits; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - mutex_lock(&dev_priv->psr.lock); - if (!dev_priv->psr.enabled) { - mutex_unlock(&dev_priv->psr.lock); - return; - } + if (origin == ORIGIN_FLIP) { + tgl_dc3co_flush(intel_dp, frontbuffer_bits, origin); + continue; + } + + mutex_lock(&intel_dp->psr.lock); + if (!intel_dp->psr.enabled) { + mutex_unlock(&intel_dp->psr.lock); + continue; + } - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(dev_priv->psr.pipe); - dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; + pipe_frontbuffer_bits &= + INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe); + intel_dp->psr.busy_frontbuffer_bits &= ~pipe_frontbuffer_bits; - /* By definition flush = invalidate + flush */ - if (frontbuffer_bits) - psr_force_hw_tracking_exit(dev_priv); + /* By definition flush = invalidate + flush */ + if (pipe_frontbuffer_bits) + psr_force_hw_tracking_exit(intel_dp); - if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) - schedule_work(&dev_priv->psr.work); - mutex_unlock(&dev_priv->psr.lock); + if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits) + schedule_work(&intel_dp->psr.work); + mutex_unlock(&intel_dp->psr.lock); + } } /** * intel_psr_init - Init basic PSR work and mutex. - * @dev_priv: i915 device private + * @intel_dp: Intel DP * - * This function is called only once at driver load to initialize basic - * PSR stuff. + * This function is called after the initializing connector. + * (the initializing of connector treats the handling of connector capabilities) + * And it initializes basic PSR stuff for each DP Encoder. */ -void intel_psr_init(struct drm_i915_private *dev_priv) +void intel_psr_init(struct intel_dp *intel_dp) { + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + if (!HAS_PSR(dev_priv)) return; - if (!dev_priv->psr.sink_support) + if (!intel_dp->psr.sink_support) return; + /* + * HSW spec explicitly says PSR is tied to port A. + * BDW+ platforms have a instance of PSR registers per transcoder but + * BDW, GEN9 and GEN11 are not validated by HW team in other transcoder + * than eDP one. + * For now it only supports one instance of PSR for BDW, GEN9 and GEN11. + * So lets keep it hardcoded to PORT_A for BDW, GEN9 and GEN11. + * But GEN12 supports a instance of PSR registers per transcoder. + */ + if (INTEL_GEN(dev_priv) < 12 && dig_port->base.port != PORT_A) { + drm_dbg_kms(&dev_priv->drm, + "PSR condition failed: Port not supported\n"); + return; + } + + intel_dp->psr.source_support = true; + if (IS_HASWELL(dev_priv)) /* * HSW don't have PSR registers on the same space as transcoder @@ -1824,14 +1875,14 @@ void intel_psr_init(struct drm_i915_private *dev_priv) /* Set link_standby x link_off defaults */ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) /* HSW and BDW require workarounds that we don't implement. */ - dev_priv->psr.link_standby = false; + intel_dp->psr.link_standby = false; else if (INTEL_GEN(dev_priv) < 12) /* For new platforms up to TGL let's respect VBT back again */ - dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link; + intel_dp->psr.link_standby = dev_priv->vbt.psr.full_link; - INIT_WORK(&dev_priv->psr.work, intel_psr_work); - INIT_DELAYED_WORK(&dev_priv->psr.dc3co_work, tgl_dc3co_disable_work); - mutex_init(&dev_priv->psr.lock); + INIT_WORK(&intel_dp->psr.work, intel_psr_work); + INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work); + mutex_init(&intel_dp->psr.lock); } static int psr_get_status_and_error_status(struct intel_dp *intel_dp, @@ -1857,7 +1908,7 @@ static void psr_alpm_check(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct drm_dp_aux *aux = &intel_dp->aux; - struct i915_psr *psr = &dev_priv->psr; + struct intel_psr *psr = &intel_dp->psr; u8 val; int r; @@ -1884,7 +1935,7 @@ static void psr_alpm_check(struct intel_dp *intel_dp) static void psr_capability_changed_check(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - struct i915_psr *psr = &dev_priv->psr; + struct intel_psr *psr = &intel_dp->psr; u8 val; int r; @@ -1908,18 +1959,18 @@ static void psr_capability_changed_check(struct intel_dp *intel_dp) void intel_psr_short_pulse(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - struct i915_psr *psr = &dev_priv->psr; + struct intel_psr *psr = &intel_dp->psr; u8 status, error_status; const u8 errors = DP_PSR_RFB_STORAGE_ERROR | DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | DP_PSR_LINK_CRC_ERROR; - if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp)) + if (!CAN_PSR(intel_dp) || !intel_dp_is_edp(intel_dp)) return; mutex_lock(&psr->lock); - if (!psr->enabled || psr->dp != intel_dp) + if (!psr->enabled) goto exit; if (psr_get_status_and_error_status(intel_dp, &status, &error_status)) { @@ -1962,15 +2013,14 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) bool intel_psr_enabled(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); bool ret; - if (!CAN_PSR(dev_priv) || !intel_dp_is_edp(intel_dp)) + if (!CAN_PSR(intel_dp) || !intel_dp_is_edp(intel_dp)) return false; - mutex_lock(&dev_priv->psr.lock); - ret = (dev_priv->psr.dp == intel_dp && dev_priv->psr.enabled); - mutex_unlock(&dev_priv->psr.lock); + mutex_lock(&intel_dp->psr.lock); + ret = intel_dp->psr.enabled; + mutex_unlock(&intel_dp->psr.lock); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 0a517978e8af1..0491a49ffd507 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -18,7 +18,6 @@ struct intel_atomic_state; struct intel_plane_state; struct intel_plane; -#define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, @@ -28,20 +27,19 @@ void intel_psr_disable(struct intel_dp *intel_dp, void intel_psr_update(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); -int intel_psr_debug_set(struct drm_i915_private *dev_priv, u64 value); +int intel_psr_debug_set(struct intel_dp *intel_dp, u64 value); void intel_psr_invalidate(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin); void intel_psr_flush(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin); -void intel_psr_init(struct drm_i915_private *dev_priv); +void intel_psr_init(struct intel_dp *intel_dp); void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); -void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); +void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); -int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state, - u32 *out_value); +void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); bool intel_psr_enabled(struct intel_dp *intel_dp); int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 402030251c64a..26025251b038a 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -96,7 +96,6 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); DEFINE_WAIT(wait); - u32 psr_status; if (new_crtc_state->uapi.async_flip) return; @@ -122,10 +121,7 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) * VBL interrupts will start the PSR exit and prevent a PSR * re-entry as well. */ - if (intel_psr_wait_for_idle(new_crtc_state, &psr_status)) - drm_err(&dev_priv->drm, - "PSR idle timed out 0x%x, atomic update may fail\n", - psr_status); + intel_psr_wait_for_idle(new_crtc_state); local_irq_disable(); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 60c52588d552a..017208ff8df41 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -475,42 +475,6 @@ struct i915_drrs { enum drrs_support_type type; }; -struct i915_psr { - struct mutex lock; - -#define I915_PSR_DEBUG_MODE_MASK 0x0f -#define I915_PSR_DEBUG_DEFAULT 0x00 -#define I915_PSR_DEBUG_DISABLE 0x01 -#define I915_PSR_DEBUG_ENABLE 0x02 -#define I915_PSR_DEBUG_FORCE_PSR1 0x03 -#define I915_PSR_DEBUG_IRQ 0x10 - - u32 debug; - bool sink_support; - bool enabled; - struct intel_dp *dp; - enum pipe pipe; - enum transcoder transcoder; - bool active; - struct work_struct work; - unsigned busy_frontbuffer_bits; - bool sink_psr2_support; - bool link_standby; - bool colorimetry_support; - bool psr2_enabled; - bool psr2_sel_fetch_enabled; - u8 sink_sync_latency; - ktime_t last_entry_attempt; - ktime_t last_exit; - bool sink_not_reliable; - bool irq_aux_error; - u16 su_x_granularity; - bool dc3co_enabled; - u32 dc3co_exit_delay; - struct delayed_work dc3co_work; - struct drm_dp_vsc_sdp vsc; -}; - #define QUIRK_LVDS_SSC_DISABLE (1<<1) #define QUIRK_INVERT_BRIGHTNESS (1<<2) #define QUIRK_BACKLIGHT_PRESENT (1<<3) @@ -1038,8 +1002,6 @@ struct drm_i915_private { struct i915_power_domains power_domains; - struct i915_psr psr; - struct i915_gpu_error gpu_error; struct drm_i915_gem_object *vlv_pctx; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9d47da8ec86d8..374a65d053914 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2094,10 +2094,19 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, ivb_err_int_handler(dev_priv); if (de_iir & DE_EDP_PSR_INT_HSW) { - u32 psr_iir = intel_uncore_read(&dev_priv->uncore, EDP_PSR_IIR); + struct intel_encoder *encoder; - intel_psr_irq_handler(dev_priv, psr_iir); - intel_uncore_write(&dev_priv->uncore, EDP_PSR_IIR, psr_iir); + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + u32 psr_iir = intel_uncore_read(&dev_priv->uncore, + EDP_PSR_IIR); + + intel_psr_irq_handler(intel_dp, psr_iir); + intel_uncore_write(&dev_priv->uncore, + EDP_PSR_IIR, psr_iir); + break; + } } if (de_iir & DE_AUX_CHANNEL_A_IVB) @@ -2310,21 +2319,30 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) } if (iir & GEN8_DE_EDP_PSR) { + struct intel_encoder *encoder; u32 psr_iir; i915_reg_t iir_reg; - if (INTEL_GEN(dev_priv) >= 12) - iir_reg = TRANS_PSR_IIR(dev_priv->psr.transcoder); - else - iir_reg = EDP_PSR_IIR; + for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg); - intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir); + if (INTEL_GEN(dev_priv) >= 12) + iir_reg = TRANS_PSR_IIR(intel_dp->psr.transcoder); + else + iir_reg = EDP_PSR_IIR; - if (psr_iir) - found = true; + psr_iir = intel_uncore_read(&dev_priv->uncore, iir_reg); + intel_uncore_write(&dev_priv->uncore, iir_reg, psr_iir); - intel_psr_irq_handler(dev_priv, psr_iir); + if (psr_iir) + found = true; + + intel_psr_irq_handler(intel_dp, psr_iir); + + /* prior GEN12 only have one EDP PSR */ + if (INTEL_GEN(dev_priv) < 12) + break; + } } if (!found) From 759cd2a6d1bf1a129e7705992198ff8bd1d2fed4 Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Thu, 4 Feb 2021 15:40:15 +0200 Subject: [PATCH 036/142] drm/i915/display: Support Multiple Transcoders' PSR status on debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to support the PSR state of each transcoder, it adds i915_psr_status to sub-directory of each transcoder. v2: Change using of Symbolic permissions 'S_IRUGO' to using of octal permissions '0444' v5: Addressed JJani Nikula's review comments - Remove checking of Gen12 for i915_psr_status. - Add check of HAS_PSR() - Remove meaningless check routine. Signed-off-by: Gwan-gyeong Mun Cc: José Roberto de Souza Cc: Jani Nikula Cc: Anshuman Gupta Reviewed-by: Anshuman Gupta Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210204134015.419036-2-gwan-gyeong.mun@intel.com --- .../gpu/drm/i915/display/intel_display_debugfs.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index b1bda1f5ef16b..d6e4a9237bda2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -2211,6 +2211,16 @@ static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data) } DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); +static int i915_psr_status_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct intel_dp *intel_dp = + intel_attached_dp(to_intel_connector(connector)); + + return intel_psr_status(m, intel_dp); +} +DEFINE_SHOW_ATTRIBUTE(i915_psr_status); + #define LPSP_CAPABLE(COND) (COND ? seq_puts(m, "LPSP: capable\n") : \ seq_puts(m, "LPSP: incapable\n")) @@ -2386,6 +2396,12 @@ int intel_connector_debugfs_add(struct drm_connector *connector) connector, &i915_psr_sink_status_fops); } + if (HAS_PSR(dev_priv) && + connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + debugfs_create_file("i915_psr_status", 0444, root, + connector, &i915_psr_status_fops); + } + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { From c5c874a8352918555c79b8af5a25f7e543c84844 Mon Sep 17 00:00:00 2001 From: Edmund Dea Date: Thu, 4 Feb 2021 09:58:30 -0800 Subject: [PATCH 037/142] drm/i915/display: Remove PSR2 on JSL and EHL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While JSL and EHL eDP transcoder supports PSR2, the phy of this platforms only supports eDP 1.3, so removing PSR2 support as this feature was added in eDP 1.4. Signed-off-by: Edmund Dea Signed-off-by: José Roberto de Souza Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210204175830.97857-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index bf48eb4e1a847..28423356d53b5 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -717,6 +717,12 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, if (!intel_dp->psr.sink_psr2_support) return false; + /* JSL and EHL only supports eDP 1.3 */ + if (IS_JSL_EHL(dev_priv)) { + drm_dbg_kms(&dev_priv->drm, "PSR2 not supported by phy\n"); + return false; + } + if (!transcoder_has_psr2(dev_priv, crtc_state->cpu_transcoder)) { drm_dbg_kms(&dev_priv->drm, "PSR2 not supported in transcoder %s\n", From 64218f91ab49a8aa1d0e5793cc9e29f03a93639b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 4 Feb 2021 07:33:57 -0800 Subject: [PATCH 038/142] drm/i915: Make psr_safest_params and enable_psr2_sel_fetch parameters read only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By mistake those 2 parameters were defined as read and write in the .h file while in the .c file it is read only. The intention here was to be read only to avoid the need of additional handling. Cc: Gwan-gyeong Mun Cc: Petri Latvala Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210204153357.39681-1-jose.souza@intel.com --- drivers/gpu/drm/i915/i915_params.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index 330c03e2b4f70..21a7a5f686ec6 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -53,8 +53,8 @@ struct drm_printer; param(int, enable_dc, -1, 0400) \ param(int, enable_fbc, -1, 0600) \ param(int, enable_psr, -1, 0600) \ - param(bool, psr_safest_params, false, 0600) \ - param(bool, enable_psr2_sel_fetch, false, 0600) \ + param(bool, psr_safest_params, false, 0400) \ + param(bool, enable_psr2_sel_fetch, false, 0400) \ param(int, disable_power_well, -1, 0400) \ param(int, enable_ips, 1, 0600) \ param(int, invert_brightness, 0, 0600) \ From 99092a976c8c3632bbdc021a149970b1c069b74b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Feb 2021 21:43:18 +0200 Subject: [PATCH 039/142] drm/i915: refactor ddi translations into a separate file (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville suggested this, these tables are probably better being standalone. This fixes up the cnl/bxt interfaces to be like the others, the intel one I left alone since it has a few extra entrypoints. v2: add back missing rocketlake bits. Reviewed-by: Ville Syrjälä Signed-off-by: Dave Airlie [Jani: made some functions static] Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/def9eed2581d71863ccdf35f323b525facc2482c.1612467466.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 1417 +---------------- .../drm/i915/display/intel_ddi_buf_trans.c | 1394 ++++++++++++++++ .../drm/i915/display/intel_ddi_buf_trans.h | 100 ++ 4 files changed, 1507 insertions(+), 1405 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c create mode 100644 drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ffd3a15f0ca1e..0e98cf2eec309 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -241,6 +241,7 @@ i915-y += \ display/icl_dsi.o \ display/intel_crt.o \ display/intel_ddi.o \ + display/intel_ddi_buf_trans.o \ display/intel_dp.o \ display/intel_dp_aux.o \ display/intel_dp_aux_backlight.o \ diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 5bc5033a2deaf..e2b82e0557e7c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -33,6 +33,7 @@ #include "intel_combo_phy.h" #include "intel_connector.h" #include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_dp.h" #include "intel_dp_mst.h" @@ -53,12 +54,6 @@ #include "intel_vdsc.h" #include "intel_vrr.h" -struct ddi_buf_trans { - u32 trans1; /* balance leg enable, de-emph level */ - u32 trans2; /* vref sel, vswing */ - u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ -}; - static const u8 index_to_dp_signal_levels[] = { [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0, [1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1, @@ -72,1389 +67,15 @@ static const u8 index_to_dp_signal_levels[] = { [9] = DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0, }; -/* HDMI/DVI modes ignore everything but the last 2 items. So we share - * them for both DP and FDI transports, allowing those ports to - * automatically adapt to HDMI connections as well - */ -static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0006000E, 0x0 }, - { 0x00D75FFF, 0x0005000A, 0x0 }, - { 0x00C30FFF, 0x00040006, 0x0 }, - { 0x80AAAFFF, 0x000B0000, 0x0 }, - { 0x00FFFFFF, 0x0005000A, 0x0 }, - { 0x00D75FFF, 0x000C0004, 0x0 }, - { 0x80C30FFF, 0x000B0000, 0x0 }, - { 0x00FFFFFF, 0x00040006, 0x0 }, - { 0x80D75FFF, 0x000B0000, 0x0 }, -}; - -static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0007000E, 0x0 }, - { 0x00D75FFF, 0x000F000A, 0x0 }, - { 0x00C30FFF, 0x00060006, 0x0 }, - { 0x00AAAFFF, 0x001E0000, 0x0 }, - { 0x00FFFFFF, 0x000F000A, 0x0 }, - { 0x00D75FFF, 0x00160004, 0x0 }, - { 0x00C30FFF, 0x001E0000, 0x0 }, - { 0x00FFFFFF, 0x00060006, 0x0 }, - { 0x00D75FFF, 0x001E0000, 0x0 }, -}; - -static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { - /* Idx NT mV d T mV d db */ - { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ - { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ - { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ - { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ - { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ - { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ - { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ - { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ - { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ - { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ - { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ - { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ -}; - -static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { - { 0x00FFFFFF, 0x00000012, 0x0 }, - { 0x00EBAFFF, 0x00020011, 0x0 }, - { 0x00C71FFF, 0x0006000F, 0x0 }, - { 0x00AAAFFF, 0x000E000A, 0x0 }, - { 0x00FFFFFF, 0x00020011, 0x0 }, - { 0x00DB6FFF, 0x0005000F, 0x0 }, - { 0x00BEEFFF, 0x000A000C, 0x0 }, - { 0x00FFFFFF, 0x0005000F, 0x0 }, - { 0x00DB6FFF, 0x000A000C, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0007000E, 0x0 }, - { 0x00D75FFF, 0x000E000A, 0x0 }, - { 0x00BEFFFF, 0x00140006, 0x0 }, - { 0x80B2CFFF, 0x001B0002, 0x0 }, - { 0x00FFFFFF, 0x000E000A, 0x0 }, - { 0x00DB6FFF, 0x00160005, 0x0 }, - { 0x80C71FFF, 0x001A0002, 0x0 }, - { 0x00F7DFFF, 0x00180004, 0x0 }, - { 0x80D75FFF, 0x001B0002, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0001000E, 0x0 }, - { 0x00D75FFF, 0x0004000A, 0x0 }, - { 0x00C30FFF, 0x00070006, 0x0 }, - { 0x00AAAFFF, 0x000C0000, 0x0 }, - { 0x00FFFFFF, 0x0004000A, 0x0 }, - { 0x00D75FFF, 0x00090004, 0x0 }, - { 0x00C30FFF, 0x000C0000, 0x0 }, - { 0x00FFFFFF, 0x00070006, 0x0 }, - { 0x00D75FFF, 0x000C0000, 0x0 }, -}; - -static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { - /* Idx NT mV d T mV df db */ - { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ - { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ - { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ - { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ - { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ - { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ - { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ - { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ - { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ - { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ -}; - -/* Skylake H and S */ -static const struct ddi_buf_trans skl_ddi_translations_dp[] = { - { 0x00002016, 0x000000A0, 0x0 }, - { 0x00005012, 0x0000009B, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x00002016, 0x0000009B, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x000000DF, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Skylake U */ -static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { - { 0x0000201B, 0x000000A2, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x1 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x0000201B, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x00000088, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Skylake Y */ -static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { - { 0x00000018, 0x000000A2, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x80009010, 0x000000C0, 0x3 }, - { 0x00000018, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00000018, 0x00000088, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* Kabylake H and S */ -static const struct ddi_buf_trans kbl_ddi_translations_dp[] = { - { 0x00002016, 0x000000A0, 0x0 }, - { 0x00005012, 0x0000009B, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x80009010, 0x000000C0, 0x1 }, - { 0x00002016, 0x0000009B, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000C0, 0x1 }, - { 0x00002016, 0x00000097, 0x0 }, - { 0x80005012, 0x000000C0, 0x1 }, -}; - -/* Kabylake U */ -static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = { - { 0x0000201B, 0x000000A1, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x80009010, 0x000000C0, 0x3 }, - { 0x0000201B, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00002016, 0x0000004F, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* Kabylake Y */ -static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = { - { 0x00001017, 0x000000A1, 0x0 }, - { 0x00005012, 0x00000088, 0x0 }, - { 0x80007011, 0x000000CD, 0x3 }, - { 0x8000800F, 0x000000C0, 0x3 }, - { 0x00001017, 0x0000009D, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, - { 0x80007011, 0x000000C0, 0x3 }, - { 0x00001017, 0x0000004C, 0x0 }, - { 0x80005012, 0x000000C0, 0x3 }, -}; - -/* - * Skylake/Kabylake H and S - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000A9, 0x0 }, - { 0x00007011, 0x000000A2, 0x0 }, - { 0x00009010, 0x0000009C, 0x0 }, - { 0x00000018, 0x000000A9, 0x0 }, - { 0x00006013, 0x000000A2, 0x0 }, - { 0x00007011, 0x000000A6, 0x0 }, - { 0x00000018, 0x000000AB, 0x0 }, - { 0x00007013, 0x0000009F, 0x0 }, - { 0x00000018, 0x000000DF, 0x0 }, -}; - -/* - * Skylake/Kabylake U - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000A9, 0x0 }, - { 0x00007011, 0x000000A2, 0x0 }, - { 0x00009010, 0x0000009C, 0x0 }, - { 0x00000018, 0x000000A9, 0x0 }, - { 0x00006013, 0x000000A2, 0x0 }, - { 0x00007011, 0x000000A6, 0x0 }, - { 0x00002016, 0x000000AB, 0x0 }, - { 0x00005013, 0x0000009F, 0x0 }, - { 0x00000018, 0x000000DF, 0x0 }, -}; - -/* - * Skylake/Kabylake Y - * eDP 1.4 low vswing translation parameters - */ -static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = { - { 0x00000018, 0x000000A8, 0x0 }, - { 0x00004013, 0x000000AB, 0x0 }, - { 0x00007011, 0x000000A4, 0x0 }, - { 0x00009010, 0x000000DF, 0x0 }, - { 0x00000018, 0x000000AA, 0x0 }, - { 0x00006013, 0x000000A4, 0x0 }, - { 0x00007011, 0x0000009D, 0x0 }, - { 0x00000018, 0x000000A0, 0x0 }, - { 0x00006012, 0x000000DF, 0x0 }, - { 0x00000018, 0x0000008A, 0x0 }, -}; - -/* Skylake/Kabylake U, H and S */ -static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000AC, 0x0 }, - { 0x00005012, 0x0000009D, 0x0 }, - { 0x00007011, 0x00000088, 0x0 }, - { 0x00000018, 0x000000A1, 0x0 }, - { 0x00000018, 0x00000098, 0x0 }, - { 0x00004013, 0x00000088, 0x0 }, - { 0x80006012, 0x000000CD, 0x1 }, - { 0x00000018, 0x000000DF, 0x0 }, - { 0x80003015, 0x000000CD, 0x1 }, /* Default */ - { 0x80003015, 0x000000C0, 0x1 }, - { 0x80000018, 0x000000C0, 0x1 }, -}; - -/* Skylake/Kabylake Y */ -static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000A1, 0x0 }, - { 0x00005012, 0x000000DF, 0x0 }, - { 0x80007011, 0x000000CB, 0x3 }, - { 0x00000018, 0x000000A4, 0x0 }, - { 0x00000018, 0x0000009D, 0x0 }, - { 0x00004013, 0x00000080, 0x0 }, - { 0x80006013, 0x000000C0, 0x3 }, - { 0x00000018, 0x0000008A, 0x0 }, - { 0x80003015, 0x000000C0, 0x3 }, /* Default */ - { 0x80003015, 0x000000C0, 0x3 }, - { 0x80000018, 0x000000C0, 0x3 }, -}; - -struct bxt_ddi_buf_trans { - u8 margin; /* swing value */ - u8 scale; /* scale value */ - u8 enable; /* scale enable */ - u8 deemphasis; -}; - -static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { - /* Idx NT mV diff db */ - { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ - { 78, 0x9A, 0, 85, }, /* 1: 400 3.5 */ - { 104, 0x9A, 0, 64, }, /* 2: 400 6 */ - { 154, 0x9A, 0, 43, }, /* 3: 400 9.5 */ - { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ - { 116, 0x9A, 0, 85, }, /* 5: 600 3.5 */ - { 154, 0x9A, 0, 64, }, /* 6: 600 6 */ - { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ - { 154, 0x9A, 0, 85, }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ -}; - -static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = { - /* Idx NT mV diff db */ - { 26, 0, 0, 128, }, /* 0: 200 0 */ - { 38, 0, 0, 112, }, /* 1: 200 1.5 */ - { 48, 0, 0, 96, }, /* 2: 200 4 */ - { 54, 0, 0, 69, }, /* 3: 200 6 */ - { 32, 0, 0, 128, }, /* 4: 250 0 */ - { 48, 0, 0, 104, }, /* 5: 250 1.5 */ - { 54, 0, 0, 85, }, /* 6: 250 4 */ - { 43, 0, 0, 128, }, /* 7: 300 0 */ - { 54, 0, 0, 101, }, /* 8: 300 1.5 */ - { 48, 0, 0, 128, }, /* 9: 300 0 */ -}; - -/* BSpec has 2 recommended values - entries 0 and 8. - * Using the entry with higher vswing. - */ -static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { - /* Idx NT mV diff db */ - { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ - { 52, 0x9A, 0, 85, }, /* 1: 400 3.5 */ - { 52, 0x9A, 0, 64, }, /* 2: 400 6 */ - { 42, 0x9A, 0, 43, }, /* 3: 400 9.5 */ - { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ - { 77, 0x9A, 0, 85, }, /* 5: 600 3.5 */ - { 77, 0x9A, 0, 64, }, /* 6: 600 6 */ - { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ - { 102, 0x9A, 0, 85, }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ -}; - -struct cnl_ddi_buf_trans { - u8 dw2_swing_sel; - u8 dw7_n_scalar; - u8 dw4_cursor_coeff; - u8 dw4_post_cursor_2; - u8 dw4_post_cursor_1; -}; - -/* Voltage Swing Programming for VccIO 0.85V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ - { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.85V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ - { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ - { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.85V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x66, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x66, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x70, 0x3C, 0x00, 0x03 }, /* 460 600 2.3 */ - { 0xC, 0x75, 0x3C, 0x00, 0x03 }, /* 537 700 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ - { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5C, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x69, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x76, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0xA, 0x5E, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x69, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0xB, 0x79, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ - { 0x5, 0x76, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ - { 0x6, 0x7D, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ - { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 0.95V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x61, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x61, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x68, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ - { 0xC, 0x6E, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ - { 0x4, 0x7F, 0x3A, 0x00, 0x05 }, /* 460 600 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for DP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 400 1050 8.4 */ - { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 550 1050 5.6 */ - { 0x5, 0x76, 0x3E, 0x00, 0x01 }, /* 850 900 0.5 */ - { 0x6, 0x7F, 0x36, 0x00, 0x09 }, /* 750 1050 2.9 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for HDMI */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ - { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ - { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ - { 0xA, 0x5B, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ - { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ - { 0x6, 0x7C, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ - { 0x5, 0x70, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ - { 0x6, 0x7C, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ - { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ -}; - -/* Voltage Swing Programming for VccIO 1.05V for eDP */ -static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { - /* NT mV Trans mV db */ - { 0xA, 0x5E, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ - { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ - { 0xA, 0x5E, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ - { 0xB, 0x64, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ - { 0xE, 0x6A, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ - { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ -}; - -/* icl_combo_phy_ddi_translations */ -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = { - /* NT mV Trans mV db */ - { 0x0, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ - { 0x9, 0x7F, 0x31, 0x00, 0x0E }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ - { 0x9, 0x7F, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0x9, 0x7F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = { - /* NT mV Trans mV db */ - { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ - { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ - { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ - { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 ALS */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ -}; - -static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = { - /* NT mV Trans mV db */ - { 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ - { 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */ - { 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ - { 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x38, 0x00, 0x07 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = { - /* NT mV Trans mV db */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ - { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ - { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = { - /* NT mV Trans mV db */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */ - { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */ - { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */ - { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */ - { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ - { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ -}; - -static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_rbr_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ - { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xC, 0x60, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ - { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ - { 0xC, 0x58, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -struct icl_mg_phy_ddi_buf_trans { - u32 cri_txdeemph_override_11_6; - u32 cri_txdeemph_override_5_0; - u32 cri_txdeemph_override_17_12; -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_rbr_hbr[] = { - /* Voltage swing pre-emphasis */ - { 0x18, 0x00, 0x00 }, /* 0 0 */ - { 0x1D, 0x00, 0x05 }, /* 0 1 */ - { 0x24, 0x00, 0x0C }, /* 0 2 */ - { 0x2B, 0x00, 0x14 }, /* 0 3 */ - { 0x21, 0x00, 0x00 }, /* 1 0 */ - { 0x2B, 0x00, 0x08 }, /* 1 1 */ - { 0x30, 0x00, 0x0F }, /* 1 2 */ - { 0x31, 0x00, 0x03 }, /* 2 0 */ - { 0x34, 0x00, 0x0B }, /* 2 1 */ - { 0x3F, 0x00, 0x00 }, /* 3 0 */ -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hbr2_hbr3[] = { - /* Voltage swing pre-emphasis */ - { 0x18, 0x00, 0x00 }, /* 0 0 */ - { 0x1D, 0x00, 0x05 }, /* 0 1 */ - { 0x24, 0x00, 0x0C }, /* 0 2 */ - { 0x2B, 0x00, 0x14 }, /* 0 3 */ - { 0x26, 0x00, 0x00 }, /* 1 0 */ - { 0x2C, 0x00, 0x07 }, /* 1 1 */ - { 0x33, 0x00, 0x0C }, /* 1 2 */ - { 0x2E, 0x00, 0x00 }, /* 2 0 */ - { 0x36, 0x00, 0x09 }, /* 2 1 */ - { 0x3F, 0x00, 0x00 }, /* 3 0 */ -}; - -static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hdmi[] = { - /* HDMI Preset VS Pre-emph */ - { 0x1A, 0x0, 0x0 }, /* 1 400mV 0dB */ - { 0x20, 0x0, 0x0 }, /* 2 500mV 0dB */ - { 0x29, 0x0, 0x0 }, /* 3 650mV 0dB */ - { 0x32, 0x0, 0x0 }, /* 4 800mV 0dB */ - { 0x3F, 0x0, 0x0 }, /* 5 1000mV 0dB */ - { 0x3A, 0x0, 0x5 }, /* 6 Full -1.5 dB */ - { 0x39, 0x0, 0x6 }, /* 7 Full -1.8 dB */ - { 0x38, 0x0, 0x7 }, /* 8 Full -2 dB */ - { 0x37, 0x0, 0x8 }, /* 9 Full -2.5 dB */ - { 0x36, 0x0, 0x9 }, /* 10 Full -3 dB */ -}; - -struct tgl_dkl_phy_ddi_buf_trans { - u32 dkl_vswing_control; - u32 dkl_preshoot_control; - u32 dkl_de_emphasis_control; -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans[] = { - /* VS pre-emp Non-trans mV Pre-emph dB */ - { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ - { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ - { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ - { 0x0, 0x0, 0x18 }, /* 0 3 400mV 9.5 dB */ - { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ - { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ - { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ - { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ - { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ - { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans_hbr2[] = { - /* VS pre-emp Non-trans mV Pre-emph dB */ - { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ - { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ - { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ - { 0x0, 0x0, 0x19 }, /* 0 3 400mV 9.5 dB */ - { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ - { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ - { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ - { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ - { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ - { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ -}; - -static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_hdmi_ddi_trans[] = { - /* HDMI Preset VS Pre-emph */ - { 0x7, 0x0, 0x0 }, /* 1 400mV 0dB */ - { 0x6, 0x0, 0x0 }, /* 2 500mV 0dB */ - { 0x4, 0x0, 0x0 }, /* 3 650mV 0dB */ - { 0x2, 0x0, 0x0 }, /* 4 800mV 0dB */ - { 0x0, 0x0, 0x0 }, /* 5 1000mV 0dB */ - { 0x0, 0x0, 0x5 }, /* 6 Full -1.5 dB */ - { 0x0, 0x0, 0x6 }, /* 7 Full -1.8 dB */ - { 0x0, 0x0, 0x7 }, /* 8 Full -2 dB */ - { 0x0, 0x0, 0x8 }, /* 9 Full -2.5 dB */ - { 0x0, 0x0, 0xA }, /* 10 Full -3 dB */ -}; - -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7D, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ - { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x63, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x61, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7B, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ - { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ - { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ - { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ - { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ - { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -/* - * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries - * that DisplayPort specification requires - */ -static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { - /* VS pre-emp */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */ -}; - -static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr[] = { - /* NT mV Trans mV db */ - { 0xA, 0x2F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ - { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ - { 0x6, 0x7D, 0x2A, 0x00, 0x15 }, /* 350 900 8.2 */ - { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x6E, 0x3E, 0x00, 0x01 }, /* 650 700 0.6 */ - { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { - /* NT mV Trans mV db */ - { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ - { 0xA, 0x50, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ - { 0xC, 0x61, 0x33, 0x00, 0x0C }, /* 350 700 6.0 */ - { 0x6, 0x7F, 0x2E, 0x00, 0x11 }, /* 350 900 8.2 */ - { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ - { 0xC, 0x5F, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ - { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ - { 0xC, 0x5F, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ - { 0x6, 0x7E, 0x36, 0x00, 0x09 }, /* 600 900 3.5 */ - { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ -}; - -static bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table) -{ - return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl; -} - -static const struct ddi_buf_trans * -bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp); - return bdw_ddi_translations_edp; - } else { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); - return bdw_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_SKL_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); - return skl_y_ddi_translations_dp; - } else if (IS_SKL_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); - return skl_u_ddi_translations_dp; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); - return skl_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -kbl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp); - return kbl_y_ddi_translations_dp; - } else if (IS_KBL_ULT(dev_priv) || - IS_CFL_ULT(dev_priv) || - IS_CML_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp); - return kbl_u_ddi_translations_dp; - } else { - *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp); - return kbl_ddi_translations_dp; - } -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - if (IS_SKL_ULX(dev_priv) || - IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp); - return skl_y_ddi_translations_edp; - } else if (IS_SKL_ULT(dev_priv) || - IS_KBL_ULT(dev_priv) || - IS_CFL_ULT(dev_priv) || - IS_CML_ULT(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); - return skl_u_ddi_translations_edp; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); - return skl_ddi_translations_edp; - } - } - - if (IS_KABYLAKE(dev_priv) || - IS_COFFEELAKE(dev_priv) || - IS_COMETLAKE(dev_priv)) - return kbl_get_buf_trans_dp(encoder, n_entries); - else - return skl_get_buf_trans_dp(encoder, n_entries); -} - -static const struct ddi_buf_trans * -skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries) -{ - if (IS_SKL_ULX(dev_priv) || - IS_KBL_ULX(dev_priv) || - IS_CFL_ULX(dev_priv) || - IS_CML_ULX(dev_priv)) { - *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi); - return skl_y_ddi_translations_hdmi; - } else { - *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); - return skl_ddi_translations_hdmi; - } -} - -static int skl_buf_trans_num_entries(enum port port, int n_entries) -{ - /* Only DDIA and DDIE can select the 10th register with DP */ - if (port == PORT_A || port == PORT_E) - return min(n_entries, 10); - else - return min(n_entries, 9); -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_KABYLAKE(dev_priv) || - IS_COFFEELAKE(dev_priv) || - IS_COMETLAKE(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - kbl_get_buf_trans_dp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_SKYLAKE(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - skl_get_buf_trans_dp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); - return bdw_ddi_translations_dp; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); - return hsw_ddi_translations_dp; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_GEN9_BC(dev_priv)) { - const struct ddi_buf_trans *ddi_translations = - skl_get_buf_trans_edp(encoder, n_entries); - *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); - return ddi_translations; - } else if (IS_BROADWELL(dev_priv)) { - return bdw_get_buf_trans_edp(encoder, n_entries); - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); - return hsw_ddi_translations_dp; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, - int *n_entries) -{ - if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi); - return bdw_ddi_translations_fdi; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi); - return hsw_ddi_translations_fdi; - } - - *n_entries = 0; - return NULL; -} - -static const struct ddi_buf_trans * -intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (IS_GEN9_BC(dev_priv)) { - return skl_get_buf_trans_hdmi(dev_priv, n_entries); - } else if (IS_BROADWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); - return bdw_ddi_translations_hdmi; - } else if (IS_HASWELL(dev_priv)) { - *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); - return hsw_ddi_translations_hdmi; - } - - *n_entries = 0; - return NULL; -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); - return bxt_ddi_translations_dp; -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp); - return bxt_ddi_translations_edp; - } - - return bxt_get_buf_trans_dp(encoder, n_entries); -} - -static const struct bxt_ddi_buf_trans * -bxt_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) -{ - *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi); - return bxt_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V); - return cnl_ddi_translations_hdmi_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V); - return cnl_ddi_translations_hdmi_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V); - return cnl_ddi_translations_hdmi_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V); - return cnl_ddi_translations_dp_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V); - return cnl_ddi_translations_dp_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V); - return cnl_ddi_translations_dp_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; -} - -static const struct cnl_ddi_buf_trans * -cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; - - if (dev_priv->vbt.edp.low_vswing) { - if (voltage == VOLTAGE_INFO_0_85V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V); - return cnl_ddi_translations_edp_0_85V; - } else if (voltage == VOLTAGE_INFO_0_95V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V); - return cnl_ddi_translations_edp_0_95V; - } else if (voltage == VOLTAGE_INFO_1_05V) { - *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V); - return cnl_ddi_translations_edp_1_05V; - } else { - *n_entries = 1; /* shut up gcc */ - MISSING_CASE(voltage); - } - return NULL; - } else { - return cnl_get_buf_trans_dp(encoder, n_entries); - } -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); - return icl_combo_phy_ddi_translations_dp_hbr2; -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (crtc_state->port_clock > 540000) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); - return icl_combo_phy_ddi_translations_edp_hbr3; - } else if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } else if (IS_DG1(dev_priv) && crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_hbr2_hbr3); - return dg1_combo_phy_ddi_translations_dp_hbr2_hbr3; - } else if (IS_DG1(dev_priv)) { - *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_rbr_hbr); - return dg1_combo_phy_ddi_translations_dp_rbr_hbr; - } - - return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -icl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi); - return icl_mg_phy_ddi_translations_hdmi; -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3); - return icl_mg_phy_ddi_translations_hbr2_hbr3; - } else { - *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr); - return icl_mg_phy_ddi_translations_rbr_hbr; - } -} - -static const struct icl_mg_phy_ddi_buf_trans * -icl_get_mg_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries); - else - return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp); - return ehl_combo_phy_ddi_translations_dp; -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } - - return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -ehl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); - return icl_combo_phy_ddi_translations_dp_hbr2; -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (dev_priv->vbt.edp.low_vswing) { - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2); - return jsl_combo_phy_ddi_translations_edp_hbr2; - } else { - *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr); - return jsl_combo_phy_ddi_translations_edp_hbr; - } - } - - return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -jsl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); - return icl_combo_phy_ddi_translations_hdmi; -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - - if (crtc_state->port_clock > 270000) { - if (IS_ROCKETLAKE(dev_priv)) { - *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr2_hbr3); - return rkl_combo_phy_ddi_translations_dp_hbr2_hbr3; - } else if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { - *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2); - return tgl_uy_combo_phy_ddi_translations_dp_hbr2; - } else { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); - return tgl_combo_phy_ddi_translations_dp_hbr2; - } - } else { - if (IS_ROCKETLAKE(dev_priv)) { - *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr); - return rkl_combo_phy_ddi_translations_dp_hbr; - } else { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr); - return tgl_combo_phy_ddi_translations_dp_hbr; - } - } -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (crtc_state->port_clock > 540000) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); - return icl_combo_phy_ddi_translations_edp_hbr3; - } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { - *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); - return tgl_combo_phy_ddi_translations_edp_hbr2_hobl; - } else if (dev_priv->vbt.edp.low_vswing) { - *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); - return icl_combo_phy_ddi_translations_edp_hbr2; - } - - return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct cnl_ddi_buf_trans * -tgl_get_combo_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); - else - return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans); - return tgl_dkl_phy_hdmi_ddi_trans; -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (crtc_state->port_clock > 270000) { - *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2); - return tgl_dkl_phy_dp_ddi_trans_hbr2; - } else { - *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans); - return tgl_dkl_phy_dp_ddi_trans; - } -} - -static const struct tgl_dkl_phy_ddi_buf_trans * -tgl_get_dkl_buf_trans(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state, - int *n_entries) -{ - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries); - else - return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); -} - static int intel_ddi_hdmi_level(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); int n_entries, level, default_entry; - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - if (INTEL_GEN(dev_priv) >= 12) { - if (intel_phy_is_combo(dev_priv, phy)) - tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); - else - tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries); - default_entry = n_entries - 1; - } else if (INTEL_GEN(dev_priv) == 11) { - if (intel_phy_is_combo(dev_priv, phy)) - icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); - else - icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries); - default_entry = n_entries - 1; - } else if (IS_CANNONLAKE(dev_priv)) { - cnl_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = n_entries - 1; - } else if (IS_GEN9_LP(dev_priv)) { - bxt_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = n_entries - 1; - } else if (IS_GEN9_BC(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 8; - } else if (IS_BROADWELL(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 7; - } else if (IS_HASWELL(dev_priv)) { - intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); - default_entry = 6; - } else { - drm_WARN(&dev_priv->drm, 1, "ddi translation table missing\n"); + n_entries = intel_ddi_hdmi_num_entries(encoder, crtc_state, &default_entry); + if (n_entries == 0) return 0; - } - - if (drm_WARN_ON_ONCE(&dev_priv->drm, n_entries == 0)) - return 0; - level = intel_bios_hdmi_level_shift(encoder); if (level < 0) level = default_entry; @@ -1637,6 +258,9 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); u32 temp, i, rx_ctl_val, ddi_pll_sel; + int n_entries; + + intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); intel_prepare_dp_ddi_buffers(encoder, crtc_state); @@ -1669,7 +293,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, /* Start the training iterating through available voltages and emphasis, * testing each value twice. */ - for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) { + for (i = 0; i < n_entries * 2; i++) { /* Configure DP_TP_CTL with auto-training */ intel_de_write(dev_priv, DP_TP_CTL(PORT_E), DP_TP_CTL_FDI_AUTOTRAIN | @@ -1718,7 +342,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, * Leave things enabled even if we failed to train FDI. * Results in less fireworks from the state checker. */ - if (i == ARRAY_SIZE(hsw_ddi_translations_fdi) * 2 - 1) { + if (i == n_entries * 2 - 1) { drm_err(&dev_priv->drm, "FDI link training failed!\n"); break; } @@ -2480,13 +1104,7 @@ static void bxt_ddi_vswing_sequence(struct intel_encoder *encoder, enum port port = encoder->port; int n_entries; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - ddi_translations = bxt_get_buf_trans_hdmi(encoder, &n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - ddi_translations = bxt_get_buf_trans_edp(encoder, &n_entries); - else - ddi_translations = bxt_get_buf_trans_dp(encoder, &n_entries); - + ddi_translations = bxt_get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) return; if (drm_WARN_ON_ONCE(&dev_priv->drm, level >= n_entries)) @@ -2523,15 +1141,9 @@ static u8 intel_ddi_dp_voltage_max(struct intel_dp *intel_dp, else icl_get_mg_buf_trans(encoder, crtc_state, &n_entries); } else if (IS_CANNONLAKE(dev_priv)) { - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - cnl_get_buf_trans_edp(encoder, &n_entries); - else - cnl_get_buf_trans_dp(encoder, &n_entries); + cnl_get_buf_trans(encoder, crtc_state, &n_entries); } else if (IS_GEN9_LP(dev_priv)) { - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - bxt_get_buf_trans_edp(encoder, &n_entries); - else - bxt_get_buf_trans_dp(encoder, &n_entries); + bxt_get_buf_trans(encoder, crtc_state, &n_entries); } else { if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) intel_ddi_get_buf_trans_edp(encoder, &n_entries); @@ -2569,12 +1181,7 @@ static void cnl_ddi_vswing_program(struct intel_encoder *encoder, int n_entries, ln; u32 val; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - ddi_translations = cnl_get_buf_trans_hdmi(encoder, &n_entries); - else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) - ddi_translations = cnl_get_buf_trans_edp(encoder, &n_entries); - else - ddi_translations = cnl_get_buf_trans_dp(encoder, &n_entries); + ddi_translations = cnl_get_buf_trans(encoder, crtc_state, &n_entries); if (drm_WARN_ON_ONCE(&dev_priv->drm, !ddi_translations)) return; diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c new file mode 100644 index 0000000000000..f65c2b35461c3 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c @@ -0,0 +1,1394 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ + +#include "i915_drv.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" +#include "intel_display_types.h" + +/* HDMI/DVI modes ignore everything but the last 2 items. So we share + * them for both DP and FDI transports, allowing those ports to + * automatically adapt to HDMI connections as well + */ +static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { + { 0x00FFFFFF, 0x0006000E, 0x0 }, + { 0x00D75FFF, 0x0005000A, 0x0 }, + { 0x00C30FFF, 0x00040006, 0x0 }, + { 0x80AAAFFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x0005000A, 0x0 }, + { 0x00D75FFF, 0x000C0004, 0x0 }, + { 0x80C30FFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x00040006, 0x0 }, + { 0x80D75FFF, 0x000B0000, 0x0 }, +}; + +static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000F000A, 0x0 }, + { 0x00C30FFF, 0x00060006, 0x0 }, + { 0x00AAAFFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x000F000A, 0x0 }, + { 0x00D75FFF, 0x00160004, 0x0 }, + { 0x00C30FFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x00060006, 0x0 }, + { 0x00D75FFF, 0x001E0000, 0x0 }, +}; + +static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { + /* Idx NT mV d T mV d db */ + { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ + { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ + { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ + { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ + { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ + { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ + { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ + { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ + { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ + { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ + { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ + { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ +}; + +static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { + { 0x00FFFFFF, 0x00000012, 0x0 }, + { 0x00EBAFFF, 0x00020011, 0x0 }, + { 0x00C71FFF, 0x0006000F, 0x0 }, + { 0x00AAAFFF, 0x000E000A, 0x0 }, + { 0x00FFFFFF, 0x00020011, 0x0 }, + { 0x00DB6FFF, 0x0005000F, 0x0 }, + { 0x00BEEFFF, 0x000A000C, 0x0 }, + { 0x00FFFFFF, 0x0005000F, 0x0 }, + { 0x00DB6FFF, 0x000A000C, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000E000A, 0x0 }, + { 0x00BEFFFF, 0x00140006, 0x0 }, + { 0x80B2CFFF, 0x001B0002, 0x0 }, + { 0x00FFFFFF, 0x000E000A, 0x0 }, + { 0x00DB6FFF, 0x00160005, 0x0 }, + { 0x80C71FFF, 0x001A0002, 0x0 }, + { 0x00F7DFFF, 0x00180004, 0x0 }, + { 0x80D75FFF, 0x001B0002, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { + { 0x00FFFFFF, 0x0001000E, 0x0 }, + { 0x00D75FFF, 0x0004000A, 0x0 }, + { 0x00C30FFF, 0x00070006, 0x0 }, + { 0x00AAAFFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x0004000A, 0x0 }, + { 0x00D75FFF, 0x00090004, 0x0 }, + { 0x00C30FFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x00070006, 0x0 }, + { 0x00D75FFF, 0x000C0000, 0x0 }, +}; + +static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { + /* Idx NT mV d T mV df db */ + { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ + { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ + { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ + { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ + { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ + { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ + { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ + { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ + { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ + { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ +}; + +/* Skylake H and S */ +static const struct ddi_buf_trans skl_ddi_translations_dp[] = { + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x000000DF, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Skylake U */ +static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { + { 0x0000201B, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x1 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x0000201B, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x00000088, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Skylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { + { 0x00000018, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x80009010, 0x000000C0, 0x3 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00000018, 0x00000088, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* Kabylake H and S */ +static const struct ddi_buf_trans kbl_ddi_translations_dp[] = { + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x80009010, 0x000000C0, 0x1 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000C0, 0x1 }, + { 0x00002016, 0x00000097, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, +}; + +/* Kabylake U */ +static const struct ddi_buf_trans kbl_u_ddi_translations_dp[] = { + { 0x0000201B, 0x000000A1, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x80009010, 0x000000C0, 0x3 }, + { 0x0000201B, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00002016, 0x0000004F, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* Kabylake Y */ +static const struct ddi_buf_trans kbl_y_ddi_translations_dp[] = { + { 0x00001017, 0x000000A1, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x80007011, 0x000000CD, 0x3 }, + { 0x8000800F, 0x000000C0, 0x3 }, + { 0x00001017, 0x0000009D, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, + { 0x80007011, 0x000000C0, 0x3 }, + { 0x00001017, 0x0000004C, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, +}; + +/* + * Skylake/Kabylake H and S + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00000018, 0x000000AB, 0x0 }, + { 0x00007013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; + +/* + * Skylake/Kabylake U + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00002016, 0x000000AB, 0x0 }, + { 0x00005013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; + +/* + * Skylake/Kabylake Y + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000AB, 0x0 }, + { 0x00007011, 0x000000A4, 0x0 }, + { 0x00009010, 0x000000DF, 0x0 }, + { 0x00000018, 0x000000AA, 0x0 }, + { 0x00006013, 0x000000A4, 0x0 }, + { 0x00007011, 0x0000009D, 0x0 }, + { 0x00000018, 0x000000A0, 0x0 }, + { 0x00006012, 0x000000DF, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, +}; + +/* Skylake/Kabylake U, H and S */ +static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000AC, 0x0 }, + { 0x00005012, 0x0000009D, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00000018, 0x00000098, 0x0 }, + { 0x00004013, 0x00000088, 0x0 }, + { 0x80006012, 0x000000CD, 0x1 }, + { 0x00000018, 0x000000DF, 0x0 }, + { 0x80003015, 0x000000CD, 0x1 }, /* Default */ + { 0x80003015, 0x000000C0, 0x1 }, + { 0x80000018, 0x000000C0, 0x1 }, +}; + +/* Skylake/Kabylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00005012, 0x000000DF, 0x0 }, + { 0x80007011, 0x000000CB, 0x3 }, + { 0x00000018, 0x000000A4, 0x0 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00004013, 0x00000080, 0x0 }, + { 0x80006013, 0x000000C0, 0x3 }, + { 0x00000018, 0x0000008A, 0x0 }, + { 0x80003015, 0x000000C0, 0x3 }, /* Default */ + { 0x80003015, 0x000000C0, 0x3 }, + { 0x80000018, 0x000000C0, 0x3 }, +}; + + +static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { + /* Idx NT mV diff db */ + { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ + { 78, 0x9A, 0, 85, }, /* 1: 400 3.5 */ + { 104, 0x9A, 0, 64, }, /* 2: 400 6 */ + { 154, 0x9A, 0, 43, }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ + { 116, 0x9A, 0, 85, }, /* 5: 600 3.5 */ + { 154, 0x9A, 0, 64, }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ + { 154, 0x9A, 0, 85, }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ +}; + +static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = { + /* Idx NT mV diff db */ + { 26, 0, 0, 128, }, /* 0: 200 0 */ + { 38, 0, 0, 112, }, /* 1: 200 1.5 */ + { 48, 0, 0, 96, }, /* 2: 200 4 */ + { 54, 0, 0, 69, }, /* 3: 200 6 */ + { 32, 0, 0, 128, }, /* 4: 250 0 */ + { 48, 0, 0, 104, }, /* 5: 250 1.5 */ + { 54, 0, 0, 85, }, /* 6: 250 4 */ + { 43, 0, 0, 128, }, /* 7: 300 0 */ + { 54, 0, 0, 101, }, /* 8: 300 1.5 */ + { 48, 0, 0, 128, }, /* 9: 300 0 */ +}; + +/* BSpec has 2 recommended values - entries 0 and 8. + * Using the entry with higher vswing. + */ +static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { + /* Idx NT mV diff db */ + { 52, 0x9A, 0, 128, }, /* 0: 400 0 */ + { 52, 0x9A, 0, 85, }, /* 1: 400 3.5 */ + { 52, 0x9A, 0, 64, }, /* 2: 400 6 */ + { 42, 0x9A, 0, 43, }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, }, /* 4: 600 0 */ + { 77, 0x9A, 0, 85, }, /* 5: 600 3.5 */ + { 77, 0x9A, 0, 64, }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, }, /* 7: 800 0 */ + { 102, 0x9A, 0, 85, }, /* 8: 800 3.5 */ + { 154, 0x9A, 1, 128, }, /* 9: 1200 0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ + { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ + { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ + { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.85V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_85V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x66, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x66, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x70, 0x3C, 0x00, 0x03 }, /* 460 600 2.3 */ + { 0xC, 0x75, 0x3C, 0x00, 0x03 }, /* 537 700 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5D, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x6A, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xB, 0x7A, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0x6, 0x7C, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xA, 0x69, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xB, 0x7A, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7C, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xB, 0x7D, 0x3C, 0x00, 0x03 }, /* 650 725 0.9 */ + { 0x6, 0x7C, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7B, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5C, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x69, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x76, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0xA, 0x5E, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x69, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0xB, 0x79, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ + { 0x5, 0x76, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ + { 0x6, 0x7D, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ + { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 0.95V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_0_95V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x61, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x61, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x68, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ + { 0xC, 0x6E, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ + { 0x4, 0x7F, 0x3A, 0x00, 0x05 }, /* 460 600 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for DP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_dp_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 400 1050 8.4 */ + { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 550 1050 5.6 */ + { 0x5, 0x76, 0x3E, 0x00, 0x01 }, /* 850 900 0.5 */ + { 0x6, 0x7F, 0x36, 0x00, 0x09 }, /* 750 1050 2.9 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for HDMI */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_hdmi_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x58, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ + { 0xB, 0x64, 0x37, 0x00, 0x08 }, /* 400 600 3.5 */ + { 0x5, 0x70, 0x31, 0x00, 0x0E }, /* 400 800 6.0 */ + { 0xA, 0x5B, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x64, 0x3F, 0x00, 0x00 }, /* 600 600 0.0 */ + { 0x5, 0x73, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ + { 0x6, 0x7C, 0x32, 0x00, 0x0D }, /* 600 1000 4.4 */ + { 0x5, 0x70, 0x3F, 0x00, 0x00 }, /* 800 800 0.0 */ + { 0x6, 0x7C, 0x39, 0x00, 0x06 }, /* 800 1000 1.9 */ + { 0x6, 0x7F, 0x39, 0x00, 0x06 }, /* 850 1050 1.8 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1050 1050 0.0 */ +}; + +/* Voltage Swing Programming for VccIO 1.05V for eDP */ +static const struct cnl_ddi_buf_trans cnl_ddi_translations_edp_1_05V[] = { + /* NT mV Trans mV db */ + { 0xA, 0x5E, 0x3A, 0x00, 0x05 }, /* 384 500 2.3 */ + { 0x0, 0x7F, 0x38, 0x00, 0x07 }, /* 153 200 2.3 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 192 250 2.3 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 230 300 2.3 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 269 350 2.3 */ + { 0xA, 0x5E, 0x3C, 0x00, 0x03 }, /* 446 500 1.0 */ + { 0xB, 0x64, 0x39, 0x00, 0x06 }, /* 460 600 2.3 */ + { 0xE, 0x6A, 0x39, 0x00, 0x06 }, /* 537 700 2.3 */ + { 0x2, 0x7F, 0x3F, 0x00, 0x00 }, /* 400 400 0.0 */ +}; + +/* icl_combo_phy_ddi_translations */ +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr2[] = { + /* NT mV Trans mV db */ + { 0x0, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ + { 0x9, 0x7F, 0x31, 0x00, 0x0E }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ + { 0x9, 0x7F, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0x9, 0x7F, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0x9, 0x7F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_edp_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans icl_combo_phy_ddi_translations_hdmi[] = { + /* NT mV Trans mV db */ + { 0xA, 0x60, 0x3F, 0x00, 0x00 }, /* 450 450 0.0 */ + { 0xB, 0x73, 0x36, 0x00, 0x09 }, /* 450 650 3.2 */ + { 0x6, 0x7F, 0x31, 0x00, 0x0E }, /* 450 850 5.5 */ + { 0xB, 0x73, 0x3F, 0x00, 0x00 }, /* 650 650 0.0 ALS */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 650 850 2.3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 850 850 0.0 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 850 3.0 */ +}; + +static const struct cnl_ddi_buf_trans ehl_combo_phy_ddi_translations_dp[] = { + /* NT mV Trans mV db */ + { 0xA, 0x33, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x47, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ + { 0xC, 0x64, 0x34, 0x00, 0x0B }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 350 900 8.2 */ + { 0xA, 0x46, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x64, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ + { 0xC, 0x61, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x38, 0x00, 0x07 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr[] = { + /* NT mV Trans mV db */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x38, 0x00, 0x07 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x33, 0x00, 0x0C }, /* 200 300 3.5 */ + { 0xA, 0x35, 0x36, 0x00, 0x09 }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x38, 0x00, 0x07 }, /* 250 300 1.6 */ + { 0xA, 0x35, 0x35, 0x00, 0x0A }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans jsl_combo_phy_ddi_translations_edp_hbr2[] = { + /* NT mV Trans mV db */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 200 0.0 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 200 250 1.9 */ + { 0x1, 0x7F, 0x3D, 0x00, 0x02 }, /* 200 300 3.5 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 200 350 4.9 */ + { 0x8, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 250 0.0 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 250 300 1.6 */ + { 0xA, 0x35, 0x3A, 0x00, 0x05 }, /* 250 350 2.9 */ + { 0x1, 0x7F, 0x3F, 0x00, 0x00 }, /* 300 300 0.0 */ + { 0xA, 0x35, 0x38, 0x00, 0x07 }, /* 300 350 1.3 */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ +}; + +static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_rbr_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ + { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xC, 0x60, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x37, 0x00, 0x08 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans dg1_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x48, 0x35, 0x00, 0x0A }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2C, 0x00, 0x13 }, /* 350 900 8.2 */ + { 0xA, 0x43, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x60, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x30, 0x00, 0x0F }, /* 500 900 5.1 */ + { 0xC, 0x58, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_rbr_hbr[] = { + /* Voltage swing pre-emphasis */ + { 0x18, 0x00, 0x00 }, /* 0 0 */ + { 0x1D, 0x00, 0x05 }, /* 0 1 */ + { 0x24, 0x00, 0x0C }, /* 0 2 */ + { 0x2B, 0x00, 0x14 }, /* 0 3 */ + { 0x21, 0x00, 0x00 }, /* 1 0 */ + { 0x2B, 0x00, 0x08 }, /* 1 1 */ + { 0x30, 0x00, 0x0F }, /* 1 2 */ + { 0x31, 0x00, 0x03 }, /* 2 0 */ + { 0x34, 0x00, 0x0B }, /* 2 1 */ + { 0x3F, 0x00, 0x00 }, /* 3 0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hbr2_hbr3[] = { + /* Voltage swing pre-emphasis */ + { 0x18, 0x00, 0x00 }, /* 0 0 */ + { 0x1D, 0x00, 0x05 }, /* 0 1 */ + { 0x24, 0x00, 0x0C }, /* 0 2 */ + { 0x2B, 0x00, 0x14 }, /* 0 3 */ + { 0x26, 0x00, 0x00 }, /* 1 0 */ + { 0x2C, 0x00, 0x07 }, /* 1 1 */ + { 0x33, 0x00, 0x0C }, /* 1 2 */ + { 0x2E, 0x00, 0x00 }, /* 2 0 */ + { 0x36, 0x00, 0x09 }, /* 2 1 */ + { 0x3F, 0x00, 0x00 }, /* 3 0 */ +}; + +static const struct icl_mg_phy_ddi_buf_trans icl_mg_phy_ddi_translations_hdmi[] = { + /* HDMI Preset VS Pre-emph */ + { 0x1A, 0x0, 0x0 }, /* 1 400mV 0dB */ + { 0x20, 0x0, 0x0 }, /* 2 500mV 0dB */ + { 0x29, 0x0, 0x0 }, /* 3 650mV 0dB */ + { 0x32, 0x0, 0x0 }, /* 4 800mV 0dB */ + { 0x3F, 0x0, 0x0 }, /* 5 1000mV 0dB */ + { 0x3A, 0x0, 0x5 }, /* 6 Full -1.5 dB */ + { 0x39, 0x0, 0x6 }, /* 7 Full -1.8 dB */ + { 0x38, 0x0, 0x7 }, /* 8 Full -2 dB */ + { 0x37, 0x0, 0x8 }, /* 9 Full -2.5 dB */ + { 0x36, 0x0, 0x9 }, /* 10 Full -3 dB */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans[] = { + /* VS pre-emp Non-trans mV Pre-emph dB */ + { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ + { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ + { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ + { 0x0, 0x0, 0x18 }, /* 0 3 400mV 9.5 dB */ + { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ + { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ + { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ + { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ + { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ + { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_dp_ddi_trans_hbr2[] = { + /* VS pre-emp Non-trans mV Pre-emph dB */ + { 0x7, 0x0, 0x00 }, /* 0 0 400mV 0 dB */ + { 0x5, 0x0, 0x05 }, /* 0 1 400mV 3.5 dB */ + { 0x2, 0x0, 0x0B }, /* 0 2 400mV 6 dB */ + { 0x0, 0x0, 0x19 }, /* 0 3 400mV 9.5 dB */ + { 0x5, 0x0, 0x00 }, /* 1 0 600mV 0 dB */ + { 0x2, 0x0, 0x08 }, /* 1 1 600mV 3.5 dB */ + { 0x0, 0x0, 0x14 }, /* 1 2 600mV 6 dB */ + { 0x2, 0x0, 0x00 }, /* 2 0 800mV 0 dB */ + { 0x0, 0x0, 0x0B }, /* 2 1 800mV 3.5 dB */ + { 0x0, 0x0, 0x00 }, /* 3 0 1200mV 0 dB HDMI default */ +}; + +static const struct tgl_dkl_phy_ddi_buf_trans tgl_dkl_phy_hdmi_ddi_trans[] = { + /* HDMI Preset VS Pre-emph */ + { 0x7, 0x0, 0x0 }, /* 1 400mV 0dB */ + { 0x6, 0x0, 0x0 }, /* 2 500mV 0dB */ + { 0x4, 0x0, 0x0 }, /* 3 650mV 0dB */ + { 0x2, 0x0, 0x0 }, /* 4 800mV 0dB */ + { 0x0, 0x0, 0x0 }, /* 5 1000mV 0dB */ + { 0x0, 0x0, 0x5 }, /* 6 Full -1.5 dB */ + { 0x0, 0x0, 0x6 }, /* 7 Full -1.8 dB */ + { 0x0, 0x0, 0x7 }, /* 8 Full -2 dB */ + { 0x0, 0x0, 0x8 }, /* 9 Full -2.5 dB */ + { 0x0, 0x0, 0xA }, /* 10 Full -3 dB */ +}; + +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x32, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x71, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7D, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6C, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2B, 0x00, 0x14 }, /* 350 900 8.2 */ + { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x63, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x61, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7B, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans tgl_uy_combo_phy_ddi_translations_dp_hbr2[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x36, 0x00, 0x09 }, /* 350 500 3.1 */ + { 0xC, 0x60, 0x32, 0x00, 0x0D }, /* 350 700 6.0 */ + { 0xC, 0x7F, 0x2D, 0x00, 0x12 }, /* 350 900 8.2 */ + { 0xC, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x6F, 0x36, 0x00, 0x09 }, /* 500 700 2.9 */ + { 0x6, 0x7D, 0x32, 0x00, 0x0D }, /* 500 900 5.1 */ + { 0x6, 0x60, 0x3C, 0x00, 0x03 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x34, 0x00, 0x0B }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +/* + * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries + * that DisplayPort specification requires + */ +static const struct cnl_ddi_buf_trans tgl_combo_phy_ddi_translations_edp_hbr2_hobl[] = { + /* VS pre-emp */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 0 3 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 1 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 1 2 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 0 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 2 1 */ +}; + +static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr[] = { + /* NT mV Trans mV db */ + { 0xA, 0x2F, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x4F, 0x37, 0x00, 0x08 }, /* 350 500 3.1 */ + { 0xC, 0x63, 0x2F, 0x00, 0x10 }, /* 350 700 6.0 */ + { 0x6, 0x7D, 0x2A, 0x00, 0x15 }, /* 350 900 8.2 */ + { 0xA, 0x4C, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x73, 0x34, 0x00, 0x0B }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x6E, 0x3E, 0x00, 0x01 }, /* 650 700 0.6 */ + { 0x6, 0x7F, 0x35, 0x00, 0x0A }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +static const struct cnl_ddi_buf_trans rkl_combo_phy_ddi_translations_dp_hbr2_hbr3[] = { + /* NT mV Trans mV db */ + { 0xA, 0x35, 0x3F, 0x00, 0x00 }, /* 350 350 0.0 */ + { 0xA, 0x50, 0x38, 0x00, 0x07 }, /* 350 500 3.1 */ + { 0xC, 0x61, 0x33, 0x00, 0x0C }, /* 350 700 6.0 */ + { 0x6, 0x7F, 0x2E, 0x00, 0x11 }, /* 350 900 8.2 */ + { 0xA, 0x47, 0x3F, 0x00, 0x00 }, /* 500 500 0.0 */ + { 0xC, 0x5F, 0x38, 0x00, 0x07 }, /* 500 700 2.9 */ + { 0x6, 0x7F, 0x2F, 0x00, 0x10 }, /* 500 900 5.1 */ + { 0xC, 0x5F, 0x3F, 0x00, 0x00 }, /* 650 700 0.6 */ + { 0x6, 0x7E, 0x36, 0x00, 0x09 }, /* 600 900 3.5 */ + { 0x6, 0x7F, 0x3F, 0x00, 0x00 }, /* 900 900 0.0 */ +}; + +bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table) +{ + return table == tgl_combo_phy_ddi_translations_edp_hbr2_hobl; +} + +static const struct ddi_buf_trans * +bdw_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_edp); + return bdw_ddi_translations_edp; + } else { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); + return bdw_ddi_translations_dp; + } +} + +static const struct ddi_buf_trans * +skl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_SKL_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); + return skl_y_ddi_translations_dp; + } else if (IS_SKL_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + return skl_u_ddi_translations_dp; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + return skl_ddi_translations_dp; + } +} + +static const struct ddi_buf_trans * +kbl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(kbl_y_ddi_translations_dp); + return kbl_y_ddi_translations_dp; + } else if (IS_KBL_ULT(dev_priv) || + IS_CFL_ULT(dev_priv) || + IS_CML_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(kbl_u_ddi_translations_dp); + return kbl_u_ddi_translations_dp; + } else { + *n_entries = ARRAY_SIZE(kbl_ddi_translations_dp); + return kbl_ddi_translations_dp; + } +} + +static const struct ddi_buf_trans * +skl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + if (IS_SKL_ULX(dev_priv) || + IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp); + return skl_y_ddi_translations_edp; + } else if (IS_SKL_ULT(dev_priv) || + IS_KBL_ULT(dev_priv) || + IS_CFL_ULT(dev_priv) || + IS_CML_ULT(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); + return skl_u_ddi_translations_edp; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); + return skl_ddi_translations_edp; + } + } + + if (IS_KABYLAKE(dev_priv) || + IS_COFFEELAKE(dev_priv) || + IS_COMETLAKE(dev_priv)) + return kbl_get_buf_trans_dp(encoder, n_entries); + else + return skl_get_buf_trans_dp(encoder, n_entries); +} + +static const struct ddi_buf_trans * +skl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries) +{ + if (IS_SKL_ULX(dev_priv) || + IS_KBL_ULX(dev_priv) || + IS_CFL_ULX(dev_priv) || + IS_CML_ULX(dev_priv)) { + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi); + return skl_y_ddi_translations_hdmi; + } else { + *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); + return skl_ddi_translations_hdmi; + } +} + +static int skl_buf_trans_num_entries(enum port port, int n_entries) +{ + /* Only DDIA and DDIE can select the 10th register with DP */ + if (port == PORT_A || port == PORT_E) + return min(n_entries, 10); + else + return min(n_entries, 9); +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_KABYLAKE(dev_priv) || + IS_COFFEELAKE(dev_priv) || + IS_COMETLAKE(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + kbl_get_buf_trans_dp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_SKYLAKE(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + skl_get_buf_trans_dp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_dp); + return bdw_ddi_translations_dp; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); + return hsw_ddi_translations_dp; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_GEN9_BC(dev_priv)) { + const struct ddi_buf_trans *ddi_translations = + skl_get_buf_trans_edp(encoder, n_entries); + *n_entries = skl_buf_trans_num_entries(encoder->port, *n_entries); + return ddi_translations; + } else if (IS_BROADWELL(dev_priv)) { + return bdw_get_buf_trans_edp(encoder, n_entries); + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_dp); + return hsw_ddi_translations_dp; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, + int *n_entries) +{ + if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi); + return bdw_ddi_translations_fdi; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi); + return hsw_ddi_translations_fdi; + } + + *n_entries = 0; + return NULL; +} + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (IS_GEN9_BC(dev_priv)) { + return skl_get_buf_trans_hdmi(dev_priv, n_entries); + } else if (IS_BROADWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi); + return bdw_ddi_translations_hdmi; + } else if (IS_HASWELL(dev_priv)) { + *n_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi); + return hsw_ddi_translations_hdmi; + } + + *n_entries = 0; + return NULL; +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + *n_entries = ARRAY_SIZE(bxt_ddi_translations_dp); + return bxt_ddi_translations_dp; +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(bxt_ddi_translations_edp); + return bxt_ddi_translations_edp; + } + + return bxt_get_buf_trans_dp(encoder, n_entries); +} + +static const struct bxt_ddi_buf_trans * +bxt_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) +{ + *n_entries = ARRAY_SIZE(bxt_ddi_translations_hdmi); + return bxt_ddi_translations_hdmi; +} + +const struct bxt_ddi_buf_trans * +bxt_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return bxt_get_buf_trans_hdmi(encoder, n_entries); + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return bxt_get_buf_trans_edp(encoder, n_entries); + return bxt_get_buf_trans_dp(encoder, n_entries); +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_hdmi(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V); + return cnl_ddi_translations_hdmi_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V); + return cnl_ddi_translations_hdmi_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V); + return cnl_ddi_translations_hdmi_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V); + return cnl_ddi_translations_dp_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V); + return cnl_ddi_translations_dp_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V); + return cnl_ddi_translations_dp_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; +} + +static const struct cnl_ddi_buf_trans * +cnl_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 voltage = intel_de_read(dev_priv, CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK; + + if (dev_priv->vbt.edp.low_vswing) { + if (voltage == VOLTAGE_INFO_0_85V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V); + return cnl_ddi_translations_edp_0_85V; + } else if (voltage == VOLTAGE_INFO_0_95V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V); + return cnl_ddi_translations_edp_0_95V; + } else if (voltage == VOLTAGE_INFO_1_05V) { + *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V); + return cnl_ddi_translations_edp_1_05V; + } else { + *n_entries = 1; /* shut up gcc */ + MISSING_CASE(voltage); + } + return NULL; + } else { + return cnl_get_buf_trans_dp(encoder, n_entries); + } +} + +const struct cnl_ddi_buf_trans * +cnl_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return cnl_get_buf_trans_hdmi(encoder, n_entries); + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return cnl_get_buf_trans_edp(encoder, n_entries); + return cnl_get_buf_trans_dp(encoder, n_entries); +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); + return icl_combo_phy_ddi_translations_dp_hbr2; +} + +static const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (crtc_state->port_clock > 540000) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); + return icl_combo_phy_ddi_translations_edp_hbr3; + } else if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } else if (IS_DG1(dev_priv) && crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_hbr2_hbr3); + return dg1_combo_phy_ddi_translations_dp_hbr2_hbr3; + } else if (IS_DG1(dev_priv)) { + *n_entries = ARRAY_SIZE(dg1_combo_phy_ddi_translations_dp_rbr_hbr); + return dg1_combo_phy_ddi_translations_dp_rbr_hbr; + } + + return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return icl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return icl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return icl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hdmi); + return icl_mg_phy_ddi_translations_hdmi; +} + +static const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_hbr2_hbr3); + return icl_mg_phy_ddi_translations_hbr2_hbr3; + } else { + *n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations_rbr_hbr); + return icl_mg_phy_ddi_translations_rbr_hbr; + } +} + +const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return icl_get_mg_buf_trans_hdmi(encoder, crtc_state, n_entries); + else + return icl_get_mg_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(ehl_combo_phy_ddi_translations_dp); + return ehl_combo_phy_ddi_translations_dp; +} + +static const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } + + return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return ehl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return ehl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return ehl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_dp_hbr2); + return icl_combo_phy_ddi_translations_dp_hbr2; +} + +static const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (dev_priv->vbt.edp.low_vswing) { + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr2); + return jsl_combo_phy_ddi_translations_edp_hbr2; + } else { + *n_entries = ARRAY_SIZE(jsl_combo_phy_ddi_translations_edp_hbr); + return jsl_combo_phy_ddi_translations_edp_hbr; + } + } + + return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return jsl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return jsl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return jsl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_hdmi); + return icl_combo_phy_ddi_translations_hdmi; +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + + if (crtc_state->port_clock > 270000) { + if (IS_ROCKETLAKE(dev_priv)) { + *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr2_hbr3); + return rkl_combo_phy_ddi_translations_dp_hbr2_hbr3; + } else if (IS_TGL_U(dev_priv) || IS_TGL_Y(dev_priv)) { + *n_entries = ARRAY_SIZE(tgl_uy_combo_phy_ddi_translations_dp_hbr2); + return tgl_uy_combo_phy_ddi_translations_dp_hbr2; + } else { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr2); + return tgl_combo_phy_ddi_translations_dp_hbr2; + } + } else { + if (IS_ROCKETLAKE(dev_priv)) { + *n_entries = ARRAY_SIZE(rkl_combo_phy_ddi_translations_dp_hbr); + return rkl_combo_phy_ddi_translations_dp_hbr; + } else { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_dp_hbr); + return tgl_combo_phy_ddi_translations_dp_hbr; + } + } +} + +static const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans_edp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (crtc_state->port_clock > 540000) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr3); + return icl_combo_phy_ddi_translations_edp_hbr3; + } else if (dev_priv->vbt.edp.hobl && !intel_dp->hobl_failed) { + *n_entries = ARRAY_SIZE(tgl_combo_phy_ddi_translations_edp_hbr2_hobl); + return tgl_combo_phy_ddi_translations_edp_hbr2_hobl; + } else if (dev_priv->vbt.edp.low_vswing) { + *n_entries = ARRAY_SIZE(icl_combo_phy_ddi_translations_edp_hbr2); + return icl_combo_phy_ddi_translations_edp_hbr2; + } + + return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, n_entries); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return tgl_get_combo_buf_trans_edp(encoder, crtc_state, n_entries); + else + return tgl_get_combo_buf_trans_dp(encoder, crtc_state, n_entries); +} + +static const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans_hdmi(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + *n_entries = ARRAY_SIZE(tgl_dkl_phy_hdmi_ddi_trans); + return tgl_dkl_phy_hdmi_ddi_trans; +} + +static const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans_dp(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (crtc_state->port_clock > 270000) { + *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans_hbr2); + return tgl_dkl_phy_dp_ddi_trans_hbr2; + } else { + *n_entries = ARRAY_SIZE(tgl_dkl_phy_dp_ddi_trans); + return tgl_dkl_phy_dp_ddi_trans; + } +} + +const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries) +{ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + return tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, n_entries); + else + return tgl_get_dkl_buf_trans_dp(encoder, crtc_state, n_entries); +} + +int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *default_entry) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + int n_entries; + + if (INTEL_GEN(dev_priv) >= 12) { + if (intel_phy_is_combo(dev_priv, phy)) + tgl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); + else + tgl_get_dkl_buf_trans_hdmi(encoder, crtc_state, &n_entries); + *default_entry = n_entries - 1; + } else if (INTEL_GEN(dev_priv) == 11) { + if (intel_phy_is_combo(dev_priv, phy)) + icl_get_combo_buf_trans_hdmi(encoder, crtc_state, &n_entries); + else + icl_get_mg_buf_trans_hdmi(encoder, crtc_state, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_CANNONLAKE(dev_priv)) { + cnl_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_GEN9_LP(dev_priv)) { + bxt_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = n_entries - 1; + } else if (IS_GEN9_BC(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 8; + } else if (IS_BROADWELL(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 7; + } else if (IS_HASWELL(dev_priv)) { + intel_ddi_get_buf_trans_hdmi(encoder, &n_entries); + *default_entry = 6; + } else { + drm_WARN(&dev_priv->drm, 1, "ddi translation table missing\n"); + return 0; + } + + if (drm_WARN_ON_ONCE(&dev_priv->drm, n_entries == 0)) + return 0; + + return n_entries; +} diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h new file mode 100644 index 0000000000000..f8f0ef87e9773 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#ifndef _INTEL_DDI_BUF_TRANS_H_ +#define _INTEL_DDI_BUF_TRANS_H_ + +#include + +struct drm_i915_private; +struct intel_encoder; +struct intel_crtc_state; + +struct ddi_buf_trans { + u32 trans1; /* balance leg enable, de-emph level */ + u32 trans2; /* vref sel, vswing */ + u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ +}; + +struct bxt_ddi_buf_trans { + u8 margin; /* swing value */ + u8 scale; /* scale value */ + u8 enable; /* scale enable */ + u8 deemphasis; +}; + +struct cnl_ddi_buf_trans { + u8 dw2_swing_sel; + u8 dw7_n_scalar; + u8 dw4_cursor_coeff; + u8 dw4_post_cursor_2; + u8 dw4_post_cursor_1; +}; + +struct icl_mg_phy_ddi_buf_trans { + u32 cri_txdeemph_override_11_6; + u32 cri_txdeemph_override_5_0; + u32 cri_txdeemph_override_17_12; +}; + +struct tgl_dkl_phy_ddi_buf_trans { + u32 dkl_vswing_control; + u32 dkl_preshoot_control; + u32 dkl_de_emphasis_control; +}; + +bool is_hobl_buf_trans(const struct cnl_ddi_buf_trans *table); + +int intel_ddi_hdmi_num_entries(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *default_entry); + +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_edp(struct intel_encoder *encoder, int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_fdi(struct drm_i915_private *dev_priv, + int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_hdmi(struct intel_encoder *encoder, + int *n_entries); +const struct ddi_buf_trans * +intel_ddi_get_buf_trans_dp(struct intel_encoder *encoder, int *n_entries); + +const struct bxt_ddi_buf_trans * +bxt_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +const struct cnl_ddi_buf_trans * +tgl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct tgl_dkl_phy_ddi_buf_trans * +tgl_get_dkl_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +jsl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +ehl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct cnl_ddi_buf_trans * +icl_get_combo_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); +const struct icl_mg_phy_ddi_buf_trans * +icl_get_mg_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +const struct cnl_ddi_buf_trans * +cnl_get_buf_trans(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + int *n_entries); + +#endif From dcb38f79126e37cfcc95bb80bc86775dfdc39fec Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Feb 2021 21:43:19 +0200 Subject: [PATCH 040/142] drm/i915: migrate hsw fdi code to new file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Daniel asked for this, but it's a bit messy and I'm not sure how best to clean it up yet. Signed-off-by: Dave Airlie [Jani: also moved fdi buf trans to intel_fdi.c.] Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/44491f2465549ea5c2e48cde5437fa232f77ab96.1612467466.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 151 ++--------------------- drivers/gpu/drm/i915/display/intel_ddi.h | 8 +- drivers/gpu/drm/i915/display/intel_fdi.c | 139 +++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_fdi.h | 3 + 5 files changed, 156 insertions(+), 146 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 4934edd51cb0b..077ebc7e63965 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -38,6 +38,7 @@ #include "intel_crt.h" #include "intel_ddi.h" #include "intel_display_types.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hotplug.h" diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e2b82e0557e7c..28877a31adc00 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -36,10 +36,11 @@ #include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_dp.h" -#include "intel_dp_mst.h" #include "intel_dp_link_training.h" +#include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_dsi.h" +#include "intel_fdi.h" #include "intel_fifo_underrun.h" #include "intel_gmbus.h" #include "intel_hdcp.h" @@ -91,8 +92,8 @@ static int intel_ddi_hdmi_level(struct intel_encoder *encoder, * values in advance. This function programs the correct values for * DP/eDP/FDI use cases. */ -static void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); u32 iboost_bit = 0; @@ -154,8 +155,8 @@ static void intel_prepare_hdmi_ddi_buffers(struct intel_encoder *encoder, ddi_translations[level].trans2); } -static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, - enum port port) +void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port) { if (IS_BROXTON(dev_priv)) { udelay(16); @@ -183,7 +184,7 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv, port_name(port)); } -static u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) +u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) { switch (pll->info->id) { case DPLL_ID_WRPLL1: @@ -243,144 +244,6 @@ static u32 icl_pll_to_ddi_clk_sel(struct intel_encoder *encoder, } } -/* Starting with Haswell, different DDI ports can work in FDI mode for - * connection to the PCH-located connectors. For this, it is necessary to train - * both the DDI port and PCH receiver for the desired DDI buffer settings. - * - * The recommended port to work in FDI mode is DDI E, which we use here. Also, - * please note that when FDI mode is active on DDI E, it shares 2 lines with - * DDI A (which is used for eDP) - */ - -void hsw_fdi_link_train(struct intel_encoder *encoder, - 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); - u32 temp, i, rx_ctl_val, ddi_pll_sel; - int n_entries; - - intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); - - intel_prepare_dp_ddi_buffers(encoder, crtc_state); - - /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the - * mode set "sequence for CRT port" document: - * - TP1 to TP2 time with the default value - * - FDI delay to 90h - * - * WaFDIAutoLinkSetTimingOverrride:hsw - */ - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), - FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); - - /* Enable the PCH Receiver FDI PLL */ - rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | - FDI_RX_PLL_ENABLE | - FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes); - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - udelay(220); - - /* Switch from Rawclk to PCDclk */ - rx_ctl_val |= FDI_PCDCLK; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - - /* Configure Port Clock Select */ - ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll); - intel_de_write(dev_priv, PORT_CLK_SEL(PORT_E), ddi_pll_sel); - drm_WARN_ON(&dev_priv->drm, ddi_pll_sel != PORT_CLK_SEL_SPLL); - - /* Start the training iterating through available voltages and emphasis, - * testing each value twice. */ - for (i = 0; i < n_entries * 2; i++) { - /* Configure DP_TP_CTL with auto-training */ - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), - DP_TP_CTL_FDI_AUTOTRAIN | - DP_TP_CTL_ENHANCED_FRAME_ENABLE | - DP_TP_CTL_LINK_TRAIN_PAT1 | - DP_TP_CTL_ENABLE); - - /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. - * DDI E does not support port reversal, the functionality is - * achieved on the PCH side in FDI_RX_CTL, so no need to set the - * port reversal bit */ - intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), - DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); - intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); - - udelay(600); - - /* Program PCH FDI Receiver TU */ - intel_de_write(dev_priv, FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64)); - - /* Enable PCH FDI Receiver with auto-training */ - rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - - /* Wait for FDI receiver lane calibration */ - udelay(30); - - /* Unset FDI_RX_MISC pwrdn lanes */ - temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); - temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); - intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); - - /* Wait for FDI auto training time */ - udelay(5); - - temp = intel_de_read(dev_priv, DP_TP_STATUS(PORT_E)); - if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { - drm_dbg_kms(&dev_priv->drm, - "FDI link training done on step %d\n", i); - break; - } - - /* - * Leave things enabled even if we failed to train FDI. - * Results in less fireworks from the state checker. - */ - if (i == n_entries * 2 - 1) { - drm_err(&dev_priv->drm, "FDI link training failed!\n"); - break; - } - - rx_ctl_val &= ~FDI_RX_ENABLE; - intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); - intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); - - temp = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_E)); - temp &= ~DDI_BUF_CTL_ENABLE; - intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), temp); - intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); - - /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ - temp = intel_de_read(dev_priv, DP_TP_CTL(PORT_E)); - temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); - temp |= DP_TP_CTL_LINK_TRAIN_PAT1; - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), temp); - intel_de_posting_read(dev_priv, DP_TP_CTL(PORT_E)); - - intel_wait_ddi_buf_idle(dev_priv, PORT_E); - - /* Reset FDI_RX_MISC pwrdn lanes */ - temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); - temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); - temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); - intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); - intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); - } - - /* Enable normal pixel sending for FDI */ - intel_de_write(dev_priv, DP_TP_CTL(PORT_E), - DP_TP_CTL_FDI_AUTOTRAIN | - DP_TP_CTL_LINK_TRAIN_NORMAL | - DP_TP_CTL_ENHANCED_FRAME_ENABLE | - DP_TP_CTL_ENABLE); -} - static void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index a4dd815c00001..f9a916cad7e75 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -17,6 +17,7 @@ struct intel_crtc_state; struct intel_dp; struct intel_dpll_hw_state; struct intel_encoder; +struct intel_shared_dpll; enum transcoder; i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder, @@ -27,8 +28,11 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state); -void hsw_fdi_link_train(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll); +void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, + enum port port); void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port); bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe); void intel_ddi_enable_transcoder_func(struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index b2eb96ae10a23..77df675e607e9 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -3,6 +3,8 @@ * Copyright © 2020 Intel Corporation */ #include "intel_atomic.h" +#include "intel_ddi.h" +#include "intel_ddi_buf_trans.h" #include "intel_display_types.h" #include "intel_fdi.h" @@ -550,6 +552,143 @@ static void ivb_manual_fdi_link_train(struct intel_crtc *crtc, drm_dbg_kms(&dev_priv->drm, "FDI train done.\n"); } +/* Starting with Haswell, different DDI ports can work in FDI mode for + * connection to the PCH-located connectors. For this, it is necessary to train + * both the DDI port and PCH receiver for the desired DDI buffer settings. + * + * The recommended port to work in FDI mode is DDI E, which we use here. Also, + * please note that when FDI mode is active on DDI E, it shares 2 lines with + * DDI A (which is used for eDP) + */ +void hsw_fdi_link_train(struct intel_encoder *encoder, + 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); + u32 temp, i, rx_ctl_val, ddi_pll_sel; + int n_entries; + + intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); + + intel_prepare_dp_ddi_buffers(encoder, crtc_state); + + /* Set the FDI_RX_MISC pwrdn lanes and the 2 workarounds listed at the + * mode set "sequence for CRT port" document: + * - TP1 to TP2 time with the default value + * - FDI delay to 90h + * + * WaFDIAutoLinkSetTimingOverrride:hsw + */ + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), + FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2) | FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); + + /* Enable the PCH Receiver FDI PLL */ + rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE | + FDI_RX_PLL_ENABLE | + FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes); + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + udelay(220); + + /* Switch from Rawclk to PCDclk */ + rx_ctl_val |= FDI_PCDCLK; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + + /* Configure Port Clock Select */ + ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll); + intel_de_write(dev_priv, PORT_CLK_SEL(PORT_E), ddi_pll_sel); + drm_WARN_ON(&dev_priv->drm, ddi_pll_sel != PORT_CLK_SEL_SPLL); + + /* Start the training iterating through available voltages and emphasis, + * testing each value twice. */ + for (i = 0; i < n_entries * 2; i++) { + /* Configure DP_TP_CTL with auto-training */ + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_LINK_TRAIN_PAT1 | + DP_TP_CTL_ENABLE); + + /* Configure and enable DDI_BUF_CTL for DDI E with next voltage. + * DDI E does not support port reversal, the functionality is + * achieved on the PCH side in FDI_RX_CTL, so no need to set the + * port reversal bit */ + intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), + DDI_BUF_CTL_ENABLE | ((crtc_state->fdi_lanes - 1) << 1) | DDI_BUF_TRANS_SELECT(i / 2)); + intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); + + udelay(600); + + /* Program PCH FDI Receiver TU */ + intel_de_write(dev_priv, FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64)); + + /* Enable PCH FDI Receiver with auto-training */ + rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + + /* Wait for FDI receiver lane calibration */ + udelay(30); + + /* Unset FDI_RX_MISC pwrdn lanes */ + temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); + intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); + + /* Wait for FDI auto training time */ + udelay(5); + + temp = intel_de_read(dev_priv, DP_TP_STATUS(PORT_E)); + if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) { + drm_dbg_kms(&dev_priv->drm, + "FDI link training done on step %d\n", i); + break; + } + + /* + * Leave things enabled even if we failed to train FDI. + * Results in less fireworks from the state checker. + */ + if (i == n_entries * 2 - 1) { + drm_err(&dev_priv->drm, "FDI link training failed!\n"); + break; + } + + rx_ctl_val &= ~FDI_RX_ENABLE; + intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); + intel_de_posting_read(dev_priv, FDI_RX_CTL(PIPE_A)); + + temp = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_E)); + temp &= ~DDI_BUF_CTL_ENABLE; + intel_de_write(dev_priv, DDI_BUF_CTL(PORT_E), temp); + intel_de_posting_read(dev_priv, DDI_BUF_CTL(PORT_E)); + + /* Disable DP_TP_CTL and FDI_RX_CTL and retry */ + temp = intel_de_read(dev_priv, DP_TP_CTL(PORT_E)); + temp &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + temp |= DP_TP_CTL_LINK_TRAIN_PAT1; + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), temp); + intel_de_posting_read(dev_priv, DP_TP_CTL(PORT_E)); + + intel_wait_ddi_buf_idle(dev_priv, PORT_E); + + /* Reset FDI_RX_MISC pwrdn lanes */ + temp = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); + temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); + temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); + intel_de_write(dev_priv, FDI_RX_MISC(PIPE_A), temp); + intel_de_posting_read(dev_priv, FDI_RX_MISC(PIPE_A)); + } + + /* Enable normal pixel sending for FDI */ + intel_de_write(dev_priv, DP_TP_CTL(PORT_E), + DP_TP_CTL_FDI_AUTOTRAIN | + DP_TP_CTL_LINK_TRAIN_NORMAL | + DP_TP_CTL_ENHANCED_FRAME_ENABLE | + DP_TP_CTL_ENABLE); +} + void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_fdi.h b/drivers/gpu/drm/i915/display/intel_fdi.h index a9cd21663eb89..af01d2c173a82 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.h +++ b/drivers/gpu/drm/i915/display/intel_fdi.h @@ -9,6 +9,7 @@ struct drm_i915_private; struct intel_crtc; struct intel_crtc_state; +struct intel_encoder; #define I915_DISPLAY_CONFIG_RETRY 1 int ilk_fdi_compute_config(struct intel_crtc *intel_crtc, @@ -18,5 +19,7 @@ void ilk_fdi_disable(struct intel_crtc *crtc); void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc); void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state); void intel_fdi_init_hook(struct drm_i915_private *dev_priv); +void hsw_fdi_link_train(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); #endif From 6499f925dd4709ef755e919be355b9e8de6038a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Feb 2021 04:08:45 +0200 Subject: [PATCH 041/142] drm/i915: Index min_{cdclk,voltage_level}[] with pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit min_cdclk[] and min_voltage_level[] are supposed to be indexed with the pipe. Fix up a few cases where we index via the crtc index (via the atomic iterators) instead. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210204020846.2094-1-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_cdclk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index bf83e9e752272..a9019287f7d51 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2145,10 +2145,10 @@ static int intel_compute_min_cdclk(struct intel_cdclk_state *cdclk_state) if (IS_ERR(bw_state)) return PTR_ERR(bw_state); - if (cdclk_state->min_cdclk[i] == min_cdclk) + if (cdclk_state->min_cdclk[crtc->pipe] == min_cdclk) continue; - cdclk_state->min_cdclk[i] = min_cdclk; + cdclk_state->min_cdclk[crtc->pipe] = min_cdclk; ret = intel_atomic_lock_global_state(&cdclk_state->base); if (ret) @@ -2199,10 +2199,10 @@ static int bxt_compute_min_voltage_level(struct intel_cdclk_state *cdclk_state) else min_voltage_level = 0; - if (cdclk_state->min_voltage_level[i] == min_voltage_level) + if (cdclk_state->min_voltage_level[crtc->pipe] == min_voltage_level) continue; - cdclk_state->min_voltage_level[i] = min_voltage_level; + cdclk_state->min_voltage_level[crtc->pipe] = min_voltage_level; ret = intel_atomic_lock_global_state(&cdclk_state->base); if (ret) From 3c4442aa22878091f16c8d9592f5f5b6a94d1556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Feb 2021 04:08:46 +0200 Subject: [PATCH 042/142] drm/i915: Use intel_hdmi_port_clock() more MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hand rolled intel_hdmi_port_clock() stuff with the real thing. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210204020846.2094-2-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_hdmi.c | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index b593a71e65172..dad54e116bc48 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -2233,6 +2233,16 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, return MODE_OK; } +static int intel_hdmi_port_clock(int clock, int bpc) +{ + /* + * Need to adjust the port link by: + * 1.5x for 12bpc + * 1.25x for 10bpc + */ + return clock * bpc / 8; +} + static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -2264,17 +2274,18 @@ intel_hdmi_mode_valid(struct drm_connector *connector, clock /= 2; /* check if we can do 8bpc */ - status = hdmi_port_clock_valid(hdmi, clock, true, has_hdmi_sink); + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 8), + true, has_hdmi_sink); if (has_hdmi_sink) { /* if we can't do 8bpc we may still be able to do 12bpc */ if (status != MODE_OK && !HAS_GMCH(dev_priv)) - status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 12), true, has_hdmi_sink); /* if we can't do 8,12bpc we may still be able to do 10bpc */ if (status != MODE_OK && INTEL_GEN(dev_priv) >= 11) - status = hdmi_port_clock_valid(hdmi, clock * 5 / 4, + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 10), true, has_hdmi_sink); } if (status != MODE_OK) @@ -2382,16 +2393,6 @@ intel_hdmi_ycbcr420_config(struct intel_crtc_state *crtc_state, return intel_pch_panel_fitting(crtc_state, conn_state); } -static int intel_hdmi_port_clock(int clock, int bpc) -{ - /* - * Need to adjust the port link by: - * 1.5x for 12bpc - * 1.25x for 10bpc - */ - return clock * bpc / 8; -} - static int intel_hdmi_compute_bpc(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int clock) From 46d12f911821f7bef99b24a1f7c63bbb51766515 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:36 +0200 Subject: [PATCH 043/142] drm/i915: migrate skl planes code new file (v5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework the plane init calls to do the gen test one level higher. Rework some of the plane helpers so they can live in new file, there is still some scope to clean up the plane/fb interactions later. v2: drop atomic code back, rename file to Ville suggestions, add header file. v3: move scaler bits back v4: drop wrong new includes (Ville) v5: integrate the ccs gen12 changes v6: fix unrelated code movement (Ville) Signed-off-by: Dave Airlie [Jani: fixed up sparse warnings.] Signed-off-by: Jani Nikula Reported-by: kernel test robot Reported-by: Dan Carpenter Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/4e88a5c6b9ab3b93cc2b6c7d78c26ae86f6abbd0.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/i9xx_plane.c | 4 - drivers/gpu/drm/i915/display/icl_dsi.c | 1 + drivers/gpu/drm/i915/display/intel_crtc.c | 13 +- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 948 +------ drivers/gpu/drm/i915/display/intel_display.h | 27 +- .../drm/i915/display/intel_display_types.h | 27 + drivers/gpu/drm/i915/display/intel_psr.c | 1 + drivers/gpu/drm/i915/display/intel_sprite.c | 1343 +--------- drivers/gpu/drm/i915/display/intel_sprite.h | 6 +- .../drm/i915/display/skl_universal_plane.c | 2265 +++++++++++++++++ .../drm/i915/display/skl_universal_plane.h | 33 + drivers/gpu/drm/i915/intel_pm.c | 1 + 14 files changed, 2380 insertions(+), 2293 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/skl_universal_plane.c create mode 100644 drivers/gpu/drm/i915/display/skl_universal_plane.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 0e98cf2eec309..40cba6f0792de 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -223,7 +223,8 @@ i915-y += \ display/intel_sprite.o \ display/intel_tc.o \ display/intel_vga.o \ - display/i9xx_plane.o + display/i9xx_plane.o \ + display/skl_universal_plane.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index d30374df67f07..d116dee201aa0 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -743,10 +743,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) int num_formats; int ret, zpos; - if (INTEL_GEN(dev_priv) >= 9) - return skl_universal_plane_create(dev_priv, pipe, - PLANE_PRIMARY); - plane = intel_plane_alloc(); if (IS_ERR(plane)) return plane; diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9d245a689323f..9eeec6fadec72 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -35,6 +35,7 @@ #include "intel_dsi.h" #include "intel_panel.h" #include "intel_vdsc.h" +#include "skl_universal_plane.h" static int header_credits_available(struct drm_i915_private *dev_priv, enum transcoder dsi_trans) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 57b0a3ebe9085..eb478712c3814 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -20,6 +20,7 @@ #include "intel_pipe_crc.h" #include "intel_sprite.h" #include "i9xx_plane.h" +#include "skl_universal_plane.h" static void assert_vblank_disabled(struct drm_crtc *crtc) { @@ -243,7 +244,11 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) crtc->pipe = pipe; crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe]; - primary = intel_primary_plane_create(dev_priv, pipe); + if (INTEL_GEN(dev_priv) >= 9) + primary = skl_universal_plane_create(dev_priv, pipe, + PLANE_PRIMARY); + else + primary = intel_primary_plane_create(dev_priv, pipe); if (IS_ERR(primary)) { ret = PTR_ERR(primary); goto fail; @@ -253,7 +258,11 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) for_each_sprite(dev_priv, pipe, sprite) { struct intel_plane *plane; - plane = intel_sprite_plane_create(dev_priv, pipe, sprite); + if (INTEL_GEN(dev_priv) >= 9) + plane = skl_universal_plane_create(dev_priv, pipe, + PLANE_SPRITE0 + sprite); + else + plane = intel_sprite_plane_create(dev_priv, pipe, sprite); if (IS_ERR(plane)) { ret = PTR_ERR(plane); goto fail; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 28877a31adc00..f4746c1edabe8 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -54,6 +54,7 @@ #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vrr.h" +#include "skl_universal_plane.h" static const u8 index_to_dp_signal_levels[] = { [0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 5a36575ba3705..257954cb74268 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -94,6 +94,7 @@ #include "intel_tc.h" #include "intel_vga.h" #include "i9xx_plane.h" +#include "skl_universal_plane.h" static void i9xx_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); @@ -116,7 +117,6 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); -static void skl_pfit_enable(const struct intel_crtc_state *crtc_state); static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); @@ -1082,32 +1082,6 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv) return IS_GEN(dev_priv, 2) ? 2048 : 4096; } -static bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) -{ - if (!is_ccs_modifier(fb->modifier)) - return false; - - return plane >= fb->format->num_planes / 2; -} - -static bool is_gen12_ccs_modifier(u64 modifier) -{ - return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; -} - -static bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) -{ - return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); -} - -static bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) -{ - return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && - plane == 2; -} - static bool is_aux_plane(const struct drm_framebuffer *fb, int plane) { if (is_ccs_modifier(fb->modifier)) @@ -1116,38 +1090,6 @@ static bool is_aux_plane(const struct drm_framebuffer *fb, int plane) return plane == 1; } -static int main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) -{ - drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || - (main_plane && main_plane >= fb->format->num_planes / 2)); - - return fb->format->num_planes / 2 + main_plane; -} - -static int ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) -{ - drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || - ccs_plane < fb->format->num_planes / 2); - - if (is_gen12_ccs_cc_plane(fb, ccs_plane)) - return 0; - - return ccs_plane - fb->format->num_planes / 2; -} - -int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) -{ - struct drm_i915_private *i915 = to_i915(fb->dev); - - if (is_ccs_modifier(fb->modifier)) - return main_to_ccs_plane(fb, main_plane); - else if (INTEL_GEN(i915) < 11 && - intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 1; - else - return 0; -} - bool intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info, u64 modifier) @@ -1163,7 +1105,7 @@ static bool is_semiplanar_uv_plane(const struct drm_framebuffer *fb, color_plane == 1; } -static unsigned int +unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); @@ -1217,7 +1159,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) } } -static unsigned int +unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane) { if (is_gen12_ccs_plane(fb, color_plane)) @@ -1322,8 +1264,8 @@ static bool has_async_flips(struct drm_i915_private *i915) return INTEL_GEN(i915) >= 5; } -static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, - int color_plane) +unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, + int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); @@ -1593,10 +1535,10 @@ static u32 intel_adjust_aligned_offset(int *x, int *y, * Adjust the tile offset by moving the difference into * the x/y offsets. */ -static u32 intel_plane_adjust_aligned_offset(int *x, int *y, - const struct intel_plane_state *state, - int color_plane, - u32 old_offset, u32 new_offset) +u32 intel_plane_adjust_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane, + u32 old_offset, u32 new_offset) { return intel_adjust_aligned_offset(x, y, state->hw.fb, color_plane, state->hw.rotation, @@ -1895,7 +1837,7 @@ bool is_ccs_modifier(u64 modifier) static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane) { - return DIV_ROUND_UP(fb->pitches[ccs_to_main_plane(fb, ccs_plane)], + return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)], 512) * 64; } @@ -2053,7 +1995,7 @@ static bool intel_plane_needs_remap(const struct intel_plane_state *plane_state) return stride > max_stride; } -static void +void intel_fb_plane_get_subsampling(int *hsub, int *vsub, const struct drm_framebuffer *fb, int color_plane) @@ -2078,7 +2020,7 @@ intel_fb_plane_get_subsampling(int *hsub, int *vsub, return; } - main_plane = ccs_to_main_plane(fb, color_plane); + main_plane = skl_ccs_to_main_plane(fb, color_plane); *hsub = drm_format_info_block_width(fb->format, color_plane) / drm_format_info_block_width(fb->format, main_plane); @@ -2118,7 +2060,7 @@ intel_fb_check_ccs_xy(struct drm_framebuffer *fb, int ccs_plane, int x, int y) ccs_x = (x * hsub) % tile_width; ccs_y = (y * vsub) % tile_height; - main_plane = ccs_to_main_plane(fb, ccs_plane); + main_plane = skl_ccs_to_main_plane(fb, ccs_plane); main_x = intel_fb->normal[main_plane].x % tile_width; main_y = intel_fb->normal[main_plane].y % tile_height; @@ -2144,7 +2086,7 @@ static void intel_fb_plane_dims(int *w, int *h, struct drm_framebuffer *fb, int color_plane) { int main_plane = is_ccs_plane(fb, color_plane) ? - ccs_to_main_plane(fb, color_plane) : 0; + skl_ccs_to_main_plane(fb, color_plane) : 0; int main_hsub, main_vsub; int hsub, vsub; @@ -2531,73 +2473,6 @@ static int i9xx_format_to_fourcc(int format) } } -int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) -{ - switch (format) { - case PLANE_CTL_FORMAT_RGB_565: - return DRM_FORMAT_RGB565; - case PLANE_CTL_FORMAT_NV12: - return DRM_FORMAT_NV12; - case PLANE_CTL_FORMAT_XYUV: - return DRM_FORMAT_XYUV8888; - case PLANE_CTL_FORMAT_P010: - return DRM_FORMAT_P010; - case PLANE_CTL_FORMAT_P012: - return DRM_FORMAT_P012; - case PLANE_CTL_FORMAT_P016: - return DRM_FORMAT_P016; - case PLANE_CTL_FORMAT_Y210: - return DRM_FORMAT_Y210; - case PLANE_CTL_FORMAT_Y212: - return DRM_FORMAT_Y212; - case PLANE_CTL_FORMAT_Y216: - return DRM_FORMAT_Y216; - case PLANE_CTL_FORMAT_Y410: - return DRM_FORMAT_XVYU2101010; - case PLANE_CTL_FORMAT_Y412: - return DRM_FORMAT_XVYU12_16161616; - case PLANE_CTL_FORMAT_Y416: - return DRM_FORMAT_XVYU16161616; - default: - case PLANE_CTL_FORMAT_XRGB_8888: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR8888; - else - return DRM_FORMAT_XBGR8888; - } else { - if (alpha) - return DRM_FORMAT_ARGB8888; - else - return DRM_FORMAT_XRGB8888; - } - case PLANE_CTL_FORMAT_XRGB_2101010: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR2101010; - else - return DRM_FORMAT_XBGR2101010; - } else { - if (alpha) - return DRM_FORMAT_ARGB2101010; - else - return DRM_FORMAT_XRGB2101010; - } - case PLANE_CTL_FORMAT_XRGB_16161616F: - if (rgb_order) { - if (alpha) - return DRM_FORMAT_ABGR16161616F; - else - return DRM_FORMAT_XBGR16161616F; - } else { - if (alpha) - return DRM_FORMAT_ARGB16161616F; - else - return DRM_FORMAT_XRGB16161616F; - } - } -} - static struct i915_vma * initial_plane_vma(struct drm_i915_private *i915, struct intel_initial_plane_config *plane_config) @@ -2902,52 +2777,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, &to_intel_frontbuffer(fb)->bits); } - -static bool -skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state, - int main_x, int main_y, u32 main_offset, - int ccs_plane) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int aux_x = plane_state->color_plane[ccs_plane].x; - int aux_y = plane_state->color_plane[ccs_plane].y; - u32 aux_offset = plane_state->color_plane[ccs_plane].offset; - u32 alignment = intel_surf_alignment(fb, ccs_plane); - int hsub; - int vsub; - - intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); - while (aux_offset >= main_offset && aux_y <= main_y) { - int x, y; - - if (aux_x == main_x && aux_y == main_y) - break; - - if (aux_offset == 0) - break; - - x = aux_x / hsub; - y = aux_y / vsub; - aux_offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - ccs_plane, - aux_offset, - aux_offset - - alignment); - aux_x = x * hsub + aux_x % hsub; - aux_y = y * vsub + aux_y % vsub; - } - - if (aux_x != main_x || aux_y != main_y) - return false; - - plane_state->color_plane[ccs_plane].offset = aux_offset; - plane_state->color_plane[ccs_plane].x = aux_x; - plane_state->color_plane[ccs_plane].y = aux_y; - - return true; -} - unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) { @@ -2959,310 +2788,6 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) return y; } -static int intel_plane_min_width(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->min_width) - return plane->min_width(fb, color_plane, rotation); - else - return 1; -} - -static int intel_plane_max_width(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->max_width) - return plane->max_width(fb, color_plane, rotation); - else - return INT_MAX; -} - -static int intel_plane_max_height(struct intel_plane *plane, - const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - if (plane->max_height) - return plane->max_height(fb, color_plane, rotation); - else - return INT_MAX; -} - -int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, - int *x, int *y, u32 *offset) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - const int aux_plane = intel_main_to_aux_plane(fb, 0); - const u32 aux_offset = plane_state->color_plane[aux_plane].offset; - const u32 alignment = intel_surf_alignment(fb, 0); - const int w = drm_rect_width(&plane_state->uapi.src) >> 16; - - intel_add_fb_offsets(x, y, plane_state, 0); - *offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0); - if (drm_WARN_ON(&dev_priv->drm, alignment && !is_power_of_2(alignment))) - return -EINVAL; - - /* - * AUX surface offset is specified as the distance from the - * main surface offset, and it must be non-negative. Make - * sure that is what we will get. - */ - if (aux_plane && *offset > aux_offset) - *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, - *offset, - aux_offset & ~(alignment - 1)); - - /* - * When using an X-tiled surface, the plane blows up - * if the x offset + width exceed the stride. - * - * TODO: linear and Y-tiled seem fine, Yf untested, - */ - if (fb->modifier == I915_FORMAT_MOD_X_TILED) { - int cpp = fb->format->cpp[0]; - - while ((*x + w) * cpp > plane_state->color_plane[0].stride) { - if (*offset == 0) { - drm_dbg_kms(&dev_priv->drm, - "Unable to find suitable display surface offset due to X-tiling\n"); - return -EINVAL; - } - - *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, - *offset, - *offset - alignment); - } - } - - return 0; -} - -static int skl_check_main_surface(struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - const unsigned int rotation = plane_state->hw.rotation; - int x = plane_state->uapi.src.x1 >> 16; - int y = plane_state->uapi.src.y1 >> 16; - const int w = drm_rect_width(&plane_state->uapi.src) >> 16; - const int h = drm_rect_height(&plane_state->uapi.src) >> 16; - const int min_width = intel_plane_min_width(plane, fb, 0, rotation); - const int max_width = intel_plane_max_width(plane, fb, 0, rotation); - const int max_height = intel_plane_max_height(plane, fb, 0, rotation); - const int aux_plane = intel_main_to_aux_plane(fb, 0); - const u32 alignment = intel_surf_alignment(fb, 0); - u32 offset; - int ret; - - if (w > max_width || w < min_width || h > max_height) { - drm_dbg_kms(&dev_priv->drm, - "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", - w, h, min_width, max_width, max_height); - return -EINVAL; - } - - ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset); - if (ret) - return ret; - - /* - * CCS AUX surface doesn't have its own x/y offsets, we must make sure - * they match with the main surface x/y offsets. - */ - if (is_ccs_modifier(fb->modifier)) { - while (!skl_check_main_ccs_coordinates(plane_state, x, y, - offset, aux_plane)) { - if (offset == 0) - break; - - offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, - offset, offset - alignment); - } - - if (x != plane_state->color_plane[aux_plane].x || - y != plane_state->color_plane[aux_plane].y) { - drm_dbg_kms(&dev_priv->drm, - "Unable to find suitable display surface offset due to CCS\n"); - return -EINVAL; - } - } - - drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); - - plane_state->color_plane[0].offset = offset; - plane_state->color_plane[0].x = x; - plane_state->color_plane[0].y = y; - - /* - * Put the final coordinates back so that the src - * coordinate checks will see the right values. - */ - drm_rect_translate_to(&plane_state->uapi.src, - x << 16, y << 16); - - return 0; -} - -static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *i915 = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - int uv_plane = 1; - int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation); - int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation); - int x = plane_state->uapi.src.x1 >> 17; - int y = plane_state->uapi.src.y1 >> 17; - int w = drm_rect_width(&plane_state->uapi.src) >> 17; - int h = drm_rect_height(&plane_state->uapi.src) >> 17; - u32 offset; - - /* FIXME not quite sure how/if these apply to the chroma plane */ - if (w > max_width || h > max_height) { - drm_dbg_kms(&i915->drm, - "CbCr source size %dx%d too big (limit %dx%d)\n", - w, h, max_width, max_height); - return -EINVAL; - } - - intel_add_fb_offsets(&x, &y, plane_state, uv_plane); - offset = intel_plane_compute_aligned_offset(&x, &y, - plane_state, uv_plane); - - if (is_ccs_modifier(fb->modifier)) { - int ccs_plane = main_to_ccs_plane(fb, uv_plane); - u32 aux_offset = plane_state->color_plane[ccs_plane].offset; - u32 alignment = intel_surf_alignment(fb, uv_plane); - - if (offset > aux_offset) - offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - uv_plane, - offset, - aux_offset & ~(alignment - 1)); - - while (!skl_check_main_ccs_coordinates(plane_state, x, y, - offset, ccs_plane)) { - if (offset == 0) - break; - - offset = intel_plane_adjust_aligned_offset(&x, &y, - plane_state, - uv_plane, - offset, offset - alignment); - } - - if (x != plane_state->color_plane[ccs_plane].x || - y != plane_state->color_plane[ccs_plane].y) { - drm_dbg_kms(&i915->drm, - "Unable to find suitable display surface offset due to CCS\n"); - return -EINVAL; - } - } - - drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); - - plane_state->color_plane[uv_plane].offset = offset; - plane_state->color_plane[uv_plane].x = x; - plane_state->color_plane[uv_plane].y = y; - - return 0; -} - -static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int src_x = plane_state->uapi.src.x1 >> 16; - int src_y = plane_state->uapi.src.y1 >> 16; - u32 offset; - int ccs_plane; - - for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) { - int main_hsub, main_vsub; - int hsub, vsub; - int x, y; - - if (!is_ccs_plane(fb, ccs_plane) || - is_gen12_ccs_cc_plane(fb, ccs_plane)) - continue; - - intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, - ccs_to_main_plane(fb, ccs_plane)); - intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); - - hsub *= main_hsub; - vsub *= main_vsub; - x = src_x / hsub; - y = src_y / vsub; - - intel_add_fb_offsets(&x, &y, plane_state, ccs_plane); - - offset = intel_plane_compute_aligned_offset(&x, &y, - plane_state, - ccs_plane); - - plane_state->color_plane[ccs_plane].offset = offset; - plane_state->color_plane[ccs_plane].x = (x * hsub + - src_x % hsub) / - main_hsub; - plane_state->color_plane[ccs_plane].y = (y * vsub + - src_y % vsub) / - main_vsub; - } - - return 0; -} - -int skl_check_plane_surface(struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - int ret, i; - - ret = intel_plane_compute_gtt(plane_state); - if (ret) - return ret; - - if (!plane_state->uapi.visible) - return 0; - - /* - * Handle the AUX surface first since the main surface setup depends on - * it. - */ - if (is_ccs_modifier(fb->modifier)) { - ret = skl_check_ccs_aux_surface(plane_state); - if (ret) - return ret; - } - - if (intel_format_info_is_yuv_semiplanar(fb->format, - fb->modifier)) { - ret = skl_check_nv12_aux_surface(plane_state); - if (ret) - return ret; - } - - for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) { - plane_state->color_plane[i].offset = 0; - plane_state->color_plane[i].x = 0; - plane_state->color_plane[i].y = 0; - } - - ret = skl_check_main_surface(plane_state); - if (ret) - return ret; - - return 0; -} - static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) { struct drm_device *dev = intel_crtc->base.dev; @@ -3295,307 +2820,6 @@ static void skl_detach_scalers(const struct intel_crtc_state *crtc_state) } } -static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb, - int color_plane, unsigned int rotation) -{ - /* - * The stride is either expressed as a multiple of 64 bytes chunks for - * linear buffers or in number of tiles for tiled buffers. - */ - if (is_surface_linear(fb, color_plane)) - return 64; - else if (drm_rotation_90_or_270(rotation)) - return intel_tile_height(fb, color_plane); - else - return intel_tile_width_bytes(fb, color_plane); -} - -u32 skl_plane_stride(const struct intel_plane_state *plane_state, - int color_plane) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - u32 stride = plane_state->color_plane[color_plane].stride; - - if (color_plane >= fb->format->num_planes) - return 0; - - return stride / skl_plane_stride_mult(fb, color_plane, rotation); -} - -static u32 skl_plane_ctl_format(u32 pixel_format) -{ - switch (pixel_format) { - case DRM_FORMAT_C8: - return PLANE_CTL_FORMAT_INDEXED; - case DRM_FORMAT_RGB565: - return PLANE_CTL_FORMAT_RGB_565; - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ABGR8888: - return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ARGB8888: - return PLANE_CTL_FORMAT_XRGB_8888; - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ABGR2101010: - return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_ARGB2101010: - return PLANE_CTL_FORMAT_XRGB_2101010; - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX; - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - return PLANE_CTL_FORMAT_XRGB_16161616F; - case DRM_FORMAT_XYUV8888: - return PLANE_CTL_FORMAT_XYUV; - case DRM_FORMAT_YUYV: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; - case DRM_FORMAT_YVYU: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; - case DRM_FORMAT_UYVY: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; - case DRM_FORMAT_VYUY: - return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; - case DRM_FORMAT_NV12: - return PLANE_CTL_FORMAT_NV12; - case DRM_FORMAT_P010: - return PLANE_CTL_FORMAT_P010; - case DRM_FORMAT_P012: - return PLANE_CTL_FORMAT_P012; - case DRM_FORMAT_P016: - return PLANE_CTL_FORMAT_P016; - case DRM_FORMAT_Y210: - return PLANE_CTL_FORMAT_Y210; - case DRM_FORMAT_Y212: - return PLANE_CTL_FORMAT_Y212; - case DRM_FORMAT_Y216: - return PLANE_CTL_FORMAT_Y216; - case DRM_FORMAT_XVYU2101010: - return PLANE_CTL_FORMAT_Y410; - case DRM_FORMAT_XVYU12_16161616: - return PLANE_CTL_FORMAT_Y412; - case DRM_FORMAT_XVYU16161616: - return PLANE_CTL_FORMAT_Y416; - default: - MISSING_CASE(pixel_format); - } - - return 0; -} - -static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state) -{ - if (!plane_state->hw.fb->format->has_alpha) - return PLANE_CTL_ALPHA_DISABLE; - - switch (plane_state->hw.pixel_blend_mode) { - case DRM_MODE_BLEND_PIXEL_NONE: - return PLANE_CTL_ALPHA_DISABLE; - case DRM_MODE_BLEND_PREMULTI: - return PLANE_CTL_ALPHA_SW_PREMULTIPLY; - case DRM_MODE_BLEND_COVERAGE: - return PLANE_CTL_ALPHA_HW_PREMULTIPLY; - default: - MISSING_CASE(plane_state->hw.pixel_blend_mode); - return PLANE_CTL_ALPHA_DISABLE; - } -} - -static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state) -{ - if (!plane_state->hw.fb->format->has_alpha) - return PLANE_COLOR_ALPHA_DISABLE; - - switch (plane_state->hw.pixel_blend_mode) { - case DRM_MODE_BLEND_PIXEL_NONE: - return PLANE_COLOR_ALPHA_DISABLE; - case DRM_MODE_BLEND_PREMULTI: - return PLANE_COLOR_ALPHA_SW_PREMULTIPLY; - case DRM_MODE_BLEND_COVERAGE: - return PLANE_COLOR_ALPHA_HW_PREMULTIPLY; - default: - MISSING_CASE(plane_state->hw.pixel_blend_mode); - return PLANE_COLOR_ALPHA_DISABLE; - } -} - -static u32 skl_plane_ctl_tiling(u64 fb_modifier) -{ - switch (fb_modifier) { - case DRM_FORMAT_MOD_LINEAR: - break; - case I915_FORMAT_MOD_X_TILED: - return PLANE_CTL_TILED_X; - case I915_FORMAT_MOD_Y_TILED: - return PLANE_CTL_TILED_Y; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: - return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: - return PLANE_CTL_TILED_Y | - PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | - PLANE_CTL_CLEAR_COLOR_DISABLE; - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE; - case I915_FORMAT_MOD_Yf_TILED: - return PLANE_CTL_TILED_YF; - case I915_FORMAT_MOD_Yf_TILED_CCS: - return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; - default: - MISSING_CASE(fb_modifier); - } - - return 0; -} - -static u32 skl_plane_ctl_rotate(unsigned int rotate) -{ - switch (rotate) { - case DRM_MODE_ROTATE_0: - break; - /* - * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr - * while i915 HW rotation is clockwise, thats why this swapping. - */ - case DRM_MODE_ROTATE_90: - return PLANE_CTL_ROTATE_270; - case DRM_MODE_ROTATE_180: - return PLANE_CTL_ROTATE_180; - case DRM_MODE_ROTATE_270: - return PLANE_CTL_ROTATE_90; - default: - MISSING_CASE(rotate); - } - - return 0; -} - -static u32 cnl_plane_ctl_flip(unsigned int reflect) -{ - switch (reflect) { - case 0: - break; - case DRM_MODE_REFLECT_X: - return PLANE_CTL_FLIP_HORIZONTAL; - case DRM_MODE_REFLECT_Y: - default: - MISSING_CASE(reflect); - } - - return 0; -} - -u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - u32 plane_ctl = 0; - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - return plane_ctl; - - if (crtc_state->gamma_enable) - plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE; - - if (crtc_state->csc_enable) - plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE; - - return plane_ctl; -} - -u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 plane_ctl; - - plane_ctl = PLANE_CTL_ENABLE; - - if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { - plane_ctl |= skl_plane_ctl_alpha(plane_state); - plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; - - if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709) - plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; - - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE; - } - - plane_ctl |= skl_plane_ctl_format(fb->format->format); - plane_ctl |= skl_plane_ctl_tiling(fb->modifier); - plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK); - - if (INTEL_GEN(dev_priv) >= 10) - plane_ctl |= cnl_plane_ctl_flip(rotation & - DRM_MODE_REFLECT_MASK); - - if (key->flags & I915_SET_COLORKEY_DESTINATION) - plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; - else if (key->flags & I915_SET_COLORKEY_SOURCE) - plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; - - return plane_ctl; -} - -u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - u32 plane_color_ctl = 0; - - if (INTEL_GEN(dev_priv) >= 11) - return plane_color_ctl; - - if (crtc_state->gamma_enable) - plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE; - - if (crtc_state->csc_enable) - plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE; - - return plane_color_ctl; -} - -u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - u32 plane_color_ctl = 0; - - plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; - plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state); - - if (fb->format->is_yuv && !icl_is_hdr_plane(dev_priv, plane->id)) { - switch (plane_state->hw.color_encoding) { - case DRM_COLOR_YCBCR_BT709: - plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; - break; - case DRM_COLOR_YCBCR_BT2020: - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020; - break; - default: - plane_color_ctl |= - PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601; - } - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; - } else if (fb->format->is_yuv) { - plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE; - if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) - plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; - } - - return plane_color_ctl; -} - static int __intel_display_resume(struct drm_device *dev, struct drm_atomic_state *state, @@ -8279,150 +7503,6 @@ static void skl_get_pfit_config(struct intel_crtc_state *crtc_state) scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX); } -static void -skl_get_initial_plane_config(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - enum plane_id plane_id = plane->id; - enum pipe pipe; - u32 val, base, offset, stride_mult, tiling, alpha; - int fourcc, pixel_format; - unsigned int aligned_height; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - - if (!plane->get_hw_state(plane, &pipe)) - return; - - drm_WARN_ON(dev, pipe != crtc->pipe); - - if (crtc_state->bigjoiner) { - drm_dbg_kms(&dev_priv->drm, - "Unsupported bigjoiner configuration for initial FB\n"); - return; - } - - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) { - drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); - return; - } - - fb = &intel_fb->base; - - fb->dev = dev; - - val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id)); - - if (INTEL_GEN(dev_priv) >= 11) - pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK; - else - pixel_format = val & PLANE_CTL_FORMAT_MASK; - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - alpha = intel_de_read(dev_priv, - PLANE_COLOR_CTL(pipe, plane_id)); - alpha &= PLANE_COLOR_ALPHA_MASK; - } else { - alpha = val & PLANE_CTL_ALPHA_MASK; - } - - fourcc = skl_format_to_fourcc(pixel_format, - val & PLANE_CTL_ORDER_RGBX, alpha); - fb->format = drm_format_info(fourcc); - - tiling = val & PLANE_CTL_TILED_MASK; - switch (tiling) { - case PLANE_CTL_TILED_LINEAR: - fb->modifier = DRM_FORMAT_MOD_LINEAR; - break; - case PLANE_CTL_TILED_X: - plane_config->tiling = I915_TILING_X; - fb->modifier = I915_FORMAT_MOD_X_TILED; - break; - case PLANE_CTL_TILED_Y: - plane_config->tiling = I915_TILING_Y; - if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = INTEL_GEN(dev_priv) >= 12 ? - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : - I915_FORMAT_MOD_Y_TILED_CCS; - else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) - fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; - else - fb->modifier = I915_FORMAT_MOD_Y_TILED; - break; - case PLANE_CTL_TILED_YF: - if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) - fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; - else - fb->modifier = I915_FORMAT_MOD_Yf_TILED; - break; - default: - MISSING_CASE(tiling); - goto error; - } - - /* - * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr - * while i915 HW rotation is clockwise, thats why this swapping. - */ - switch (val & PLANE_CTL_ROTATE_MASK) { - case PLANE_CTL_ROTATE_0: - plane_config->rotation = DRM_MODE_ROTATE_0; - break; - case PLANE_CTL_ROTATE_90: - plane_config->rotation = DRM_MODE_ROTATE_270; - break; - case PLANE_CTL_ROTATE_180: - plane_config->rotation = DRM_MODE_ROTATE_180; - break; - case PLANE_CTL_ROTATE_270: - plane_config->rotation = DRM_MODE_ROTATE_90; - break; - } - - if (INTEL_GEN(dev_priv) >= 10 && - val & PLANE_CTL_FLIP_HORIZONTAL) - plane_config->rotation |= DRM_MODE_REFLECT_X; - - /* 90/270 degree rotation would require extra work */ - if (drm_rotation_90_or_270(plane_config->rotation)) - goto error; - - base = intel_de_read(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000; - plane_config->base = base; - - offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id)); - - val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id)); - fb->height = ((val >> 16) & 0xffff) + 1; - fb->width = ((val >> 0) & 0xffff) + 1; - - val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id)); - stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0); - fb->pitches[0] = (val & 0x3ff) * stride_mult; - - aligned_height = intel_fb_align_height(fb, 0, fb->height); - - plane_config->size = fb->pitches[0] * aligned_height; - - drm_dbg_kms(&dev_priv->drm, - "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - crtc->base.name, plane->base.name, fb->width, fb->height, - fb->format->cpp[0] * 8, base, fb->pitches[0], - plane_config->size); - - plane_config->fb = intel_fb; - return; - -error: - kfree(intel_fb); -} - static void ilk_get_pfit_config(struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index c72e41b613495..3c153eb780921 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -52,6 +52,7 @@ struct intel_crtc_state; struct intel_digital_port; struct intel_dp; struct intel_encoder; +struct intel_initial_plane_config; struct intel_load_detect_pipe; struct intel_plane; struct intel_plane_state; @@ -517,7 +518,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes, struct intel_link_m_n *m_n, bool constant_n, bool fec_enable); bool is_ccs_modifier(u64 modifier); -int intel_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); @@ -629,18 +629,7 @@ u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set); void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, int id, int set, enum drm_scaling_filter filter); void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); -u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); -u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state); -u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); -u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state); -u32 skl_plane_stride(const struct intel_plane_state *plane_state, - int plane); -int skl_check_plane_surface(struct intel_plane_state *plane_state); -int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, - int *x, int *y, u32 *offset); -int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); + int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); unsigned int intel_plane_fence_y_offset(const struct intel_plane_state *plane_state); @@ -663,6 +652,18 @@ struct intel_encoder * intel_get_crtc_new_encoder(const struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state); +unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, + int color_plane); +void intel_fb_plane_get_subsampling(int *hsub, int *vsub, + const struct drm_framebuffer *fb, + int color_plane); +u32 intel_plane_adjust_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane, + u32 old_offset, u32 new_offset); +unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane); +unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane); + /* modesetting */ void intel_modeset_init_hw(struct drm_i915_private *i915); int intel_modeset_init_noirq(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 307ff4b771f44..6183f2f0424bf 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1945,4 +1946,30 @@ static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, return dev_priv->fdi_pll_freq; } +static inline bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) +{ + if (!is_ccs_modifier(fb->modifier)) + return false; + + return plane >= fb->format->num_planes / 2; +} + +static inline bool is_gen12_ccs_modifier(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; +} + +static inline bool is_gen12_ccs_plane(const struct drm_framebuffer *fb, int plane) +{ + return is_gen12_ccs_modifier(fb->modifier) && is_ccs_plane(fb, plane); +} + +static inline bool is_gen12_ccs_cc_plane(const struct drm_framebuffer *fb, int plane) +{ + return fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC && + plane == 2; +} + #endif /* __INTEL_DISPLAY_TYPES_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 28423356d53b5..bf214d0e2dec0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -32,6 +32,7 @@ #include "intel_hdmi.h" #include "intel_psr.h" #include "intel_sprite.h" +#include "skl_universal_plane.h" /** * DOC: Panel Self Refresh (PSR/SRD) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 26025251b038a..93f3afc245b99 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -376,212 +376,7 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } -static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) -{ - if (HAS_D12_PLANE_MINIMIZATION(i915)) - return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); - else - return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); -} - -bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - return INTEL_GEN(dev_priv) >= 11 && - icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id); -} - -bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) -{ - return INTEL_GEN(dev_priv) >= 11 && - icl_hdr_plane_mask() & BIT(plane_id); -} - -static void -skl_plane_ratio(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - unsigned int *num, unsigned int *den) -{ - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - - if (fb->format->cpp[0] == 8) { - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - *num = 10; - *den = 8; - } else { - *num = 9; - *den = 8; - } - } else { - *num = 1; - *den = 1; - } -} - -static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); - unsigned int num, den; - unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); - - skl_plane_ratio(crtc_state, plane_state, &num, &den); - - /* two pixels per clock on glk+ */ - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - den *= 2; - - return DIV_ROUND_UP(pixel_rate * num, den); -} - -static int skl_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - int cpp = fb->format->cpp[color_plane]; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - /* - * Validated limit is 4k, but has 5k should - * work apart from the following features: - * - Ytile (already limited to 4k) - * - FP16 (already limited to 4k) - * - render compression (already limited to 4k) - * - KVMR sprite and cursor (don't care) - * - horizontal panning (TODO verify this) - * - pipe and plane scaling (TODO verify this) - */ - if (cpp == 8) - return 4096; - else - return 5120; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - /* FIXME AUX plane? */ - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - if (cpp == 8) - return 2048; - else - return 4096; - default: - MISSING_CASE(fb->modifier); - return 2048; - } -} - -static int glk_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - int cpp = fb->format->cpp[color_plane]; - - switch (fb->modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - if (cpp == 8) - return 4096; - else - return 5120; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - /* FIXME AUX plane? */ - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - if (cpp == 8) - return 2048; - else - return 5120; - default: - MISSING_CASE(fb->modifier); - return 2048; - } -} - -static int icl_plane_min_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - /* Wa_14011264657, Wa_14011050563: gen11+ */ - switch (fb->format->format) { - case DRM_FORMAT_C8: - return 18; - case DRM_FORMAT_RGB565: - return 10; - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - return 6; - case DRM_FORMAT_NV12: - return 20; - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - return 12; - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - return 4; - default: - return 1; - } -} - -static int icl_plane_max_width(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 5120; -} - -static int skl_plane_max_height(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 4096; -} - -static int icl_plane_max_height(const struct drm_framebuffer *fb, - int color_plane, - unsigned int rotation) -{ - return 4320; -} - -static unsigned int -skl_plane_max_stride(struct intel_plane *plane, - u32 pixel_format, u64 modifier, - unsigned int rotation) -{ - const struct drm_format_info *info = drm_format_info(pixel_format); - int cpp = info->cpp[0]; - - /* - * "The stride in bytes must not exceed the - * of the size of 8K pixels and 32K bytes." - */ - if (drm_rotation_90_or_270(rotation)) - return min(8192, 32768 / cpp); - else - return min(8192 * cpp, 32768); -} - -static void +void skl_program_scaler(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) @@ -643,317 +438,6 @@ skl_program_scaler(struct intel_plane *plane, (crtc_w << 16) | crtc_h); } -/* Preoffset values for YUV to RGB Conversion */ -#define PREOFF_YUV_TO_RGB_HI 0x1800 -#define PREOFF_YUV_TO_RGB_ME 0x0000 -#define PREOFF_YUV_TO_RGB_LO 0x1800 - -#define ROFF(x) (((x) & 0xffff) << 16) -#define GOFF(x) (((x) & 0xffff) << 0) -#define BOFF(x) (((x) & 0xffff) << 16) - -/* - * Programs the input color space conversion stage for ICL HDR planes. - * Note that it is assumed that this stage always happens after YUV - * range correction. Thus, the input to this stage is assumed to be - * in full-range YCbCr. - */ -static void -icl_program_input_csc(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - enum plane_id plane_id = plane->id; - - static const u16 input_csc_matrix[][9] = { - /* - * BT.601 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.371, - * 1.000, -0.336, -0.698, - * 1.000, 1.732, 0.0000] - */ - [DRM_COLOR_YCBCR_BT601] = { - 0x7AF8, 0x7800, 0x0, - 0x8B28, 0x7800, 0x9AC0, - 0x0, 0x7800, 0x7DD8, - }, - /* - * BT.709 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.574, - * 1.000, -0.187, -0.468, - * 1.000, 1.855, 0.0000] - */ - [DRM_COLOR_YCBCR_BT709] = { - 0x7C98, 0x7800, 0x0, - 0x9EF8, 0x7800, 0xAC00, - 0x0, 0x7800, 0x7ED8, - }, - /* - * BT.2020 full range YCbCr -> full range RGB - * The matrix required is : - * [1.000, 0.000, 1.474, - * 1.000, -0.1645, -0.5713, - * 1.000, 1.8814, 0.0000] - */ - [DRM_COLOR_YCBCR_BT2020] = { - 0x7BC8, 0x7800, 0x0, - 0x8928, 0x7800, 0xAA88, - 0x0, 0x7800, 0x7F10, - }, - }; - const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding]; - - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), - ROFF(csc[0]) | GOFF(csc[1])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1), - BOFF(csc[2])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2), - ROFF(csc[3]) | GOFF(csc[4])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3), - BOFF(csc[5])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4), - ROFF(csc[6]) | GOFF(csc[7])); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5), - BOFF(csc[8])); - - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0), - PREOFF_YUV_TO_RGB_HI); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), - PREOFF_YUV_TO_RGB_ME); - intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2), - PREOFF_YUV_TO_RGB_LO); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0); - intel_de_write_fw(dev_priv, - PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0); -} - -static void -skl_plane_async_flip(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - bool async_flip) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - unsigned long irqflags; - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - u32 surf_addr = plane_state->color_plane[0].offset; - u32 plane_ctl = plane_state->ctl; - - plane_ctl |= skl_plane_ctl_crtc(crtc_state); - - if (async_flip) - plane_ctl |= PLANE_CTL_ASYNC_FLIP; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static void -skl_program_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 surf_addr = plane_state->color_plane[color_plane].offset; - u32 stride = skl_plane_stride(plane_state, color_plane); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int aux_plane = intel_main_to_aux_plane(fb, color_plane); - int crtc_x = plane_state->uapi.dst.x1; - int crtc_y = plane_state->uapi.dst.y1; - u32 x = plane_state->color_plane[color_plane].x; - u32 y = plane_state->color_plane[color_plane].y; - u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; - u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; - u8 alpha = plane_state->hw.alpha >> 8; - u32 plane_color_ctl = 0, aux_dist = 0; - unsigned long irqflags; - u32 keymsk, keymax; - u32 plane_ctl = plane_state->ctl; - - plane_ctl |= skl_plane_ctl_crtc(crtc_state); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - plane_color_ctl = plane_state->color_ctl | - glk_plane_color_ctl_crtc(crtc_state); - - /* Sizes are 0 based */ - src_w--; - src_h--; - - keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha); - - keymsk = key->channel_mask & 0x7ffffff; - if (alpha < 0xff) - keymsk |= PLANE_KEYMSK_ALPHA_ENABLE; - - /* The scaler will handle the output position */ - if (plane_state->scaler_id >= 0) { - crtc_x = 0; - crtc_y = 0; - } - - if (aux_plane) { - aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr; - - if (INTEL_GEN(dev_priv) < 12) - aux_dist |= skl_plane_stride(plane_state, aux_plane); - } - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride); - intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), - (crtc_y << 16) | crtc_x); - intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), - (src_h << 16) | src_w); - - intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist); - - if (icl_is_hdr_plane(dev_priv, plane_id)) - intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), - plane_state->cus_ctl); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), - plane_color_ctl); - - if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id)) - icl_program_input_csc(plane, crtc_state, plane_state); - - if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC) - intel_uncore_write64_fw(&dev_priv->uncore, - PLANE_CC_VAL(pipe, plane_id), plane_state->ccval); - - skl_write_plane_wm(plane, crtc_state); - - intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), - key->min_value); - intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk); - intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax); - - intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), - (y << 16) | x); - - if (INTEL_GEN(dev_priv) < 11) - intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), - (plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x); - - if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) - intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); - - /* - * The control register self-arms if the plane was previously - * disabled. Try to make the plane enable atomic by writing - * the control register just before the surface register. - */ - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), - intel_plane_ggtt_offset(plane_state) + surf_addr); - - if (plane_state->scaler_id >= 0) - skl_program_scaler(plane, crtc_state, plane_state); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static void -skl_update_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - int color_plane = 0; - - if (plane_state->planar_linked_plane && !plane_state->planar_slave) - /* Program the UV plane on planar master */ - color_plane = 1; - - skl_program_plane(plane, crtc_state, plane_state, color_plane); -} -static void -skl_disable_plane(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum plane_id plane_id = plane->id; - enum pipe pipe = plane->pipe; - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - if (icl_is_hdr_plane(dev_priv, plane_id)) - intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); - - skl_write_plane_wm(plane, crtc_state); - - intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); - intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -static bool -skl_plane_get_hw_state(struct intel_plane *plane, - enum pipe *pipe) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum intel_display_power_domain power_domain; - enum plane_id plane_id = plane->id; - intel_wakeref_t wakeref; - bool ret; - - power_domain = POWER_DOMAIN_PIPE(plane->pipe); - wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); - if (!wakeref) - return false; - - ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; - - *pipe = plane->pipe; - - intel_display_power_put(dev_priv, power_domain, wakeref); - - return ret; -} - -static void -skl_plane_enable_flip_done(struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - spin_lock_irq(&i915->irq_lock); - bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); - spin_unlock_irq(&i915->irq_lock); -} - -static void -skl_plane_disable_flip_done(struct intel_plane *plane) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - spin_lock_irq(&i915->irq_lock); - bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); - spin_unlock_irq(&i915->irq_lock); -} - static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ @@ -2297,253 +1781,19 @@ vlv_sprite_check(struct intel_crtc_state *crtc_state, return 0; } -static bool intel_format_is_p01x(u32 format) +static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) { - switch (format) { - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - return true; - default: - return false; - } + return INTEL_GEN(dev_priv) >= 9; } -static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static void intel_plane_set_ckey(struct intel_plane_state *plane_state, + const struct drm_intel_sprite_colorkey *set) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - struct drm_format_name_buf format_name; + struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - if (!fb) - return 0; - - if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) && - is_ccs_modifier(fb->modifier)) { - drm_dbg_kms(&dev_priv->drm, - "RC support only with 0/180 degree rotation (%x)\n", - rotation); - return -EINVAL; - } - - if (rotation & DRM_MODE_REFLECT_X && - fb->modifier == DRM_FORMAT_MOD_LINEAR) { - drm_dbg_kms(&dev_priv->drm, - "horizontal flip is not supported with linear surface formats\n"); - return -EINVAL; - } - - if (drm_rotation_90_or_270(rotation)) { - if (fb->modifier != I915_FORMAT_MOD_Y_TILED && - fb->modifier != I915_FORMAT_MOD_Yf_TILED) { - drm_dbg_kms(&dev_priv->drm, - "Y/Yf tiling required for 90/270!\n"); - return -EINVAL; - } - - /* - * 90/270 is not allowed with RGB64 16:16:16:16 and - * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards. - */ - switch (fb->format->format) { - case DRM_FORMAT_RGB565: - if (INTEL_GEN(dev_priv) >= 11) - break; - fallthrough; - case DRM_FORMAT_C8: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - drm_dbg_kms(&dev_priv->drm, - "Unsupported pixel format %s for 90/270!\n", - drm_get_format_name(fb->format->format, - &format_name)); - return -EINVAL; - default: - break; - } - } - - /* Y-tiling is not supported in IF-ID Interlace mode */ - if (crtc_state->hw.enable && - crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE && - (fb->modifier == I915_FORMAT_MOD_Y_TILED || - fb->modifier == I915_FORMAT_MOD_Yf_TILED || - fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) { - drm_dbg_kms(&dev_priv->drm, - "Y/Yf tiling not supported in IF-ID mode\n"); - return -EINVAL; - } - - /* Wa_1606054188:tgl,adl-s */ - if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) && - plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE && - intel_format_is_p01x(fb->format->format)) { - drm_dbg_kms(&dev_priv->drm, - "Source color keying not supported with P01x formats\n"); - return -EINVAL; - } - - return 0; -} - -static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = - to_i915(plane_state->uapi.plane->dev); - int crtc_x = plane_state->uapi.dst.x1; - int crtc_w = drm_rect_width(&plane_state->uapi.dst); - int pipe_src_w = crtc_state->pipe_src_w; - - /* - * Display WA #1175: cnl,glk - * Planes other than the cursor may cause FIFO underflow and display - * corruption if starting less than 4 pixels from the right edge of - * the screen. - * Besides the above WA fix the similar problem, where planes other - * than the cursor ending less than 4 pixels from the left edge of the - * screen may cause FIFO underflow and display corruption. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && - (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { - drm_dbg_kms(&dev_priv->drm, - "requested plane X %s position %d invalid (valid range %d-%d)\n", - crtc_x + crtc_w < 4 ? "end" : "start", - crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x, - 4, pipe_src_w - 4); - return -ERANGE; - } - - return 0; -} - -static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state) -{ - const struct drm_framebuffer *fb = plane_state->hw.fb; - unsigned int rotation = plane_state->hw.rotation; - int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; - - /* Display WA #1106 */ - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - src_w & 3 && - (rotation == DRM_MODE_ROTATE_270 || - rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) { - DRM_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n"); - return -EINVAL; - } - - return 0; -} - -static int skl_plane_max_scale(struct drm_i915_private *dev_priv, - const struct drm_framebuffer *fb) -{ - /* - * We don't yet know the final source width nor - * whether we can use the HQ scaler mode. Assume - * the best case. - * FIXME need to properly check this later. - */ - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) || - !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - return 0x30000 - 1; - else - return 0x20000 - 1; -} - -static int skl_plane_check(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; - int ret; - - ret = skl_plane_check_fb(crtc_state, plane_state); - if (ret) - return ret; - - /* use scaler when colorkey is not required */ - if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { - min_scale = 1; - max_scale = skl_plane_max_scale(dev_priv, fb); - } - - ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, - min_scale, max_scale, true); - if (ret) - return ret; - - ret = skl_check_plane_surface(plane_state); - if (ret) - return ret; - - if (!plane_state->uapi.visible) - return 0; - - ret = skl_plane_check_dst_coordinates(crtc_state, plane_state); - if (ret) - return ret; - - ret = intel_plane_check_src_coordinates(plane_state); - if (ret) - return ret; - - ret = skl_plane_check_nv12_rotation(plane_state); - if (ret) - return ret; - - /* HW only has 8 bits pixel precision, disable plane if invisible */ - if (!(plane_state->hw.alpha >> 8)) - plane_state->uapi.visible = false; - - plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - plane_state->color_ctl = glk_plane_color_ctl(crtc_state, - plane_state); - - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - icl_is_hdr_plane(dev_priv, plane->id)) - /* Enable and use MPEG-2 chroma siting */ - plane_state->cus_ctl = PLANE_CUS_ENABLE | - PLANE_CUS_HPHASE_0 | - PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25; - else - plane_state->cus_ctl = 0; - - return 0; -} - -static bool has_dst_key_in_primary_plane(struct drm_i915_private *dev_priv) -{ - return INTEL_GEN(dev_priv) >= 9; -} - -static void intel_plane_set_ckey(struct intel_plane_state *plane_state, - const struct drm_intel_sprite_colorkey *set) -{ - struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - - *key = *set; + *key = *set; /* * We want src key enabled on the @@ -2708,186 +1958,6 @@ static const u32 chv_pipe_b_sprite_formats[] = { DRM_FORMAT_VYUY, }; -static const u32 skl_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_XYUV8888, -}; - -static const u32 skl_planar_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_XYUV8888, -}; - -static const u32 glk_planar_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, -}; - -static const u32 icl_sdr_y_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u32 icl_sdr_uv_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u32 icl_hdr_plane_formats[] = { - DRM_FORMAT_C8, - DRM_FORMAT_RGB565, - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_ABGR8888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_XBGR2101010, - DRM_FORMAT_ARGB2101010, - DRM_FORMAT_ABGR2101010, - DRM_FORMAT_XRGB16161616F, - DRM_FORMAT_XBGR16161616F, - DRM_FORMAT_ARGB16161616F, - DRM_FORMAT_ABGR16161616F, - DRM_FORMAT_YUYV, - DRM_FORMAT_YVYU, - DRM_FORMAT_UYVY, - DRM_FORMAT_VYUY, - DRM_FORMAT_NV12, - DRM_FORMAT_P010, - DRM_FORMAT_P012, - DRM_FORMAT_P016, - DRM_FORMAT_Y210, - DRM_FORMAT_Y212, - DRM_FORMAT_Y216, - DRM_FORMAT_XYUV8888, - DRM_FORMAT_XVYU2101010, - DRM_FORMAT_XVYU12_16161616, - DRM_FORMAT_XVYU16161616, -}; - -static const u64 skl_plane_format_modifiers_noccs[] = { - I915_FORMAT_MOD_Yf_TILED, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 skl_plane_format_modifiers_ccs[] = { - I915_FORMAT_MOD_Yf_TILED_CCS, - I915_FORMAT_MOD_Y_TILED_CCS, - I915_FORMAT_MOD_Yf_TILED, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 gen12_plane_format_modifiers_mc_ccs[] = { - I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - -static const u64 gen12_plane_format_modifiers_rc_ccs[] = { - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, - I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, - I915_FORMAT_MOD_Y_TILED, - I915_FORMAT_MOD_X_TILED, - DRM_FORMAT_MOD_LINEAR, - DRM_FORMAT_MOD_INVALID -}; - static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane, u32 format, u64 modifier) { @@ -2980,150 +2050,6 @@ static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane, } } -static bool skl_plane_format_mod_supported(struct drm_plane *_plane, - u32 format, u64 modifier) -{ - struct intel_plane *plane = to_intel_plane(_plane); - - switch (modifier) { - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Yf_TILED: - break; - case I915_FORMAT_MOD_Y_TILED_CCS: - case I915_FORMAT_MOD_Yf_TILED_CCS: - if (!plane->has_ccs) - return false; - break; - default: - return false; - } - - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - if (is_ccs_modifier(modifier)) - return true; - fallthrough; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - case DRM_FORMAT_XVYU2101010: - if (modifier == I915_FORMAT_MOD_Yf_TILED) - return true; - fallthrough; - case DRM_FORMAT_C8: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - if (modifier == DRM_FORMAT_MOD_LINEAR || - modifier == I915_FORMAT_MOD_X_TILED || - modifier == I915_FORMAT_MOD_Y_TILED) - return true; - fallthrough; - default: - return false; - } -} - -static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */ - if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) || - IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0)) - return false; - - return plane_id < PLANE_SPRITE4; -} - -static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, - u32 format, u64 modifier) -{ - struct drm_i915_private *dev_priv = to_i915(_plane->dev); - struct intel_plane *plane = to_intel_plane(_plane); - - switch (modifier) { - case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: - if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id)) - return false; - fallthrough; - case DRM_FORMAT_MOD_LINEAR: - case I915_FORMAT_MOD_X_TILED: - case I915_FORMAT_MOD_Y_TILED: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: - case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: - break; - default: - return false; - } - - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - if (is_ccs_modifier(modifier)) - return true; - fallthrough; - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) - return true; - fallthrough; - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_C8: - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - if (modifier == DRM_FORMAT_MOD_LINEAR || - modifier == I915_FORMAT_MOD_X_TILED || - modifier == I915_FORMAT_MOD_Y_TILED) - return true; - fallthrough; - default: - return false; - } -} - static const struct drm_plane_funcs g4x_sprite_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -3151,257 +2077,6 @@ static const struct drm_plane_funcs vlv_sprite_funcs = { .format_mod_supported = vlv_sprite_format_mod_supported, }; -static const struct drm_plane_funcs skl_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = skl_plane_format_mod_supported, -}; - -static const struct drm_plane_funcs gen12_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = intel_plane_destroy, - .atomic_duplicate_state = intel_plane_duplicate_state, - .atomic_destroy_state = intel_plane_destroy_state, - .format_mod_supported = gen12_plane_format_mod_supported, -}; - -static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - if (!HAS_FBC(dev_priv)) - return false; - - return pipe == PIPE_A && plane_id == PLANE_PRIMARY; -} - -static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - /* Display WA #0870: skl, bxt */ - if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) - return false; - - if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) - return false; - - if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) - return false; - - return true; -} - -static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { - *num_formats = ARRAY_SIZE(skl_planar_formats); - return skl_planar_formats; - } else { - *num_formats = ARRAY_SIZE(skl_plane_formats); - return skl_plane_formats; - } -} - -static const u32 *glk_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { - *num_formats = ARRAY_SIZE(glk_planar_formats); - return glk_planar_formats; - } else { - *num_formats = ARRAY_SIZE(skl_plane_formats); - return skl_plane_formats; - } -} - -static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id, - int *num_formats) -{ - if (icl_is_hdr_plane(dev_priv, plane_id)) { - *num_formats = ARRAY_SIZE(icl_hdr_plane_formats); - return icl_hdr_plane_formats; - } else if (icl_is_nv12_y_plane(dev_priv, plane_id)) { - *num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats); - return icl_sdr_y_plane_formats; - } else { - *num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats); - return icl_sdr_uv_plane_formats; - } -} - -static const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv, - enum plane_id plane_id) -{ - if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) - return gen12_plane_format_modifiers_mc_ccs; - else - return gen12_plane_format_modifiers_rc_ccs; -} - -static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - if (plane_id == PLANE_CURSOR) - return false; - - if (INTEL_GEN(dev_priv) >= 10) - return true; - - if (IS_GEMINILAKE(dev_priv)) - return pipe != PIPE_C; - - return pipe != PIPE_C && - (plane_id == PLANE_PRIMARY || - plane_id == PLANE_SPRITE0); -} - -struct intel_plane * -skl_universal_plane_create(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id) -{ - const struct drm_plane_funcs *plane_funcs; - struct intel_plane *plane; - enum drm_plane_type plane_type; - unsigned int supported_rotations; - unsigned int supported_csc; - const u64 *modifiers; - const u32 *formats; - int num_formats; - int ret; - - plane = intel_plane_alloc(); - if (IS_ERR(plane)) - return plane; - - plane->pipe = pipe; - plane->id = plane_id; - plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id); - - plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id); - if (plane->has_fbc) { - struct intel_fbc *fbc = &dev_priv->fbc; - - fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; - } - - if (INTEL_GEN(dev_priv) >= 11) { - plane->min_width = icl_plane_min_width; - plane->max_width = icl_plane_max_width; - plane->max_height = icl_plane_max_height; - } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { - plane->max_width = glk_plane_max_width; - plane->max_height = skl_plane_max_height; - } else { - plane->max_width = skl_plane_max_width; - plane->max_height = skl_plane_max_height; - } - - plane->max_stride = skl_plane_max_stride; - plane->update_plane = skl_update_plane; - plane->disable_plane = skl_disable_plane; - plane->get_hw_state = skl_plane_get_hw_state; - plane->check_plane = skl_plane_check; - plane->min_cdclk = skl_plane_min_cdclk; - - if (plane_id == PLANE_PRIMARY) { - plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 9, 10); - plane->async_flip = skl_plane_async_flip; - plane->enable_flip_done = skl_plane_enable_flip_done; - plane->disable_flip_done = skl_plane_disable_flip_done; - } - - if (INTEL_GEN(dev_priv) >= 11) - formats = icl_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - formats = glk_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - else - formats = skl_get_plane_formats(dev_priv, pipe, - plane_id, &num_formats); - - plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id); - if (INTEL_GEN(dev_priv) >= 12) { - modifiers = gen12_get_plane_modifiers(dev_priv, plane_id); - plane_funcs = &gen12_plane_funcs; - } else { - if (plane->has_ccs) - modifiers = skl_plane_format_modifiers_ccs; - else - modifiers = skl_plane_format_modifiers_noccs; - plane_funcs = &skl_plane_funcs; - } - - if (plane_id == PLANE_PRIMARY) - plane_type = DRM_PLANE_TYPE_PRIMARY; - else - plane_type = DRM_PLANE_TYPE_OVERLAY; - - ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, - 0, plane_funcs, - formats, num_formats, modifiers, - plane_type, - "plane %d%c", plane_id + 1, - pipe_name(pipe)); - if (ret) - goto fail; - - supported_rotations = - DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | - DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; - - if (INTEL_GEN(dev_priv) >= 10) - supported_rotations |= DRM_MODE_REFLECT_X; - - drm_plane_create_rotation_property(&plane->base, - DRM_MODE_ROTATE_0, - supported_rotations); - - supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020); - - drm_plane_create_color_properties(&plane->base, - supported_csc, - BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | - BIT(DRM_COLOR_YCBCR_FULL_RANGE), - DRM_COLOR_YCBCR_BT709, - DRM_COLOR_YCBCR_LIMITED_RANGE); - - drm_plane_create_alpha_property(&plane->base); - drm_plane_create_blend_mode_property(&plane->base, - BIT(DRM_MODE_BLEND_PIXEL_NONE) | - BIT(DRM_MODE_BLEND_PREMULTI) | - BIT(DRM_MODE_BLEND_COVERAGE)); - - drm_plane_create_zpos_immutable_property(&plane->base, plane_id); - - if (INTEL_GEN(dev_priv) >= 12) - drm_plane_enable_fb_damage_clips(&plane->base); - - if (INTEL_GEN(dev_priv) >= 10) - drm_plane_create_scaling_filter_property(&plane->base, - BIT(DRM_SCALING_FILTER_DEFAULT) | - BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); - - drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); - - return plane; - -fail: - intel_plane_free(plane); - - return ERR_PTR(ret); -} - struct intel_plane * intel_sprite_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe, int sprite) @@ -3414,10 +2089,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, int num_formats; int ret, zpos; - if (INTEL_GEN(dev_priv) >= 9) - return skl_universal_plane_create(dev_priv, pipe, - PLANE_SPRITE0 + sprite); - plane = intel_plane_alloc(); if (IS_ERR(plane)) return plane; diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 76126dd8d584f..418897f953fc2 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -38,9 +38,6 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state); int intel_plane_check_stride(const struct intel_plane_state *plane_state); int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state); int chv_plane_check_rotation(const struct intel_plane_state *plane_state); -struct intel_plane * -skl_universal_plane_create(struct drm_i915_private *dev_priv, - enum pipe pipe, enum plane_id plane_id); static inline u8 icl_hdr_plane_mask(void) { @@ -59,4 +56,7 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); +void skl_program_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state); #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c new file mode 100644 index 0000000000000..29c2e3693e8be --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -0,0 +1,2265 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ + +#include +#include +#include +#include + +#include "i915_drv.h" +#include "intel_atomic_plane.h" +#include "intel_display_types.h" +#include "intel_pm.h" +#include "intel_psr.h" +#include "intel_sprite.h" +#include "skl_universal_plane.h" + +static const u32 skl_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_XYUV8888, +}; + +static const u32 skl_planar_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_XYUV8888, +}; + +static const u32 glk_planar_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, +}; + +static const u32 icl_sdr_y_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u32 icl_sdr_uv_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u32 icl_hdr_plane_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_ARGB2101010, + DRM_FORMAT_ABGR2101010, + DRM_FORMAT_XRGB16161616F, + DRM_FORMAT_XBGR16161616F, + DRM_FORMAT_ARGB16161616F, + DRM_FORMAT_ABGR16161616F, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, + DRM_FORMAT_NV12, + DRM_FORMAT_P010, + DRM_FORMAT_P012, + DRM_FORMAT_P016, + DRM_FORMAT_Y210, + DRM_FORMAT_Y212, + DRM_FORMAT_Y216, + DRM_FORMAT_XYUV8888, + DRM_FORMAT_XVYU2101010, + DRM_FORMAT_XVYU12_16161616, + DRM_FORMAT_XVYU16161616, +}; + +static const u64 skl_plane_format_modifiers_noccs[] = { + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 skl_plane_format_modifiers_ccs[] = { + I915_FORMAT_MOD_Yf_TILED_CCS, + I915_FORMAT_MOD_Y_TILED_CCS, + I915_FORMAT_MOD_Yf_TILED, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 gen12_plane_format_modifiers_mc_ccs[] = { + I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static const u64 gen12_plane_format_modifiers_rc_ccs[] = { + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS, + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC, + I915_FORMAT_MOD_Y_TILED, + I915_FORMAT_MOD_X_TILED, + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha) +{ + switch (format) { + case PLANE_CTL_FORMAT_RGB_565: + return DRM_FORMAT_RGB565; + case PLANE_CTL_FORMAT_NV12: + return DRM_FORMAT_NV12; + case PLANE_CTL_FORMAT_XYUV: + return DRM_FORMAT_XYUV8888; + case PLANE_CTL_FORMAT_P010: + return DRM_FORMAT_P010; + case PLANE_CTL_FORMAT_P012: + return DRM_FORMAT_P012; + case PLANE_CTL_FORMAT_P016: + return DRM_FORMAT_P016; + case PLANE_CTL_FORMAT_Y210: + return DRM_FORMAT_Y210; + case PLANE_CTL_FORMAT_Y212: + return DRM_FORMAT_Y212; + case PLANE_CTL_FORMAT_Y216: + return DRM_FORMAT_Y216; + case PLANE_CTL_FORMAT_Y410: + return DRM_FORMAT_XVYU2101010; + case PLANE_CTL_FORMAT_Y412: + return DRM_FORMAT_XVYU12_16161616; + case PLANE_CTL_FORMAT_Y416: + return DRM_FORMAT_XVYU16161616; + default: + case PLANE_CTL_FORMAT_XRGB_8888: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR8888; + else + return DRM_FORMAT_XBGR8888; + } else { + if (alpha) + return DRM_FORMAT_ARGB8888; + else + return DRM_FORMAT_XRGB8888; + } + case PLANE_CTL_FORMAT_XRGB_2101010: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR2101010; + else + return DRM_FORMAT_XBGR2101010; + } else { + if (alpha) + return DRM_FORMAT_ARGB2101010; + else + return DRM_FORMAT_XRGB2101010; + } + case PLANE_CTL_FORMAT_XRGB_16161616F: + if (rgb_order) { + if (alpha) + return DRM_FORMAT_ABGR16161616F; + else + return DRM_FORMAT_XBGR16161616F; + } else { + if (alpha) + return DRM_FORMAT_ARGB16161616F; + else + return DRM_FORMAT_XRGB16161616F; + } + } +} + +static u8 icl_nv12_y_plane_mask(struct drm_i915_private *i915) +{ + if (HAS_D12_PLANE_MINIMIZATION(i915)) + return BIT(PLANE_SPRITE2) | BIT(PLANE_SPRITE3); + else + return BIT(PLANE_SPRITE4) | BIT(PLANE_SPRITE5); +} + +bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + return INTEL_GEN(dev_priv) >= 11 && + icl_nv12_y_plane_mask(dev_priv) & BIT(plane_id); +} + +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id) +{ + return INTEL_GEN(dev_priv) >= 11 && + icl_hdr_plane_mask() & BIT(plane_id); +} + +static void +skl_plane_ratio(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + unsigned int *num, unsigned int *den) +{ + struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + + if (fb->format->cpp[0] == 8) { + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + *num = 10; + *den = 8; + } else { + *num = 9; + *den = 8; + } + } else { + *num = 1; + *den = 1; + } +} + +static int skl_plane_min_cdclk(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); + unsigned int num, den; + unsigned int pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state); + + skl_plane_ratio(crtc_state, plane_state, &num, &den); + + /* two pixels per clock on glk+ */ + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + den *= 2; + + return DIV_ROUND_UP(pixel_rate * num, den); +} + +static int skl_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + int cpp = fb->format->cpp[color_plane]; + + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + /* + * Validated limit is 4k, but has 5k should + * work apart from the following features: + * - Ytile (already limited to 4k) + * - FP16 (already limited to 4k) + * - render compression (already limited to 4k) + * - KVMR sprite and cursor (don't care) + * - horizontal panning (TODO verify this) + * - pipe and plane scaling (TODO verify this) + */ + if (cpp == 8) + return 4096; + else + return 5120; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + /* FIXME AUX plane? */ + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + if (cpp == 8) + return 2048; + else + return 4096; + default: + MISSING_CASE(fb->modifier); + return 2048; + } +} + +static int glk_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + int cpp = fb->format->cpp[color_plane]; + + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + if (cpp == 8) + return 4096; + else + return 5120; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + /* FIXME AUX plane? */ + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + if (cpp == 8) + return 2048; + else + return 5120; + default: + MISSING_CASE(fb->modifier); + return 2048; + } +} + +static int icl_plane_min_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + /* Wa_14011264657, Wa_14011050563: gen11+ */ + switch (fb->format->format) { + case DRM_FORMAT_C8: + return 18; + case DRM_FORMAT_RGB565: + return 10; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + return 6; + case DRM_FORMAT_NV12: + return 20; + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return 12; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + return 4; + default: + return 1; + } +} + +static int icl_plane_max_width(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 5120; +} + +static int skl_plane_max_height(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 4096; +} + +static int icl_plane_max_height(const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + return 4320; +} + +static unsigned int +skl_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + const struct drm_format_info *info = drm_format_info(pixel_format); + int cpp = info->cpp[0]; + + /* + * "The stride in bytes must not exceed the + * of the size of 8K pixels and 32K bytes." + */ + if (drm_rotation_90_or_270(rotation)) + return min(8192, 32768 / cpp); + else + return min(8192 * cpp, 32768); +} + + +/* Preoffset values for YUV to RGB Conversion */ +#define PREOFF_YUV_TO_RGB_HI 0x1800 +#define PREOFF_YUV_TO_RGB_ME 0x0000 +#define PREOFF_YUV_TO_RGB_LO 0x1800 + +#define ROFF(x) (((x) & 0xffff) << 16) +#define GOFF(x) (((x) & 0xffff) << 0) +#define BOFF(x) (((x) & 0xffff) << 16) + +/* + * Programs the input color space conversion stage for ICL HDR planes. + * Note that it is assumed that this stage always happens after YUV + * range correction. Thus, the input to this stage is assumed to be + * in full-range YCbCr. + */ +static void +icl_program_input_csc(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + enum plane_id plane_id = plane->id; + + static const u16 input_csc_matrix[][9] = { + /* + * BT.601 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.371, + * 1.000, -0.336, -0.698, + * 1.000, 1.732, 0.0000] + */ + [DRM_COLOR_YCBCR_BT601] = { + 0x7AF8, 0x7800, 0x0, + 0x8B28, 0x7800, 0x9AC0, + 0x0, 0x7800, 0x7DD8, + }, + /* + * BT.709 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.574, + * 1.000, -0.187, -0.468, + * 1.000, 1.855, 0.0000] + */ + [DRM_COLOR_YCBCR_BT709] = { + 0x7C98, 0x7800, 0x0, + 0x9EF8, 0x7800, 0xAC00, + 0x0, 0x7800, 0x7ED8, + }, + /* + * BT.2020 full range YCbCr -> full range RGB + * The matrix required is : + * [1.000, 0.000, 1.474, + * 1.000, -0.1645, -0.5713, + * 1.000, 1.8814, 0.0000] + */ + [DRM_COLOR_YCBCR_BT2020] = { + 0x7BC8, 0x7800, 0x0, + 0x8928, 0x7800, 0xAA88, + 0x0, 0x7800, 0x7F10, + }, + }; + const u16 *csc = input_csc_matrix[plane_state->hw.color_encoding]; + + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 0), + ROFF(csc[0]) | GOFF(csc[1])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 1), + BOFF(csc[2])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 2), + ROFF(csc[3]) | GOFF(csc[4])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 3), + BOFF(csc[5])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 4), + ROFF(csc[6]) | GOFF(csc[7])); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_COEFF(pipe, plane_id, 5), + BOFF(csc[8])); + + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 0), + PREOFF_YUV_TO_RGB_HI); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 1), + PREOFF_YUV_TO_RGB_ME); + intel_de_write_fw(dev_priv, PLANE_INPUT_CSC_PREOFF(pipe, plane_id, 2), + PREOFF_YUV_TO_RGB_LO); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 0), 0x0); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 1), 0x0); + intel_de_write_fw(dev_priv, + PLANE_INPUT_CSC_POSTOFF(pipe, plane_id, 2), 0x0); +} + +static bool is_surface_linear(const struct drm_framebuffer *fb, int color_plane) +{ + return fb->modifier == DRM_FORMAT_MOD_LINEAR || + is_gen12_ccs_plane(fb, color_plane); +} + +static unsigned int skl_plane_stride_mult(const struct drm_framebuffer *fb, + int color_plane, unsigned int rotation) +{ + /* + * The stride is either expressed as a multiple of 64 bytes chunks for + * linear buffers or in number of tiles for tiled buffers. + */ + if (is_surface_linear(fb, color_plane)) + return 64; + else if (drm_rotation_90_or_270(rotation)) + return intel_tile_height(fb, color_plane); + else + return intel_tile_width_bytes(fb, color_plane); +} + +static u32 skl_plane_stride(const struct intel_plane_state *plane_state, + int color_plane) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + u32 stride = plane_state->color_plane[color_plane].stride; + + if (color_plane >= fb->format->num_planes) + return 0; + + return stride / skl_plane_stride_mult(fb, color_plane, rotation); +} + +static void +skl_disable_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + if (icl_is_hdr_plane(dev_priv, plane_id)) + intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), 0); + + skl_write_plane_wm(plane, crtc_state); + + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static bool +skl_plane_get_hw_state(struct intel_plane *plane, + enum pipe *pipe) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum intel_display_power_domain power_domain; + enum plane_id plane_id = plane->id; + intel_wakeref_t wakeref; + bool ret; + + power_domain = POWER_DOMAIN_PIPE(plane->pipe); + wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain); + if (!wakeref) + return false; + + ret = intel_de_read(dev_priv, PLANE_CTL(plane->pipe, plane_id)) & PLANE_CTL_ENABLE; + + *pipe = plane->pipe; + + intel_display_power_put(dev_priv, power_domain, wakeref); + + return ret; +} + +static u32 skl_plane_ctl_format(u32 pixel_format) +{ + switch (pixel_format) { + case DRM_FORMAT_C8: + return PLANE_CTL_FORMAT_INDEXED; + case DRM_FORMAT_RGB565: + return PLANE_CTL_FORMAT_RGB_565; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + return PLANE_CTL_FORMAT_XRGB_8888; + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ABGR2101010: + return PLANE_CTL_FORMAT_XRGB_2101010 | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ARGB2101010: + return PLANE_CTL_FORMAT_XRGB_2101010; + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + return PLANE_CTL_FORMAT_XRGB_16161616F | PLANE_CTL_ORDER_RGBX; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + return PLANE_CTL_FORMAT_XRGB_16161616F; + case DRM_FORMAT_XYUV8888: + return PLANE_CTL_FORMAT_XYUV; + case DRM_FORMAT_YUYV: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; + case DRM_FORMAT_YVYU: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; + case DRM_FORMAT_UYVY: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; + case DRM_FORMAT_VYUY: + return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; + case DRM_FORMAT_NV12: + return PLANE_CTL_FORMAT_NV12; + case DRM_FORMAT_P010: + return PLANE_CTL_FORMAT_P010; + case DRM_FORMAT_P012: + return PLANE_CTL_FORMAT_P012; + case DRM_FORMAT_P016: + return PLANE_CTL_FORMAT_P016; + case DRM_FORMAT_Y210: + return PLANE_CTL_FORMAT_Y210; + case DRM_FORMAT_Y212: + return PLANE_CTL_FORMAT_Y212; + case DRM_FORMAT_Y216: + return PLANE_CTL_FORMAT_Y216; + case DRM_FORMAT_XVYU2101010: + return PLANE_CTL_FORMAT_Y410; + case DRM_FORMAT_XVYU12_16161616: + return PLANE_CTL_FORMAT_Y412; + case DRM_FORMAT_XVYU16161616: + return PLANE_CTL_FORMAT_Y416; + default: + MISSING_CASE(pixel_format); + } + + return 0; +} + +static u32 skl_plane_ctl_alpha(const struct intel_plane_state *plane_state) +{ + if (!plane_state->hw.fb->format->has_alpha) + return PLANE_CTL_ALPHA_DISABLE; + + switch (plane_state->hw.pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return PLANE_CTL_ALPHA_DISABLE; + case DRM_MODE_BLEND_PREMULTI: + return PLANE_CTL_ALPHA_SW_PREMULTIPLY; + case DRM_MODE_BLEND_COVERAGE: + return PLANE_CTL_ALPHA_HW_PREMULTIPLY; + default: + MISSING_CASE(plane_state->hw.pixel_blend_mode); + return PLANE_CTL_ALPHA_DISABLE; + } +} + +static u32 glk_plane_color_ctl_alpha(const struct intel_plane_state *plane_state) +{ + if (!plane_state->hw.fb->format->has_alpha) + return PLANE_COLOR_ALPHA_DISABLE; + + switch (plane_state->hw.pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return PLANE_COLOR_ALPHA_DISABLE; + case DRM_MODE_BLEND_PREMULTI: + return PLANE_COLOR_ALPHA_SW_PREMULTIPLY; + case DRM_MODE_BLEND_COVERAGE: + return PLANE_COLOR_ALPHA_HW_PREMULTIPLY; + default: + MISSING_CASE(plane_state->hw.pixel_blend_mode); + return PLANE_COLOR_ALPHA_DISABLE; + } +} + +static u32 skl_plane_ctl_tiling(u64 fb_modifier) +{ + switch (fb_modifier) { + case DRM_FORMAT_MOD_LINEAR: + break; + case I915_FORMAT_MOD_X_TILED: + return PLANE_CTL_TILED_X; + case I915_FORMAT_MOD_Y_TILED: + return PLANE_CTL_TILED_Y; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: + return PLANE_CTL_TILED_Y | + PLANE_CTL_RENDER_DECOMPRESSION_ENABLE | + PLANE_CTL_CLEAR_COLOR_DISABLE; + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + return PLANE_CTL_TILED_Y | PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE; + case I915_FORMAT_MOD_Yf_TILED: + return PLANE_CTL_TILED_YF; + case I915_FORMAT_MOD_Yf_TILED_CCS: + return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; + default: + MISSING_CASE(fb_modifier); + } + + return 0; +} + +static u32 skl_plane_ctl_rotate(unsigned int rotate) +{ + switch (rotate) { + case DRM_MODE_ROTATE_0: + break; + /* + * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr + * while i915 HW rotation is clockwise, thats why this swapping. + */ + case DRM_MODE_ROTATE_90: + return PLANE_CTL_ROTATE_270; + case DRM_MODE_ROTATE_180: + return PLANE_CTL_ROTATE_180; + case DRM_MODE_ROTATE_270: + return PLANE_CTL_ROTATE_90; + default: + MISSING_CASE(rotate); + } + + return 0; +} + +static u32 cnl_plane_ctl_flip(unsigned int reflect) +{ + switch (reflect) { + case 0: + break; + case DRM_MODE_REFLECT_X: + return PLANE_CTL_FLIP_HORIZONTAL; + case DRM_MODE_REFLECT_Y: + default: + MISSING_CASE(reflect); + } + + return 0; +} + +static u32 skl_plane_ctl_crtc(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + u32 plane_ctl = 0; + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + return plane_ctl; + + if (crtc_state->gamma_enable) + plane_ctl |= PLANE_CTL_PIPE_GAMMA_ENABLE; + + if (crtc_state->csc_enable) + plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE; + + return plane_ctl; +} + +static u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + u32 plane_ctl; + + plane_ctl = PLANE_CTL_ENABLE; + + if (INTEL_GEN(dev_priv) < 10 && !IS_GEMINILAKE(dev_priv)) { + plane_ctl |= skl_plane_ctl_alpha(plane_state); + plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; + + if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709) + plane_ctl |= PLANE_CTL_YUV_TO_RGB_CSC_FORMAT_BT709; + + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_ctl |= PLANE_CTL_YUV_RANGE_CORRECTION_DISABLE; + } + + plane_ctl |= skl_plane_ctl_format(fb->format->format); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier); + plane_ctl |= skl_plane_ctl_rotate(rotation & DRM_MODE_ROTATE_MASK); + + if (INTEL_GEN(dev_priv) >= 10) + plane_ctl |= cnl_plane_ctl_flip(rotation & + DRM_MODE_REFLECT_MASK); + + if (key->flags & I915_SET_COLORKEY_DESTINATION) + plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION; + else if (key->flags & I915_SET_COLORKEY_SOURCE) + plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE; + + return plane_ctl; +} + +static u32 glk_plane_color_ctl_crtc(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + u32 plane_color_ctl = 0; + + if (INTEL_GEN(dev_priv) >= 11) + return plane_color_ctl; + + if (crtc_state->gamma_enable) + plane_color_ctl |= PLANE_COLOR_PIPE_GAMMA_ENABLE; + + if (crtc_state->csc_enable) + plane_color_ctl |= PLANE_COLOR_PIPE_CSC_ENABLE; + + return plane_color_ctl; +} + +static u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + u32 plane_color_ctl = 0; + + plane_color_ctl |= PLANE_COLOR_PLANE_GAMMA_DISABLE; + plane_color_ctl |= glk_plane_color_ctl_alpha(plane_state); + + if (fb->format->is_yuv && !icl_is_hdr_plane(dev_priv, plane->id)) { + switch (plane_state->hw.color_encoding) { + case DRM_COLOR_YCBCR_BT709: + plane_color_ctl |= PLANE_COLOR_CSC_MODE_YUV709_TO_RGB709; + break; + case DRM_COLOR_YCBCR_BT2020: + plane_color_ctl |= + PLANE_COLOR_CSC_MODE_YUV2020_TO_RGB2020; + break; + default: + plane_color_ctl |= + PLANE_COLOR_CSC_MODE_YUV601_TO_RGB601; + } + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; + } else if (fb->format->is_yuv) { + plane_color_ctl |= PLANE_COLOR_INPUT_CSC_ENABLE; + if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE) + plane_color_ctl |= PLANE_COLOR_YUV_RANGE_CORRECTION_DISABLE; + } + + return plane_color_ctl; +} + +static int +main_to_ccs_plane(const struct drm_framebuffer *fb, int main_plane) +{ + drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || + (main_plane && main_plane >= fb->format->num_planes / 2)); + + return fb->format->num_planes / 2 + main_plane; +} + +int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane) +{ + drm_WARN_ON(fb->dev, !is_ccs_modifier(fb->modifier) || + ccs_plane < fb->format->num_planes / 2); + + if (is_gen12_ccs_cc_plane(fb, ccs_plane)) + return 0; + + return ccs_plane - fb->format->num_planes / 2; +} + +static int +skl_main_to_aux_plane(const struct drm_framebuffer *fb, int main_plane) +{ + struct drm_i915_private *i915 = to_i915(fb->dev); + + if (is_ccs_modifier(fb->modifier)) + return main_to_ccs_plane(fb, main_plane); + else if (INTEL_GEN(i915) < 11 && + intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + return 1; + else + return 0; +} + +static void +skl_program_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + int color_plane) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; + u32 surf_addr = plane_state->color_plane[color_plane].offset; + u32 stride = skl_plane_stride(plane_state, color_plane); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int aux_plane = skl_main_to_aux_plane(fb, color_plane); + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + u32 x = plane_state->color_plane[color_plane].x; + u32 y = plane_state->color_plane[color_plane].y; + u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16; + u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16; + u8 alpha = plane_state->hw.alpha >> 8; + u32 plane_color_ctl = 0, aux_dist = 0; + unsigned long irqflags; + u32 keymsk, keymax; + u32 plane_ctl = plane_state->ctl; + + plane_ctl |= skl_plane_ctl_crtc(crtc_state); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + plane_color_ctl = plane_state->color_ctl | + glk_plane_color_ctl_crtc(crtc_state); + + /* Sizes are 0 based */ + src_w--; + src_h--; + + keymax = (key->max_value & 0xffffff) | PLANE_KEYMAX_ALPHA(alpha); + + keymsk = key->channel_mask & 0x7ffffff; + if (alpha < 0xff) + keymsk |= PLANE_KEYMSK_ALPHA_ENABLE; + + /* The scaler will handle the output position */ + if (plane_state->scaler_id >= 0) { + crtc_x = 0; + crtc_y = 0; + } + + if (aux_plane) { + aux_dist = plane_state->color_plane[aux_plane].offset - surf_addr; + + if (INTEL_GEN(dev_priv) < 12) + aux_dist |= skl_plane_stride(plane_state, aux_plane); + } + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, PLANE_STRIDE(pipe, plane_id), stride); + intel_de_write_fw(dev_priv, PLANE_POS(pipe, plane_id), + (crtc_y << 16) | crtc_x); + intel_de_write_fw(dev_priv, PLANE_SIZE(pipe, plane_id), + (src_h << 16) | src_w); + + intel_de_write_fw(dev_priv, PLANE_AUX_DIST(pipe, plane_id), aux_dist); + + if (icl_is_hdr_plane(dev_priv, plane_id)) + intel_de_write_fw(dev_priv, PLANE_CUS_CTL(pipe, plane_id), + plane_state->cus_ctl); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + intel_de_write_fw(dev_priv, PLANE_COLOR_CTL(pipe, plane_id), + plane_color_ctl); + + if (fb->format->is_yuv && icl_is_hdr_plane(dev_priv, plane_id)) + icl_program_input_csc(plane, crtc_state, plane_state); + + if (fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC) + intel_uncore_write64_fw(&dev_priv->uncore, + PLANE_CC_VAL(pipe, plane_id), plane_state->ccval); + + skl_write_plane_wm(plane, crtc_state); + + intel_de_write_fw(dev_priv, PLANE_KEYVAL(pipe, plane_id), + key->min_value); + intel_de_write_fw(dev_priv, PLANE_KEYMSK(pipe, plane_id), keymsk); + intel_de_write_fw(dev_priv, PLANE_KEYMAX(pipe, plane_id), keymax); + + intel_de_write_fw(dev_priv, PLANE_OFFSET(pipe, plane_id), + (y << 16) | x); + + if (INTEL_GEN(dev_priv) < 11) + intel_de_write_fw(dev_priv, PLANE_AUX_OFFSET(pipe, plane_id), + (plane_state->color_plane[1].y << 16) | plane_state->color_plane[1].x); + + if (!drm_atomic_crtc_needs_modeset(&crtc_state->uapi)) + intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, color_plane); + + /* + * The control register self-arms if the plane was previously + * disabled. Try to make the plane enable atomic by writing + * the control register just before the surface register. + */ + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), + intel_plane_ggtt_offset(plane_state) + surf_addr); + + if (plane_state->scaler_id >= 0) + skl_program_scaler(plane, crtc_state, plane_state); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static void +skl_plane_async_flip(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + bool async_flip) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + unsigned long irqflags; + enum plane_id plane_id = plane->id; + enum pipe pipe = plane->pipe; + u32 surf_addr = plane_state->color_plane[0].offset; + u32 plane_ctl = plane_state->ctl; + + plane_ctl |= skl_plane_ctl_crtc(crtc_state); + + if (async_flip) + plane_ctl |= PLANE_CTL_ASYNC_FLIP; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), plane_ctl); + intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), + intel_plane_ggtt_offset(plane_state) + surf_addr); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +static void +skl_update_plane(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + int color_plane = 0; + + if (plane_state->planar_linked_plane && !plane_state->planar_slave) + /* Program the UV plane on planar master */ + color_plane = 1; + + skl_program_plane(plane, crtc_state, plane_state, color_plane); +} + +static bool intel_format_is_p01x(u32 format) +{ + switch (format) { + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return true; + default: + return false; + } +} + +static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + struct drm_format_name_buf format_name; + + if (!fb) + return 0; + + if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) && + is_ccs_modifier(fb->modifier)) { + drm_dbg_kms(&dev_priv->drm, + "RC support only with 0/180 degree rotation (%x)\n", + rotation); + return -EINVAL; + } + + if (rotation & DRM_MODE_REFLECT_X && + fb->modifier == DRM_FORMAT_MOD_LINEAR) { + drm_dbg_kms(&dev_priv->drm, + "horizontal flip is not supported with linear surface formats\n"); + return -EINVAL; + } + + if (drm_rotation_90_or_270(rotation)) { + if (fb->modifier != I915_FORMAT_MOD_Y_TILED && + fb->modifier != I915_FORMAT_MOD_Yf_TILED) { + drm_dbg_kms(&dev_priv->drm, + "Y/Yf tiling required for 90/270!\n"); + return -EINVAL; + } + + /* + * 90/270 is not allowed with RGB64 16:16:16:16 and + * Indexed 8-bit. RGB 16-bit 5:6:5 is allowed gen11 onwards. + */ + switch (fb->format->format) { + case DRM_FORMAT_RGB565: + if (INTEL_GEN(dev_priv) >= 11) + break; + fallthrough; + case DRM_FORMAT_C8: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + drm_dbg_kms(&dev_priv->drm, + "Unsupported pixel format %s for 90/270!\n", + drm_get_format_name(fb->format->format, + &format_name)); + return -EINVAL; + default: + break; + } + } + + /* Y-tiling is not supported in IF-ID Interlace mode */ + if (crtc_state->hw.enable && + crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE && + (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED || + fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || + fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + fb->modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC)) { + drm_dbg_kms(&dev_priv->drm, + "Y/Yf tiling not supported in IF-ID mode\n"); + return -EINVAL; + } + + /* Wa_1606054188:tgl,adl-s */ + if ((IS_ALDERLAKE_S(dev_priv) || IS_TIGERLAKE(dev_priv)) && + plane_state->ckey.flags & I915_SET_COLORKEY_SOURCE && + intel_format_is_p01x(fb->format->format)) { + drm_dbg_kms(&dev_priv->drm, + "Source color keying not supported with P01x formats\n"); + return -EINVAL; + } + + return 0; +} + +static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->uapi.plane->dev); + int crtc_x = plane_state->uapi.dst.x1; + int crtc_w = drm_rect_width(&plane_state->uapi.dst); + int pipe_src_w = crtc_state->pipe_src_w; + + /* + * Display WA #1175: cnl,glk + * Planes other than the cursor may cause FIFO underflow and display + * corruption if starting less than 4 pixels from the right edge of + * the screen. + * Besides the above WA fix the similar problem, where planes other + * than the cursor ending less than 4 pixels from the left edge of the + * screen may cause FIFO underflow and display corruption. + */ + if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && + (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { + drm_dbg_kms(&dev_priv->drm, + "requested plane X %s position %d invalid (valid range %d-%d)\n", + crtc_x + crtc_w < 4 ? "end" : "start", + crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x, + 4, pipe_src_w - 4); + return -ERANGE; + } + + return 0; +} + +static int skl_plane_check_nv12_rotation(const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + int src_w = drm_rect_width(&plane_state->uapi.src) >> 16; + + /* Display WA #1106 */ + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + src_w & 3 && + (rotation == DRM_MODE_ROTATE_270 || + rotation == (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90))) { + DRM_DEBUG_KMS("src width must be multiple of 4 for rotated planar YUV\n"); + return -EINVAL; + } + + return 0; +} + +static int skl_plane_max_scale(struct drm_i915_private *dev_priv, + const struct drm_framebuffer *fb) +{ + /* + * We don't yet know the final source width nor + * whether we can use the HQ scaler mode. Assume + * the best case. + * FIXME need to properly check this later. + */ + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) || + !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + return 0x30000 - 1; + else + return 0x20000 - 1; +} + +static int intel_plane_min_width(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->min_width) + return plane->min_width(fb, color_plane, rotation); + else + return 1; +} + +static int intel_plane_max_width(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->max_width) + return plane->max_width(fb, color_plane, rotation); + else + return INT_MAX; +} + +static int intel_plane_max_height(struct intel_plane *plane, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation) +{ + if (plane->max_height) + return plane->max_height(fb, color_plane, rotation); + else + return INT_MAX; +} + +static bool +skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state, + int main_x, int main_y, u32 main_offset, + int ccs_plane) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int aux_x = plane_state->color_plane[ccs_plane].x; + int aux_y = plane_state->color_plane[ccs_plane].y; + u32 aux_offset = plane_state->color_plane[ccs_plane].offset; + u32 alignment = intel_surf_alignment(fb, ccs_plane); + int hsub; + int vsub; + + intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); + while (aux_offset >= main_offset && aux_y <= main_y) { + int x, y; + + if (aux_x == main_x && aux_y == main_y) + break; + + if (aux_offset == 0) + break; + + x = aux_x / hsub; + y = aux_y / vsub; + aux_offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + ccs_plane, + aux_offset, + aux_offset - + alignment); + aux_x = x * hsub + aux_x % hsub; + aux_y = y * vsub + aux_y % vsub; + } + + if (aux_x != main_x || aux_y != main_y) + return false; + + plane_state->color_plane[ccs_plane].offset = aux_offset; + plane_state->color_plane[ccs_plane].x = aux_x; + plane_state->color_plane[ccs_plane].y = aux_y; + + return true; +} + + +int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, + int *x, int *y, u32 *offset) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + const int aux_plane = skl_main_to_aux_plane(fb, 0); + const u32 aux_offset = plane_state->color_plane[aux_plane].offset; + const u32 alignment = intel_surf_alignment(fb, 0); + const int w = drm_rect_width(&plane_state->uapi.src) >> 16; + + intel_add_fb_offsets(x, y, plane_state, 0); + *offset = intel_plane_compute_aligned_offset(x, y, plane_state, 0); + if (drm_WARN_ON(&dev_priv->drm, alignment && !is_power_of_2(alignment))) + return -EINVAL; + + /* + * AUX surface offset is specified as the distance from the + * main surface offset, and it must be non-negative. Make + * sure that is what we will get. + */ + if (aux_plane && *offset > aux_offset) + *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, + *offset, + aux_offset & ~(alignment - 1)); + + /* + * When using an X-tiled surface, the plane blows up + * if the x offset + width exceed the stride. + * + * TODO: linear and Y-tiled seem fine, Yf untested, + */ + if (fb->modifier == I915_FORMAT_MOD_X_TILED) { + int cpp = fb->format->cpp[0]; + + while ((*x + w) * cpp > plane_state->color_plane[0].stride) { + if (*offset == 0) { + drm_dbg_kms(&dev_priv->drm, + "Unable to find suitable display surface offset due to X-tiling\n"); + return -EINVAL; + } + + *offset = intel_plane_adjust_aligned_offset(x, y, plane_state, 0, + *offset, + *offset - alignment); + } + } + + return 0; +} + +static int skl_check_main_surface(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + const unsigned int rotation = plane_state->hw.rotation; + int x = plane_state->uapi.src.x1 >> 16; + int y = plane_state->uapi.src.y1 >> 16; + const int w = drm_rect_width(&plane_state->uapi.src) >> 16; + const int h = drm_rect_height(&plane_state->uapi.src) >> 16; + const int min_width = intel_plane_min_width(plane, fb, 0, rotation); + const int max_width = intel_plane_max_width(plane, fb, 0, rotation); + const int max_height = intel_plane_max_height(plane, fb, 0, rotation); + const int aux_plane = skl_main_to_aux_plane(fb, 0); + const u32 alignment = intel_surf_alignment(fb, 0); + u32 offset; + int ret; + + if (w > max_width || w < min_width || h > max_height) { + drm_dbg_kms(&dev_priv->drm, + "requested Y/RGB source size %dx%d outside limits (min: %dx1 max: %dx%d)\n", + w, h, min_width, max_width, max_height); + return -EINVAL; + } + + ret = skl_calc_main_surface_offset(plane_state, &x, &y, &offset); + if (ret) + return ret; + + /* + * CCS AUX surface doesn't have its own x/y offsets, we must make sure + * they match with the main surface x/y offsets. + */ + if (is_ccs_modifier(fb->modifier)) { + while (!skl_check_main_ccs_coordinates(plane_state, x, y, + offset, aux_plane)) { + if (offset == 0) + break; + + offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + offset, offset - alignment); + } + + if (x != plane_state->color_plane[aux_plane].x || + y != plane_state->color_plane[aux_plane].y) { + drm_dbg_kms(&dev_priv->drm, + "Unable to find suitable display surface offset due to CCS\n"); + return -EINVAL; + } + } + + drm_WARN_ON(&dev_priv->drm, x > 8191 || y > 8191); + + plane_state->color_plane[0].offset = offset; + plane_state->color_plane[0].x = x; + plane_state->color_plane[0].y = y; + + /* + * Put the final coordinates back so that the src + * coordinate checks will see the right values. + */ + drm_rect_translate_to(&plane_state->uapi.src, + x << 16, y << 16); + + return 0; +} + +static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *i915 = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + unsigned int rotation = plane_state->hw.rotation; + int uv_plane = 1; + int max_width = intel_plane_max_width(plane, fb, uv_plane, rotation); + int max_height = intel_plane_max_height(plane, fb, uv_plane, rotation); + int x = plane_state->uapi.src.x1 >> 17; + int y = plane_state->uapi.src.y1 >> 17; + int w = drm_rect_width(&plane_state->uapi.src) >> 17; + int h = drm_rect_height(&plane_state->uapi.src) >> 17; + u32 offset; + + /* FIXME not quite sure how/if these apply to the chroma plane */ + if (w > max_width || h > max_height) { + drm_dbg_kms(&i915->drm, + "CbCr source size %dx%d too big (limit %dx%d)\n", + w, h, max_width, max_height); + return -EINVAL; + } + + intel_add_fb_offsets(&x, &y, plane_state, uv_plane); + offset = intel_plane_compute_aligned_offset(&x, &y, + plane_state, uv_plane); + + if (is_ccs_modifier(fb->modifier)) { + int ccs_plane = main_to_ccs_plane(fb, uv_plane); + u32 aux_offset = plane_state->color_plane[ccs_plane].offset; + u32 alignment = intel_surf_alignment(fb, uv_plane); + + if (offset > aux_offset) + offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + uv_plane, + offset, + aux_offset & ~(alignment - 1)); + + while (!skl_check_main_ccs_coordinates(plane_state, x, y, + offset, ccs_plane)) { + if (offset == 0) + break; + + offset = intel_plane_adjust_aligned_offset(&x, &y, + plane_state, + uv_plane, + offset, offset - alignment); + } + + if (x != plane_state->color_plane[ccs_plane].x || + y != plane_state->color_plane[ccs_plane].y) { + drm_dbg_kms(&i915->drm, + "Unable to find suitable display surface offset due to CCS\n"); + return -EINVAL; + } + } + + drm_WARN_ON(&i915->drm, x > 8191 || y > 8191); + + plane_state->color_plane[uv_plane].offset = offset; + plane_state->color_plane[uv_plane].x = x; + plane_state->color_plane[uv_plane].y = y; + + return 0; +} + +static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int src_x = plane_state->uapi.src.x1 >> 16; + int src_y = plane_state->uapi.src.y1 >> 16; + u32 offset; + int ccs_plane; + + for (ccs_plane = 0; ccs_plane < fb->format->num_planes; ccs_plane++) { + int main_hsub, main_vsub; + int hsub, vsub; + int x, y; + + if (!is_ccs_plane(fb, ccs_plane) || + is_gen12_ccs_cc_plane(fb, ccs_plane)) + continue; + + intel_fb_plane_get_subsampling(&main_hsub, &main_vsub, fb, + skl_ccs_to_main_plane(fb, ccs_plane)); + intel_fb_plane_get_subsampling(&hsub, &vsub, fb, ccs_plane); + + hsub *= main_hsub; + vsub *= main_vsub; + x = src_x / hsub; + y = src_y / vsub; + + intel_add_fb_offsets(&x, &y, plane_state, ccs_plane); + + offset = intel_plane_compute_aligned_offset(&x, &y, + plane_state, + ccs_plane); + + plane_state->color_plane[ccs_plane].offset = offset; + plane_state->color_plane[ccs_plane].x = (x * hsub + + src_x % hsub) / + main_hsub; + plane_state->color_plane[ccs_plane].y = (y * vsub + + src_y % vsub) / + main_vsub; + } + + return 0; +} + +static int skl_check_plane_surface(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->hw.fb; + int ret, i; + + ret = intel_plane_compute_gtt(plane_state); + if (ret) + return ret; + + if (!plane_state->uapi.visible) + return 0; + + /* + * Handle the AUX surface first since the main surface setup depends on + * it. + */ + if (is_ccs_modifier(fb->modifier)) { + ret = skl_check_ccs_aux_surface(plane_state); + if (ret) + return ret; + } + + if (intel_format_info_is_yuv_semiplanar(fb->format, + fb->modifier)) { + ret = skl_check_nv12_aux_surface(plane_state); + if (ret) + return ret; + } + + for (i = fb->format->num_planes; i < ARRAY_SIZE(plane_state->color_plane); i++) { + plane_state->color_plane[i].offset = 0; + plane_state->color_plane[i].x = 0; + plane_state->color_plane[i].y = 0; + } + + ret = skl_check_main_surface(plane_state); + if (ret) + return ret; + + return 0; +} + +static bool intel_fb_scalable(const struct drm_framebuffer *fb) +{ + if (!fb) + return false; + + switch (fb->format->format) { + case DRM_FORMAT_C8: + return false; + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + return INTEL_GEN(to_i915(fb->dev)) >= 11; + default: + return true; + } +} + +static int skl_plane_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + int min_scale = DRM_PLANE_HELPER_NO_SCALING; + int max_scale = DRM_PLANE_HELPER_NO_SCALING; + int ret; + + ret = skl_plane_check_fb(crtc_state, plane_state); + if (ret) + return ret; + + /* use scaler when colorkey is not required */ + if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { + min_scale = 1; + max_scale = skl_plane_max_scale(dev_priv, fb); + } + + ret = intel_atomic_plane_check_clipping(plane_state, crtc_state, + min_scale, max_scale, true); + if (ret) + return ret; + + ret = skl_check_plane_surface(plane_state); + if (ret) + return ret; + + if (!plane_state->uapi.visible) + return 0; + + ret = skl_plane_check_dst_coordinates(crtc_state, plane_state); + if (ret) + return ret; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = skl_plane_check_nv12_rotation(plane_state); + if (ret) + return ret; + + /* HW only has 8 bits pixel precision, disable plane if invisible */ + if (!(plane_state->hw.alpha >> 8)) + plane_state->uapi.visible = false; + + plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + plane_state->color_ctl = glk_plane_color_ctl(crtc_state, + plane_state); + + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + icl_is_hdr_plane(dev_priv, plane->id)) + /* Enable and use MPEG-2 chroma siting */ + plane_state->cus_ctl = PLANE_CUS_ENABLE | + PLANE_CUS_HPHASE_0 | + PLANE_CUS_VPHASE_SIGN_NEGATIVE | PLANE_CUS_VPHASE_0_25; + else + plane_state->cus_ctl = 0; + + return 0; +} + +static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (!HAS_FBC(dev_priv)) + return false; + + return pipe == PIPE_A && plane_id == PLANE_PRIMARY; +} + +static bool skl_plane_has_planar(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + /* Display WA #0870: skl, bxt */ + if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) + return false; + + if (IS_GEN(dev_priv, 9) && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) + return false; + + if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) + return false; + + return true; +} + +static const u32 *skl_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { + *num_formats = ARRAY_SIZE(skl_planar_formats); + return skl_planar_formats; + } else { + *num_formats = ARRAY_SIZE(skl_plane_formats); + return skl_plane_formats; + } +} + +static const u32 *glk_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (skl_plane_has_planar(dev_priv, pipe, plane_id)) { + *num_formats = ARRAY_SIZE(glk_planar_formats); + return glk_planar_formats; + } else { + *num_formats = ARRAY_SIZE(skl_plane_formats); + return skl_plane_formats; + } +} + +static const u32 *icl_get_plane_formats(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id, + int *num_formats) +{ + if (icl_is_hdr_plane(dev_priv, plane_id)) { + *num_formats = ARRAY_SIZE(icl_hdr_plane_formats); + return icl_hdr_plane_formats; + } else if (icl_is_nv12_y_plane(dev_priv, plane_id)) { + *num_formats = ARRAY_SIZE(icl_sdr_y_plane_formats); + return icl_sdr_y_plane_formats; + } else { + *num_formats = ARRAY_SIZE(icl_sdr_uv_plane_formats); + return icl_sdr_uv_plane_formats; + } +} + +static bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + if (plane_id == PLANE_CURSOR) + return false; + + if (INTEL_GEN(dev_priv) >= 10) + return true; + + if (IS_GEMINILAKE(dev_priv)) + return pipe != PIPE_C; + + return pipe != PIPE_C && + (plane_id == PLANE_PRIMARY || + plane_id == PLANE_SPRITE0); +} + +static bool skl_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) +{ + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Yf_TILED: + break; + case I915_FORMAT_MOD_Y_TILED_CCS: + case I915_FORMAT_MOD_Yf_TILED_CCS: + if (!plane->has_ccs) + return false; + break; + default: + return false; + } + + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + if (is_ccs_modifier(modifier)) + return true; + fallthrough; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + case DRM_FORMAT_XVYU2101010: + if (modifier == I915_FORMAT_MOD_Yf_TILED) + return true; + fallthrough; + case DRM_FORMAT_C8: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED || + modifier == I915_FORMAT_MOD_Y_TILED) + return true; + fallthrough; + default: + return false; + } +} + +static bool gen12_plane_supports_mc_ccs(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + /* Wa_14010477008:tgl[a0..c0],rkl[all],dg1[all] */ + if (IS_DG1(dev_priv) || IS_ROCKETLAKE(dev_priv) || + IS_TGL_DISP_STEPPING(dev_priv, STEP_A0, STEP_C0)) + return false; + + return plane_id < PLANE_SPRITE4; +} + +static bool gen12_plane_format_mod_supported(struct drm_plane *_plane, + u32 format, u64 modifier) +{ + struct drm_i915_private *dev_priv = to_i915(_plane->dev); + struct intel_plane *plane = to_intel_plane(_plane); + + switch (modifier) { + case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS: + if (!gen12_plane_supports_mc_ccs(dev_priv, plane->id)) + return false; + fallthrough; + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS: + case I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC: + break; + default: + return false; + } + + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + if (is_ccs_modifier(modifier)) + return true; + fallthrough; + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + if (modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) + return true; + fallthrough; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_C8: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + if (modifier == DRM_FORMAT_MOD_LINEAR || + modifier == I915_FORMAT_MOD_X_TILED || + modifier == I915_FORMAT_MOD_Y_TILED) + return true; + fallthrough; + default: + return false; + } +} + +static const u64 *gen12_get_plane_modifiers(struct drm_i915_private *dev_priv, + enum plane_id plane_id) +{ + if (gen12_plane_supports_mc_ccs(dev_priv, plane_id)) + return gen12_plane_format_modifiers_mc_ccs; + else + return gen12_plane_format_modifiers_rc_ccs; +} + +static const struct drm_plane_funcs skl_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = skl_plane_format_mod_supported, +}; + +static const struct drm_plane_funcs gen12_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = intel_plane_destroy, + .atomic_duplicate_state = intel_plane_duplicate_state, + .atomic_destroy_state = intel_plane_destroy_state, + .format_mod_supported = gen12_plane_format_mod_supported, +}; + +static void +skl_plane_enable_flip_done(struct intel_plane *plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + spin_lock_irq(&i915->irq_lock); + bdw_enable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); + spin_unlock_irq(&i915->irq_lock); +} + +static void +skl_plane_disable_flip_done(struct intel_plane *plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + spin_lock_irq(&i915->irq_lock); + bdw_disable_pipe_irq(i915, pipe, GEN9_PIPE_PLANE_FLIP_DONE(plane->id)); + spin_unlock_irq(&i915->irq_lock); +} + +struct intel_plane * +skl_universal_plane_create(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id) +{ + const struct drm_plane_funcs *plane_funcs; + struct intel_plane *plane; + enum drm_plane_type plane_type; + unsigned int supported_rotations; + unsigned int supported_csc; + const u64 *modifiers; + const u32 *formats; + int num_formats; + int ret; + + plane = intel_plane_alloc(); + if (IS_ERR(plane)) + return plane; + + plane->pipe = pipe; + plane->id = plane_id; + plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane_id); + + plane->has_fbc = skl_plane_has_fbc(dev_priv, pipe, plane_id); + if (plane->has_fbc) { + struct intel_fbc *fbc = &dev_priv->fbc; + + fbc->possible_framebuffer_bits |= plane->frontbuffer_bit; + } + + if (INTEL_GEN(dev_priv) >= 11) { + plane->min_width = icl_plane_min_width; + plane->max_width = icl_plane_max_width; + plane->max_height = icl_plane_max_height; + } else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + plane->max_width = glk_plane_max_width; + plane->max_height = skl_plane_max_height; + } else { + plane->max_width = skl_plane_max_width; + plane->max_height = skl_plane_max_height; + } + + plane->max_stride = skl_plane_max_stride; + plane->update_plane = skl_update_plane; + plane->disable_plane = skl_disable_plane; + plane->get_hw_state = skl_plane_get_hw_state; + plane->check_plane = skl_plane_check; + plane->min_cdclk = skl_plane_min_cdclk; + + if (plane_id == PLANE_PRIMARY) { + plane->need_async_flip_disable_wa = IS_GEN_RANGE(dev_priv, 9, 10); + plane->async_flip = skl_plane_async_flip; + plane->enable_flip_done = skl_plane_enable_flip_done; + plane->disable_flip_done = skl_plane_disable_flip_done; + } + + if (INTEL_GEN(dev_priv) >= 11) + formats = icl_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + else if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + formats = glk_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + else + formats = skl_get_plane_formats(dev_priv, pipe, + plane_id, &num_formats); + + plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, plane_id); + if (INTEL_GEN(dev_priv) >= 12) { + modifiers = gen12_get_plane_modifiers(dev_priv, plane_id); + plane_funcs = &gen12_plane_funcs; + } else { + if (plane->has_ccs) + modifiers = skl_plane_format_modifiers_ccs; + else + modifiers = skl_plane_format_modifiers_noccs; + plane_funcs = &skl_plane_funcs; + } + + if (plane_id == PLANE_PRIMARY) + plane_type = DRM_PLANE_TYPE_PRIMARY; + else + plane_type = DRM_PLANE_TYPE_OVERLAY; + + ret = drm_universal_plane_init(&dev_priv->drm, &plane->base, + 0, plane_funcs, + formats, num_formats, modifiers, + plane_type, + "plane %d%c", plane_id + 1, + pipe_name(pipe)); + if (ret) + goto fail; + + supported_rotations = + DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; + + if (INTEL_GEN(dev_priv) >= 10) + supported_rotations |= DRM_MODE_REFLECT_X; + + drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + supported_rotations); + + supported_csc = BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709); + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + supported_csc |= BIT(DRM_COLOR_YCBCR_BT2020); + + drm_plane_create_color_properties(&plane->base, + supported_csc, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + drm_plane_create_zpos_immutable_property(&plane->base, plane_id); + + if (INTEL_GEN(dev_priv) >= 12) + drm_plane_enable_fb_damage_clips(&plane->base); + + if (INTEL_GEN(dev_priv) >= 10) + drm_plane_create_scaling_filter_property(&plane->base, + BIT(DRM_SCALING_FILTER_DEFAULT) | + BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); + + drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs); + + return plane; + +fail: + intel_plane_free(plane); + + return ERR_PTR(ret); +} + +void +skl_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + enum plane_id plane_id = plane->id; + enum pipe pipe; + u32 val, base, offset, stride_mult, tiling, alpha; + int fourcc, pixel_format; + unsigned int aligned_height; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + + if (!plane->get_hw_state(plane, &pipe)) + return; + + drm_WARN_ON(dev, pipe != crtc->pipe); + + if (crtc_state->bigjoiner) { + drm_dbg_kms(&dev_priv->drm, + "Unsupported bigjoiner configuration for initial FB\n"); + return; + } + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); + return; + } + + fb = &intel_fb->base; + + fb->dev = dev; + + val = intel_de_read(dev_priv, PLANE_CTL(pipe, plane_id)); + + if (INTEL_GEN(dev_priv) >= 11) + pixel_format = val & ICL_PLANE_CTL_FORMAT_MASK; + else + pixel_format = val & PLANE_CTL_FORMAT_MASK; + + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) { + alpha = intel_de_read(dev_priv, + PLANE_COLOR_CTL(pipe, plane_id)); + alpha &= PLANE_COLOR_ALPHA_MASK; + } else { + alpha = val & PLANE_CTL_ALPHA_MASK; + } + + fourcc = skl_format_to_fourcc(pixel_format, + val & PLANE_CTL_ORDER_RGBX, alpha); + fb->format = drm_format_info(fourcc); + + tiling = val & PLANE_CTL_TILED_MASK; + switch (tiling) { + case PLANE_CTL_TILED_LINEAR: + fb->modifier = DRM_FORMAT_MOD_LINEAR; + break; + case PLANE_CTL_TILED_X: + plane_config->tiling = I915_TILING_X; + fb->modifier = I915_FORMAT_MOD_X_TILED; + break; + case PLANE_CTL_TILED_Y: + plane_config->tiling = I915_TILING_Y; + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = INTEL_GEN(dev_priv) >= 12 ? + I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS : + I915_FORMAT_MOD_Y_TILED_CCS; + else if (val & PLANE_CTL_MEDIA_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS; + else + fb->modifier = I915_FORMAT_MOD_Y_TILED; + break; + case PLANE_CTL_TILED_YF: + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) + fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; + else + fb->modifier = I915_FORMAT_MOD_Yf_TILED; + break; + default: + MISSING_CASE(tiling); + goto error; + } + + /* + * DRM_MODE_ROTATE_ is counter clockwise to stay compatible with Xrandr + * while i915 HW rotation is clockwise, thats why this swapping. + */ + switch (val & PLANE_CTL_ROTATE_MASK) { + case PLANE_CTL_ROTATE_0: + plane_config->rotation = DRM_MODE_ROTATE_0; + break; + case PLANE_CTL_ROTATE_90: + plane_config->rotation = DRM_MODE_ROTATE_270; + break; + case PLANE_CTL_ROTATE_180: + plane_config->rotation = DRM_MODE_ROTATE_180; + break; + case PLANE_CTL_ROTATE_270: + plane_config->rotation = DRM_MODE_ROTATE_90; + break; + } + + if (INTEL_GEN(dev_priv) >= 10 && + val & PLANE_CTL_FLIP_HORIZONTAL) + plane_config->rotation |= DRM_MODE_REFLECT_X; + + /* 90/270 degree rotation would require extra work */ + if (drm_rotation_90_or_270(plane_config->rotation)) + goto error; + + base = intel_de_read(dev_priv, PLANE_SURF(pipe, plane_id)) & 0xfffff000; + plane_config->base = base; + + offset = intel_de_read(dev_priv, PLANE_OFFSET(pipe, plane_id)); + + val = intel_de_read(dev_priv, PLANE_SIZE(pipe, plane_id)); + fb->height = ((val >> 16) & 0xffff) + 1; + fb->width = ((val >> 0) & 0xffff) + 1; + + val = intel_de_read(dev_priv, PLANE_STRIDE(pipe, plane_id)); + stride_mult = skl_plane_stride_mult(fb, 0, DRM_MODE_ROTATE_0); + fb->pitches[0] = (val & 0x3ff) * stride_mult; + + aligned_height = intel_fb_align_height(fb, 0, fb->height); + + plane_config->size = fb->pitches[0] * aligned_height; + + drm_dbg_kms(&dev_priv->drm, + "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + crtc->base.name, plane->base.name, fb->width, fb->height, + fb->format->cpp[0] * 8, base, fb->pitches[0], + plane_config->size); + + plane_config->fb = intel_fb; + return; + +error: + kfree(intel_fb); +} + diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h new file mode 100644 index 0000000000000..70eb5010cd284 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ + +#ifndef _SKL_UNIVERSAL_PLANE_H_ +#define _SKL_UNIVERSAL_PLANE_H_ + +#include + +struct drm_framebuffer; +struct drm_i915_private; +struct intel_crtc; +struct intel_initial_plane_config; +struct intel_plane_state; + +enum pipe; +enum plane_id; + +struct intel_plane * +skl_universal_plane_create(struct drm_i915_private *dev_priv, + enum pipe pipe, enum plane_id plane_id); + +void skl_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config); + +int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); + +int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane); +int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, + int *x, int *y, u32 *offset); + +#endif diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c58e5077590df..8c42fa51c0f6d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -38,6 +38,7 @@ #include "display/intel_display_types.h" #include "display/intel_fbc.h" #include "display/intel_sprite.h" +#include "display/skl_universal_plane.h" #include "gt/intel_llc.h" From d471008b00c1a0f0bee3beaabf962106bbc9f47d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:37 +0200 Subject: [PATCH 044/142] drm/i915: move pipe update code into crtc. (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Daniel suggested this should move here. v2: move vrr code. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/738c7aaeb63c7d2357ddd932f18787ec8a3cefeb.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_crtc.c | 241 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_sprite.c | 238 ------------------- 2 files changed, 241 insertions(+), 238 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index eb478712c3814..8bfa8fc2efdbb 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -10,6 +10,9 @@ #include #include +#include "i915_trace.h" +#include "i915_vgpu.h" + #include "intel_atomic.h" #include "intel_atomic_plane.h" #include "intel_color.h" @@ -17,8 +20,11 @@ #include "intel_cursor.h" #include "intel_display_debugfs.h" #include "intel_display_types.h" +#include "intel_dsi.h" #include "intel_pipe_crc.h" +#include "intel_psr.h" #include "intel_sprite.h" +#include "intel_vrr.h" #include "i9xx_plane.h" #include "skl_universal_plane.h" @@ -332,3 +338,238 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe) return ret; } + +int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, + int usecs) +{ + /* paranoia */ + if (!adjusted_mode->crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, + 1000 * adjusted_mode->crtc_htotal); +} + +static int intel_mode_vblank_start(const struct drm_display_mode *mode) +{ + int vblank_start = mode->crtc_vblank_start; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + vblank_start = DIV_ROUND_UP(vblank_start, 2); + + return vblank_start; +} + +/** + * intel_pipe_update_start() - start update of a set of display registers + * @new_crtc_state: the new crtc state + * + * Mark the start of an update to pipe registers that should be updated + * atomically regarding vblank. If the next vblank will happens within + * the next 100 us, this function waits until the vblank passes. + * + * After a successful call to this function, interrupts will be disabled + * until a subsequent call to intel_pipe_update_end(). That is done to + * avoid random delays. + */ +void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; + long timeout = msecs_to_jiffies_timeout(1); + int scanline, min, max, vblank_start; + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); + bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); + DEFINE_WAIT(wait); + + if (new_crtc_state->uapi.async_flip) + return; + + if (new_crtc_state->vrr.enable) + vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); + else + vblank_start = intel_mode_vblank_start(adjusted_mode); + + /* FIXME needs to be calibrated sensibly */ + min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, + VBLANK_EVASION_TIME_US); + max = vblank_start - 1; + + if (min <= 0 || max <= 0) + goto irq_disable; + + if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base))) + goto irq_disable; + + /* + * Wait for psr to idle out after enabling the VBL interrupts + * VBL interrupts will start the PSR exit and prevent a PSR + * re-entry as well. + */ + intel_psr_wait_for_idle(new_crtc_state); + + local_irq_disable(); + + crtc->debug.min_vbl = min; + crtc->debug.max_vbl = max; + trace_intel_pipe_update_start(crtc); + + for (;;) { + /* + * prepare_to_wait() has a memory barrier, which guarantees + * other CPUs can see the task state update by the time we + * read the scanline. + */ + prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); + + scanline = intel_get_crtc_scanline(crtc); + if (scanline < min || scanline > max) + break; + + if (!timeout) { + drm_err(&dev_priv->drm, + "Potential atomic update failure on pipe %c\n", + pipe_name(crtc->pipe)); + break; + } + + local_irq_enable(); + + timeout = schedule_timeout(timeout); + + local_irq_disable(); + } + + finish_wait(wq, &wait); + + drm_crtc_vblank_put(&crtc->base); + + /* + * On VLV/CHV DSI the scanline counter would appear to + * increment approx. 1/3 of a scanline before start of vblank. + * The registers still get latched at start of vblank however. + * This means we must not write any registers on the first + * line of vblank (since not the whole line is actually in + * vblank). And unfortunately we can't use the interrupt to + * wait here since it will fire too soon. We could use the + * frame start interrupt instead since it will fire after the + * critical scanline, but that would require more changes + * in the interrupt code. So for now we'll just do the nasty + * thing and poll for the bad scanline to pass us by. + * + * FIXME figure out if BXT+ DSI suffers from this as well + */ + while (need_vlv_dsi_wa && scanline == vblank_start) + scanline = intel_get_crtc_scanline(crtc); + + crtc->debug.scanline_start = scanline; + crtc->debug.start_vbl_time = ktime_get(); + crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); + + trace_intel_pipe_update_vblank_evaded(crtc); + return; + +irq_disable: + local_irq_disable(); +} + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) +static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) +{ + u64 delta = ktime_to_ns(ktime_sub(end, crtc->debug.start_vbl_time)); + unsigned int h; + + h = ilog2(delta >> 9); + if (h >= ARRAY_SIZE(crtc->debug.vbl.times)) + h = ARRAY_SIZE(crtc->debug.vbl.times) - 1; + crtc->debug.vbl.times[h]++; + + crtc->debug.vbl.sum += delta; + if (!crtc->debug.vbl.min || delta < crtc->debug.vbl.min) + crtc->debug.vbl.min = delta; + if (delta > crtc->debug.vbl.max) + crtc->debug.vbl.max = delta; + + if (delta > 1000 * VBLANK_EVASION_TIME_US) { + drm_dbg_kms(crtc->base.dev, + "Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", + pipe_name(crtc->pipe), + div_u64(delta, 1000), + VBLANK_EVASION_TIME_US); + crtc->debug.vbl.over++; + } +} +#else +static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} +#endif + +/** + * intel_pipe_update_end() - end update of a set of display registers + * @new_crtc_state: the new crtc state + * + * Mark the end of an update started with intel_pipe_update_start(). This + * re-enables interrupts and verifies the update was actually completed + * before a vblank. + */ +void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); + enum pipe pipe = crtc->pipe; + int scanline_end = intel_get_crtc_scanline(crtc); + u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); + ktime_t end_vbl_time = ktime_get(); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + if (new_crtc_state->uapi.async_flip) + return; + + trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); + + /* + * Incase of mipi dsi command mode, we need to set frame update + * request for every commit. + */ + if (INTEL_GEN(dev_priv) >= 11 && + intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI)) + icl_dsi_frame_update(new_crtc_state); + + /* We're still in the vblank-evade critical section, this can't race. + * Would be slightly nice to just grab the vblank count and arm the + * event outside of the critical section - the spinlock might spin for a + * while ... */ + if (new_crtc_state->uapi.event) { + drm_WARN_ON(&dev_priv->drm, + drm_crtc_vblank_get(&crtc->base) != 0); + + spin_lock(&crtc->base.dev->event_lock); + drm_crtc_arm_vblank_event(&crtc->base, + new_crtc_state->uapi.event); + spin_unlock(&crtc->base.dev->event_lock); + + new_crtc_state->uapi.event = NULL; + } + + local_irq_enable(); + + /* Send VRR Push to terminate Vblank */ + intel_vrr_send_push(new_crtc_state); + + if (intel_vgpu_active(dev_priv)) + return; + + if (crtc->debug.start_vbl_count && + crtc->debug.start_vbl_count != end_vbl_count) { + drm_err(&dev_priv->drm, + "Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", + pipe_name(pipe), crtc->debug.start_vbl_count, + end_vbl_count, + ktime_us_delta(end_vbl_time, + crtc->debug.start_vbl_time), + crtc->debug.min_vbl, crtc->debug.max_vbl, + crtc->debug.scanline_start, scanline_end); + } + + dbg_vblank_evade(crtc, end_vbl_time); +} diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 93f3afc245b99..b8288330dbc9c 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -45,248 +45,10 @@ #include "intel_atomic_plane.h" #include "intel_display_types.h" #include "intel_frontbuffer.h" -#include "intel_pm.h" -#include "intel_psr.h" -#include "intel_dsi.h" #include "intel_sprite.h" #include "i9xx_plane.h" #include "intel_vrr.h" -int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, - int usecs) -{ - /* paranoia */ - if (!adjusted_mode->crtc_htotal) - return 1; - - return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock, - 1000 * adjusted_mode->crtc_htotal); -} - -static int intel_mode_vblank_start(const struct drm_display_mode *mode) -{ - int vblank_start = mode->crtc_vblank_start; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - vblank_start = DIV_ROUND_UP(vblank_start, 2); - - return vblank_start; -} - -/** - * intel_pipe_update_start() - start update of a set of display registers - * @new_crtc_state: the new crtc state - * - * Mark the start of an update to pipe registers that should be updated - * atomically regarding vblank. If the next vblank will happens within - * the next 100 us, this function waits until the vblank passes. - * - * After a successful call to this function, interrupts will be disabled - * until a subsequent call to intel_pipe_update_end(). That is done to - * avoid random delays. - */ -void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &new_crtc_state->hw.adjusted_mode; - long timeout = msecs_to_jiffies_timeout(1); - int scanline, min, max, vblank_start; - wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); - bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); - DEFINE_WAIT(wait); - - if (new_crtc_state->uapi.async_flip) - return; - - if (new_crtc_state->vrr.enable) - vblank_start = intel_vrr_vmax_vblank_start(new_crtc_state); - else - vblank_start = intel_mode_vblank_start(adjusted_mode); - - /* FIXME needs to be calibrated sensibly */ - min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, - VBLANK_EVASION_TIME_US); - max = vblank_start - 1; - - if (min <= 0 || max <= 0) - goto irq_disable; - - if (drm_WARN_ON(&dev_priv->drm, drm_crtc_vblank_get(&crtc->base))) - goto irq_disable; - - /* - * Wait for psr to idle out after enabling the VBL interrupts - * VBL interrupts will start the PSR exit and prevent a PSR - * re-entry as well. - */ - intel_psr_wait_for_idle(new_crtc_state); - - local_irq_disable(); - - crtc->debug.min_vbl = min; - crtc->debug.max_vbl = max; - trace_intel_pipe_update_start(crtc); - - for (;;) { - /* - * prepare_to_wait() has a memory barrier, which guarantees - * other CPUs can see the task state update by the time we - * read the scanline. - */ - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - - scanline = intel_get_crtc_scanline(crtc); - if (scanline < min || scanline > max) - break; - - if (!timeout) { - drm_err(&dev_priv->drm, - "Potential atomic update failure on pipe %c\n", - pipe_name(crtc->pipe)); - break; - } - - local_irq_enable(); - - timeout = schedule_timeout(timeout); - - local_irq_disable(); - } - - finish_wait(wq, &wait); - - drm_crtc_vblank_put(&crtc->base); - - /* - * On VLV/CHV DSI the scanline counter would appear to - * increment approx. 1/3 of a scanline before start of vblank. - * The registers still get latched at start of vblank however. - * This means we must not write any registers on the first - * line of vblank (since not the whole line is actually in - * vblank). And unfortunately we can't use the interrupt to - * wait here since it will fire too soon. We could use the - * frame start interrupt instead since it will fire after the - * critical scanline, but that would require more changes - * in the interrupt code. So for now we'll just do the nasty - * thing and poll for the bad scanline to pass us by. - * - * FIXME figure out if BXT+ DSI suffers from this as well - */ - while (need_vlv_dsi_wa && scanline == vblank_start) - scanline = intel_get_crtc_scanline(crtc); - - crtc->debug.scanline_start = scanline; - crtc->debug.start_vbl_time = ktime_get(); - crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); - - trace_intel_pipe_update_vblank_evaded(crtc); - return; - -irq_disable: - local_irq_disable(); -} - -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) -static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) -{ - u64 delta = ktime_to_ns(ktime_sub(end, crtc->debug.start_vbl_time)); - unsigned int h; - - h = ilog2(delta >> 9); - if (h >= ARRAY_SIZE(crtc->debug.vbl.times)) - h = ARRAY_SIZE(crtc->debug.vbl.times) - 1; - crtc->debug.vbl.times[h]++; - - crtc->debug.vbl.sum += delta; - if (!crtc->debug.vbl.min || delta < crtc->debug.vbl.min) - crtc->debug.vbl.min = delta; - if (delta > crtc->debug.vbl.max) - crtc->debug.vbl.max = delta; - - if (delta > 1000 * VBLANK_EVASION_TIME_US) { - drm_dbg_kms(crtc->base.dev, - "Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n", - pipe_name(crtc->pipe), - div_u64(delta, 1000), - VBLANK_EVASION_TIME_US); - crtc->debug.vbl.over++; - } -} -#else -static void dbg_vblank_evade(struct intel_crtc *crtc, ktime_t end) {} -#endif - -/** - * intel_pipe_update_end() - end update of a set of display registers - * @new_crtc_state: the new crtc state - * - * Mark the end of an update started with intel_pipe_update_start(). This - * re-enables interrupts and verifies the update was actually completed - * before a vblank. - */ -void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc); - enum pipe pipe = crtc->pipe; - int scanline_end = intel_get_crtc_scanline(crtc); - u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc); - ktime_t end_vbl_time = ktime_get(); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (new_crtc_state->uapi.async_flip) - return; - - trace_intel_pipe_update_end(crtc, end_vbl_count, scanline_end); - - /* - * Incase of mipi dsi command mode, we need to set frame update - * request for every commit. - */ - if (INTEL_GEN(dev_priv) >= 11 && - intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI)) - icl_dsi_frame_update(new_crtc_state); - - /* We're still in the vblank-evade critical section, this can't race. - * Would be slightly nice to just grab the vblank count and arm the - * event outside of the critical section - the spinlock might spin for a - * while ... */ - if (new_crtc_state->uapi.event) { - drm_WARN_ON(&dev_priv->drm, - drm_crtc_vblank_get(&crtc->base) != 0); - - spin_lock(&crtc->base.dev->event_lock); - drm_crtc_arm_vblank_event(&crtc->base, - new_crtc_state->uapi.event); - spin_unlock(&crtc->base.dev->event_lock); - - new_crtc_state->uapi.event = NULL; - } - - local_irq_enable(); - - /* Send VRR Push to terminate Vblank */ - intel_vrr_send_push(new_crtc_state); - - if (intel_vgpu_active(dev_priv)) - return; - - if (crtc->debug.start_vbl_count && - crtc->debug.start_vbl_count != end_vbl_count) { - drm_err(&dev_priv->drm, - "Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n", - pipe_name(pipe), crtc->debug.start_vbl_count, - end_vbl_count, - ktime_us_delta(end_vbl_time, - crtc->debug.start_vbl_time), - crtc->debug.min_vbl, crtc->debug.max_vbl, - crtc->debug.scanline_start, scanline_end); - } - - dbg_vblank_evade(crtc, end_vbl_time); -} - int intel_plane_check_stride(const struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); From 14cebc1fc4344af22bbff82687c458229b674b88 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:38 +0200 Subject: [PATCH 045/142] drm/i915: split fb scalable checks into g4x and skl versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This just cleans these up a bit. Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/c91d924e93965515d2017dbf3c89c245ff6d52ea.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_sprite.c | 7 +++---- drivers/gpu/drm/i915/display/skl_universal_plane.c | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index b8288330dbc9c..46fcb5b9983f2 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -1365,19 +1365,18 @@ g4x_plane_get_hw_state(struct intel_plane *plane, return ret; } -static bool intel_fb_scalable(const struct drm_framebuffer *fb) +static bool g4x_fb_scalable(const struct drm_framebuffer *fb) { if (!fb) return false; switch (fb->format->format) { case DRM_FORMAT_C8: - return false; case DRM_FORMAT_XRGB16161616F: case DRM_FORMAT_ARGB16161616F: case DRM_FORMAT_XBGR16161616F: case DRM_FORMAT_ABGR16161616F: - return INTEL_GEN(to_i915(fb->dev)) >= 11; + return false; default: return true; } @@ -1454,7 +1453,7 @@ g4x_sprite_check(struct intel_crtc_state *crtc_state, int max_scale = DRM_PLANE_HELPER_NO_SCALING; int ret; - if (intel_fb_scalable(plane_state->hw.fb)) { + if (g4x_fb_scalable(plane_state->hw.fb)) { if (INTEL_GEN(dev_priv) < 7) { min_scale = 1; max_scale = 16 << 16; diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 29c2e3693e8be..4ae1a2ef29eca 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1618,7 +1618,7 @@ static int skl_check_plane_surface(struct intel_plane_state *plane_state) return 0; } -static bool intel_fb_scalable(const struct drm_framebuffer *fb) +static bool skl_fb_scalable(const struct drm_framebuffer *fb) { if (!fb) return false; @@ -1651,7 +1651,7 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, return ret; /* use scaler when colorkey is not required */ - if (!plane_state->ckey.flags && intel_fb_scalable(fb)) { + if (!plane_state->ckey.flags && skl_fb_scalable(fb)) { min_scale = 1; max_scale = skl_plane_max_scale(dev_priv, fb); } From 92ae3db4c1e1dc195b92055ac07ade216e5cb699 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:39 +0200 Subject: [PATCH 046/142] drm/i915: move is_ccs_modifier to an inline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for this to be out of line. Reviewed-by: Ville Syrjälä Signed-off-by: Dave Airlie Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/bb73a151b7b780f927edeb7e121449446592805d.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 9 --------- drivers/gpu/drm/i915/display/intel_display.h | 1 - drivers/gpu/drm/i915/display/intel_display_types.h | 9 +++++++++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 257954cb74268..e9e8a5233b985 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1826,15 +1826,6 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd) } } -bool is_ccs_modifier(u64 modifier) -{ - return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || - modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_CCS || - modifier == I915_FORMAT_MOD_Yf_TILED_CCS; -} - static int gen12_ccs_aux_stride(struct drm_framebuffer *fb, int ccs_plane) { return DIV_ROUND_UP(fb->pitches[skl_ccs_to_main_plane(fb, ccs_plane)], diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 3c153eb780921..2bbd2ee9147e8 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -517,7 +517,6 @@ void intel_link_compute_m_n(u16 bpp, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n, bool constant_n, bool fec_enable); -bool is_ccs_modifier(u64 modifier); void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 6183f2f0424bf..ebaa9d0ed376b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1946,6 +1946,15 @@ static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv, return dev_priv->fdi_pll_freq; } +static inline bool is_ccs_modifier(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC || + modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS || + modifier == I915_FORMAT_MOD_Y_TILED_CCS || + modifier == I915_FORMAT_MOD_Yf_TILED_CCS; +} + static inline bool is_ccs_plane(const struct drm_framebuffer *fb, int plane) { if (!is_ccs_modifier(fb->modifier)) From 12edd6ab14b400460807309158eaa344ba1d43e4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:40 +0200 Subject: [PATCH 047/142] drm/i915: migrate pll enable/disable code to intel_dpll.[ch] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the older i9xx/vlv/chv enable/disable to dpll file. Signed-off-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/7fa8c76b0f07f3ede9efd7c1f989f33fbc8c53a3.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 512 ------------------- drivers/gpu/drm/i915/display/intel_display.h | 3 - drivers/gpu/drm/i915/display/intel_dp.c | 1 + drivers/gpu/drm/i915/display/intel_dpll.c | 509 ++++++++++++++++++ drivers/gpu/drm/i915/display/intel_dpll.h | 18 + drivers/gpu/drm/i915/display/intel_pps.c | 1 + 6 files changed, 529 insertions(+), 515 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e9e8a5233b985..ef29065ea72e0 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -113,10 +113,6 @@ static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state); static void ilk_set_pipeconf(const struct intel_crtc_state *crtc_state); static void hsw_set_pipeconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipemisc(const struct intel_crtc_state *crtc_state); -static void vlv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config); -static void chv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config); static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state); static void intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); @@ -569,224 +565,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, assert_pch_hdmi_disabled(dev_priv, pipe, PORT_D, PCH_HDMID); } -static void _vlv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); - intel_de_posting_read(dev_priv, DPLL(pipe)); - udelay(150); - - if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) - drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe); -} - -static void vlv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); - - if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) - _vlv_enable_pll(crtc, pipe_config); - - intel_de_write(dev_priv, DPLL_MD(pipe), - pipe_config->dpll_hw_state.dpll_md); - intel_de_posting_read(dev_priv, DPLL_MD(pipe)); -} - - -static void _chv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 tmp; - - vlv_dpio_get(dev_priv); - - /* Enable back the 10bit clock to display controller */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); - tmp |= DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); - - vlv_dpio_put(dev_priv); - - /* - * Need to wait > 100ns between dclkp clock enable bit and PLL enable. - */ - udelay(1); - - /* Enable PLL */ - intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); - - /* Check PLL is locked */ - if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) - drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe); -} - -static void chv_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum pipe pipe = crtc->pipe; - - assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - assert_panel_unlocked(dev_priv, pipe); - - if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) - _chv_enable_pll(crtc, pipe_config); - - if (pipe != PIPE_A) { - /* - * WaPixelRepeatModeFixForC0:chv - * - * DPLLCMD is AWOL. Use chicken bits to propagate - * the value from DPLLBMD to either pipe B or C. - */ - intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe)); - intel_de_write(dev_priv, DPLL_MD(PIPE_B), - pipe_config->dpll_hw_state.dpll_md); - intel_de_write(dev_priv, CBR4_VLV, 0); - dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md; - - /* - * DPLLB VGA mode also seems to cause problems. - * We should always have it disabled. - */ - drm_WARN_ON(&dev_priv->drm, - (intel_de_read(dev_priv, DPLL(PIPE_B)) & - DPLL_VGA_MODE_DIS) == 0); - } else { - intel_de_write(dev_priv, DPLL_MD(pipe), - pipe_config->dpll_hw_state.dpll_md); - intel_de_posting_read(dev_priv, DPLL_MD(pipe)); - } -} - -static bool i9xx_has_pps(struct drm_i915_private *dev_priv) -{ - if (IS_I830(dev_priv)) - return false; - - return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv); -} - -static void i9xx_enable_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - i915_reg_t reg = DPLL(crtc->pipe); - u32 dpll = crtc_state->dpll_hw_state.dpll; - int i; - - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); - - /* PLL is protected by panel, make sure we can write it */ - if (i9xx_has_pps(dev_priv)) - assert_panel_unlocked(dev_priv, crtc->pipe); - - /* - * Apparently we need to have VGA mode enabled prior to changing - * the P1/P2 dividers. Otherwise the DPLL will keep using the old - * dividers, even though the register value does change. - */ - intel_de_write(dev_priv, reg, dpll & ~DPLL_VGA_MODE_DIS); - intel_de_write(dev_priv, reg, dpll); - - /* Wait for the clocks to stabilize. */ - intel_de_posting_read(dev_priv, reg); - udelay(150); - - if (INTEL_GEN(dev_priv) >= 4) { - intel_de_write(dev_priv, DPLL_MD(crtc->pipe), - crtc_state->dpll_hw_state.dpll_md); - } else { - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - intel_de_write(dev_priv, reg, dpll); - } - - /* We do this three times for luck */ - for (i = 0; i < 3; i++) { - intel_de_write(dev_priv, reg, dpll); - intel_de_posting_read(dev_priv, reg); - udelay(150); /* wait for warmup */ - } -} - -static void i9xx_disable_pll(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); - enum pipe pipe = crtc->pipe; - - /* Don't disable pipe or pipe PLLs if needed */ - if (IS_I830(dev_priv)) - return; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); - - intel_de_write(dev_priv, DPLL(pipe), DPLL_VGA_MODE_DIS); - intel_de_posting_read(dev_priv, DPLL(pipe)); -} - -static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - u32 val; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); - - val = DPLL_INTEGRATED_REF_CLK_VLV | - DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; - if (pipe != PIPE_A) - val |= DPLL_INTEGRATED_CRI_CLK_VLV; - - intel_de_write(dev_priv, DPLL(pipe), val); - intel_de_posting_read(dev_priv, DPLL(pipe)); -} - -static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 val; - - /* Make sure the pipe isn't still relying on us */ - assert_pipe_disabled(dev_priv, (enum transcoder)pipe); - - val = DPLL_SSC_REF_CLK_CHV | - DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; - if (pipe != PIPE_A) - val |= DPLL_INTEGRATED_CRI_CLK_VLV; - - intel_de_write(dev_priv, DPLL(pipe), val); - intel_de_posting_read(dev_priv, DPLL(pipe)); - - vlv_dpio_get(dev_priv); - - /* Disable 10bit clock to display controller */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); - val &= ~DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); - - vlv_dpio_put(dev_priv); -} - void vlv_wait_port_ready(struct drm_i915_private *dev_priv, struct intel_digital_port *dig_port, unsigned int expected_mask) @@ -5774,35 +5552,6 @@ static void intel_panel_sanitize_ssc(struct drm_i915_private *dev_priv) } } -static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe - pipe) -{ - u32 reg_val; - - /* - * PLLB opamp always calibrates to max value of 0x3f, force enable it - * and set it to a reasonable value instead. - */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); - reg_val &= 0xffffff00; - reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); - reg_val &= 0x00ffffff; - reg_val |= 0x8c000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); - reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); - - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); - reg_val &= 0x00ffffff; - reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); -} - static void intel_pch_transcoder_set_m_n(const struct intel_crtc_state *crtc_state, const struct intel_link_m_n *m_n) { @@ -5898,267 +5647,6 @@ void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_s intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2); } -static void vlv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - u32 mdiv; - u32 bestn, bestm1, bestm2, bestp1, bestp2; - u32 coreclk, reg_val; - - /* Enable Refclk */ - intel_de_write(dev_priv, DPLL(pipe), - pipe_config->dpll_hw_state.dpll & ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV)); - - /* No need to actually set up the DPLL with DSI */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - - bestn = pipe_config->dpll.n; - bestm1 = pipe_config->dpll.m1; - bestm2 = pipe_config->dpll.m2; - bestp1 = pipe_config->dpll.p1; - bestp2 = pipe_config->dpll.p2; - - /* See eDP HDMI DPIO driver vbios notes doc */ - - /* PLL B needs special handling */ - if (pipe == PIPE_B) - vlv_pllb_recal_opamp(dev_priv, pipe); - - /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); - - /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); - reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); - - /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); - - /* Set idtafcrecal before PLL is enabled */ - mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); - mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); - mdiv |= ((bestn << DPIO_N_SHIFT)); - mdiv |= (1 << DPIO_K_SHIFT); - - /* - * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, - * but we don't support that). - * Note: don't use the DAC post divider as it seems unstable. - */ - mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); - - mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); - - /* Set HBR and RBR LPF coefficients */ - if (pipe_config->port_clock == 162000 || - intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) || - intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), - 0x009f0003); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), - 0x00d0000f); - - if (intel_crtc_has_dp_encoder(pipe_config)) { - /* Use SSC source */ - if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df40000); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df70000); - } else { /* HDMI or VGA */ - /* Use bend source */ - if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df70000); - else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), - 0x0df40000); - } - - coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); - coreclk = (coreclk & 0x0000ff00) | 0x01c00000; - if (intel_crtc_has_dp_encoder(pipe_config)) - coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); - - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); - - vlv_dpio_put(dev_priv); -} - -static void chv_prepare_pll(struct intel_crtc *crtc, - const struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - u32 loopfilter, tribuf_calcntr; - u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; - u32 dpio_val; - int vco; - - /* Enable Refclk and SSC */ - intel_de_write(dev_priv, DPLL(pipe), - pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); - - /* No need to actually set up the DPLL with DSI */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - bestn = pipe_config->dpll.n; - bestm2_frac = pipe_config->dpll.m2 & 0x3fffff; - bestm1 = pipe_config->dpll.m1; - bestm2 = pipe_config->dpll.m2 >> 22; - bestp1 = pipe_config->dpll.p1; - bestp2 = pipe_config->dpll.p2; - vco = pipe_config->dpll.vco; - dpio_val = 0; - loopfilter = 0; - - vlv_dpio_get(dev_priv); - - /* p1 and p2 divider */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), - 5 << DPIO_CHV_S1_DIV_SHIFT | - bestp1 << DPIO_CHV_P1_DIV_SHIFT | - bestp2 << DPIO_CHV_P2_DIV_SHIFT | - 1 << DPIO_CHV_K_DIV_SHIFT); - - /* Feedback post-divider - m2 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); - - /* Feedback refclk divider - n and m1 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), - DPIO_CHV_M1_DIV_BY_2 | - 1 << DPIO_CHV_N_DIV_SHIFT); - - /* M2 fraction division */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); - - /* M2 fraction division enable */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); - dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); - dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); - if (bestm2_frac) - dpio_val |= DPIO_CHV_FRAC_DIV_EN; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); - - /* Program digital lock detect threshold */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); - dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | - DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); - dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); - if (!bestm2_frac) - dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); - - /* Loop filter */ - if (vco == 5400000) { - loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x9; - } else if (vco <= 6200000) { - loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x9; - } else if (vco <= 6480000) { - loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0x8; - } else { - /* Not supported. Apply the same limits as in the max case */ - loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); - loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); - loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); - tribuf_calcntr = 0; - } - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); - - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); - dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; - dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); - - /* AFC Recal */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), - vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | - DPIO_AFC_RECAL); - - vlv_dpio_put(dev_priv); -} - -/** - * vlv_force_pll_on - forcibly enable just the PLL - * @dev_priv: i915 private structure - * @pipe: pipe PLL to enable - * @dpll: PLL configuration - * - * Enable the PLL for @pipe using the supplied @dpll config. To be used - * in cases where we need the PLL enabled even when @pipe is not going to - * be enabled. - */ -int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, - const struct dpll *dpll) -{ - struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); - struct intel_crtc_state *pipe_config; - - pipe_config = intel_crtc_state_alloc(crtc); - if (!pipe_config) - return -ENOMEM; - - pipe_config->cpu_transcoder = (enum transcoder)pipe; - pipe_config->pixel_multiplier = 1; - pipe_config->dpll = *dpll; - - if (IS_CHERRYVIEW(dev_priv)) { - chv_compute_dpll(crtc, pipe_config); - chv_prepare_pll(crtc, pipe_config); - chv_enable_pll(crtc, pipe_config); - } else { - vlv_compute_dpll(crtc, pipe_config); - vlv_prepare_pll(crtc, pipe_config); - vlv_enable_pll(crtc, pipe_config); - } - - kfree(pipe_config); - - return 0; -} - -/** - * vlv_force_pll_off - forcibly disable just the PLL - * @dev_priv: i915 private structure - * @pipe: pipe PLL to disable - * - * Disable the PLL for @pipe. To be used in cases where we need - * the PLL enabled even when @pipe is not going to be enabled. - */ -void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe) -{ - if (IS_CHERRYVIEW(dev_priv)) - chv_disable_pll(dev_priv, pipe); - else - vlv_disable_pll(dev_priv, pipe); -} - - - static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 2bbd2ee9147e8..c80e5a3356ef3 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -594,9 +594,6 @@ void intel_cleanup_plane_fb(struct drm_plane *plane, void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, enum pipe pipe); -int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, - const struct dpll *dpll); -void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe); int lpt_get_iclkip(struct drm_i915_private *dev_priv); bool intel_fuzzy_clock_check(int clock1, int clock2); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 96789fbd4c06e..4f89e0de5dde3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -50,6 +50,7 @@ #include "intel_dp_aux.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" +#include "intel_dpll.h" #include "intel_dpio_phy.h" #include "intel_fifo_underrun.h" #include "intel_hdcp.h" diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index 7ba7f315aaeed..166e9a3a8c09f 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -3,11 +3,13 @@ * Copyright © 2020 Intel Corporation */ #include +#include "intel_crtc.h" #include "intel_display_types.h" #include "intel_display.h" #include "intel_dpll.h" #include "intel_lvds.h" #include "intel_panel.h" +#include "intel_sideband.h" struct intel_limit { struct { @@ -1361,3 +1363,510 @@ intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv) else dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock; } + +static bool i9xx_has_pps(struct drm_i915_private *dev_priv) +{ + if (IS_I830(dev_priv)) + return false; + + return IS_PINEVIEW(dev_priv) || IS_MOBILE(dev_priv); +} + +void i9xx_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + i915_reg_t reg = DPLL(crtc->pipe); + u32 dpll = crtc_state->dpll_hw_state.dpll; + int i; + + assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + if (i9xx_has_pps(dev_priv)) + assert_panel_unlocked(dev_priv, crtc->pipe); + + /* + * Apparently we need to have VGA mode enabled prior to changing + * the P1/P2 dividers. Otherwise the DPLL will keep using the old + * dividers, even though the register value does change. + */ + intel_de_write(dev_priv, reg, dpll & ~DPLL_VGA_MODE_DIS); + intel_de_write(dev_priv, reg, dpll); + + /* Wait for the clocks to stabilize. */ + intel_de_posting_read(dev_priv, reg); + udelay(150); + + if (INTEL_GEN(dev_priv) >= 4) { + intel_de_write(dev_priv, DPLL_MD(crtc->pipe), + crtc_state->dpll_hw_state.dpll_md); + } else { + /* The pixel multiplier can only be updated once the + * DPLL is enabled and the clocks are stable. + * + * So write it again. + */ + intel_de_write(dev_priv, reg, dpll); + } + + /* We do this three times for luck */ + for (i = 0; i < 3; i++) { + intel_de_write(dev_priv, reg, dpll); + intel_de_posting_read(dev_priv, reg); + udelay(150); /* wait for warmup */ + } +} + +static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + u32 reg_val; + + /* + * PLLB opamp always calibrates to max value of 0x3f, force enable it + * and set it to a reasonable value instead. + */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + reg_val |= 0x00000030; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x00ffffff; + reg_val |= 0x8c000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val &= 0xffffff00; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val &= 0x00ffffff; + reg_val |= 0xb0000000; + vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); +} + +static void _vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); + intel_de_posting_read(dev_priv, DPLL(pipe)); + udelay(150); + + if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) + drm_err(&dev_priv->drm, "DPLL %d failed to lock\n", pipe); +} + +void vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + assert_panel_unlocked(dev_priv, pipe); + + if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) + _vlv_enable_pll(crtc, pipe_config); + + intel_de_write(dev_priv, DPLL_MD(pipe), + pipe_config->dpll_hw_state.dpll_md); + intel_de_posting_read(dev_priv, DPLL_MD(pipe)); +} + + +static void _chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 tmp; + + vlv_dpio_get(dev_priv); + + /* Enable back the 10bit clock to display controller */ + tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + tmp |= DPIO_DCLKP_EN; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); + + vlv_dpio_put(dev_priv); + + /* + * Need to wait > 100ns between dclkp clock enable bit and PLL enable. + */ + udelay(1); + + /* Enable PLL */ + intel_de_write(dev_priv, DPLL(pipe), pipe_config->dpll_hw_state.dpll); + + /* Check PLL is locked */ + if (intel_de_wait_for_set(dev_priv, DPLL(pipe), DPLL_LOCK_VLV, 1)) + drm_err(&dev_priv->drm, "PLL %d failed to lock\n", pipe); +} + +void chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder); + + /* PLL is protected by panel, make sure we can write it */ + assert_panel_unlocked(dev_priv, pipe); + + if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) + _chv_enable_pll(crtc, pipe_config); + + if (pipe != PIPE_A) { + /* + * WaPixelRepeatModeFixForC0:chv + * + * DPLLCMD is AWOL. Use chicken bits to propagate + * the value from DPLLBMD to either pipe B or C. + */ + intel_de_write(dev_priv, CBR4_VLV, CBR_DPLLBMD_PIPE(pipe)); + intel_de_write(dev_priv, DPLL_MD(PIPE_B), + pipe_config->dpll_hw_state.dpll_md); + intel_de_write(dev_priv, CBR4_VLV, 0); + dev_priv->chv_dpll_md[pipe] = pipe_config->dpll_hw_state.dpll_md; + + /* + * DPLLB VGA mode also seems to cause problems. + * We should always have it disabled. + */ + drm_WARN_ON(&dev_priv->drm, + (intel_de_read(dev_priv, DPLL(PIPE_B)) & + DPLL_VGA_MODE_DIS) == 0); + } else { + intel_de_write(dev_priv, DPLL_MD(pipe), + pipe_config->dpll_hw_state.dpll_md); + intel_de_posting_read(dev_priv, DPLL_MD(pipe)); + } +} + +void vlv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + u32 mdiv; + u32 bestn, bestm1, bestm2, bestp1, bestp2; + u32 coreclk, reg_val; + + /* Enable Refclk */ + intel_de_write(dev_priv, DPLL(pipe), + pipe_config->dpll_hw_state.dpll & ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV)); + + /* No need to actually set up the DPLL with DSI */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + + bestn = pipe_config->dpll.n; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; + + /* See eDP HDMI DPIO driver vbios notes doc */ + + /* PLL B needs special handling */ + if (pipe == PIPE_B) + vlv_pllb_recal_opamp(dev_priv, pipe); + + /* Set up Tx target for periodic Rcomp update */ + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); + + /* Disable target IRef on PLL */ + reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); + reg_val &= 0x00ffffff; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); + + /* Disable fast lock */ + vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); + + /* Set idtafcrecal before PLL is enabled */ + mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); + mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); + mdiv |= ((bestn << DPIO_N_SHIFT)); + mdiv |= (1 << DPIO_K_SHIFT); + + /* + * Post divider depends on pixel clock rate, DAC vs digital (and LVDS, + * but we don't support that). + * Note: don't use the DAC post divider as it seems unstable. + */ + mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + mdiv |= DPIO_ENABLE_CALIBRATION; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + + /* Set HBR and RBR LPF coefficients */ + if (pipe_config->port_clock == 162000 || + intel_crtc_has_type(pipe_config, INTEL_OUTPUT_ANALOG) || + intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x009f0003); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + 0x00d0000f); + + if (intel_crtc_has_dp_encoder(pipe_config)) { + /* Use SSC source */ + if (pipe == PIPE_A) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + } else { /* HDMI or VGA */ + /* Use bend source */ + if (pipe == PIPE_A) + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df70000); + else + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + 0x0df40000); + } + + coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); + coreclk = (coreclk & 0x0000ff00) | 0x01c00000; + if (intel_crtc_has_dp_encoder(pipe_config)) + coreclk |= 0x01000000; + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); + + vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); + + vlv_dpio_put(dev_priv); +} + +void chv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum pipe pipe = crtc->pipe; + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 loopfilter, tribuf_calcntr; + u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; + u32 dpio_val; + int vco; + + /* Enable Refclk and SSC */ + intel_de_write(dev_priv, DPLL(pipe), + pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE); + + /* No need to actually set up the DPLL with DSI */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + bestn = pipe_config->dpll.n; + bestm2_frac = pipe_config->dpll.m2 & 0x3fffff; + bestm1 = pipe_config->dpll.m1; + bestm2 = pipe_config->dpll.m2 >> 22; + bestp1 = pipe_config->dpll.p1; + bestp2 = pipe_config->dpll.p2; + vco = pipe_config->dpll.vco; + dpio_val = 0; + loopfilter = 0; + + vlv_dpio_get(dev_priv); + + /* p1 and p2 divider */ + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), + 5 << DPIO_CHV_S1_DIV_SHIFT | + bestp1 << DPIO_CHV_P1_DIV_SHIFT | + bestp2 << DPIO_CHV_P2_DIV_SHIFT | + 1 << DPIO_CHV_K_DIV_SHIFT); + + /* Feedback post-divider - m2 */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); + + /* Feedback refclk divider - n and m1 */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), + DPIO_CHV_M1_DIV_BY_2 | + 1 << DPIO_CHV_N_DIV_SHIFT); + + /* M2 fraction division */ + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); + + /* M2 fraction division enable */ + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); + dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); + if (bestm2_frac) + dpio_val |= DPIO_CHV_FRAC_DIV_EN; + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); + + /* Program digital lock detect threshold */ + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); + dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | + DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); + dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); + if (!bestm2_frac) + dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); + + /* Loop filter */ + if (vco == 5400000) { + loopfilter |= (0x3 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x8 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x1 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x9; + } else if (vco <= 6200000) { + loopfilter |= (0x5 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0xB << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x9; + } else if (vco <= 6480000) { + loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0x8; + } else { + /* Not supported. Apply the same limits as in the max case */ + loopfilter |= (0x4 << DPIO_CHV_PROP_COEFF_SHIFT); + loopfilter |= (0x9 << DPIO_CHV_INT_COEFF_SHIFT); + loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); + tribuf_calcntr = 0; + } + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); + + dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); + dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; + dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); + vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); + + /* AFC Recal */ + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), + vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | + DPIO_AFC_RECAL); + + vlv_dpio_put(dev_priv); +} + +/** + * vlv_force_pll_on - forcibly enable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * @dpll: PLL configuration + * + * Enable the PLL for @pipe using the supplied @dpll config. To be used + * in cases where we need the PLL enabled even when @pipe is not going to + * be enabled. + */ +int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, + const struct dpll *dpll) +{ + struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + struct intel_crtc_state *pipe_config; + + pipe_config = intel_crtc_state_alloc(crtc); + if (!pipe_config) + return -ENOMEM; + + pipe_config->cpu_transcoder = (enum transcoder)pipe; + pipe_config->pixel_multiplier = 1; + pipe_config->dpll = *dpll; + + if (IS_CHERRYVIEW(dev_priv)) { + chv_compute_dpll(crtc, pipe_config); + chv_prepare_pll(crtc, pipe_config); + chv_enable_pll(crtc, pipe_config); + } else { + vlv_compute_dpll(crtc, pipe_config); + vlv_prepare_pll(crtc, pipe_config); + vlv_enable_pll(crtc, pipe_config); + } + + kfree(pipe_config); + + return 0; +} + +void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + u32 val; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + + val = DPLL_INTEGRATED_REF_CLK_VLV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + if (pipe != PIPE_A) + val |= DPLL_INTEGRATED_CRI_CLK_VLV; + + intel_de_write(dev_priv, DPLL(pipe), val); + intel_de_posting_read(dev_priv, DPLL(pipe)); +} + +void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + enum dpio_channel port = vlv_pipe_to_channel(pipe); + u32 val; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, (enum transcoder)pipe); + + val = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + if (pipe != PIPE_A) + val |= DPLL_INTEGRATED_CRI_CLK_VLV; + + intel_de_write(dev_priv, DPLL(pipe), val); + intel_de_posting_read(dev_priv, DPLL(pipe)); + + vlv_dpio_get(dev_priv); + + /* Disable 10bit clock to display controller */ + val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + val &= ~DPIO_DCLKP_EN; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); + + vlv_dpio_put(dev_priv); +} + +void i9xx_disable_pll(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); + enum pipe pipe = crtc->pipe; + + /* Don't disable pipe or pipe PLLs if needed */ + if (IS_I830(dev_priv)) + return; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, crtc_state->cpu_transcoder); + + intel_de_write(dev_priv, DPLL(pipe), DPLL_VGA_MODE_DIS); + intel_de_posting_read(dev_priv, DPLL(pipe)); +} + + +/** + * vlv_force_pll_off - forcibly disable just the PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to disable + * + * Disable the PLL for @pipe. To be used in cases where we need + * the PLL enabled even when @pipe is not going to be enabled. + */ +void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + if (IS_CHERRYVIEW(dev_priv)) + chv_disable_pll(dev_priv, pipe); + else + vlv_disable_pll(dev_priv, pipe); +} diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index caf4615092e1e..7ff4b0d29ed11 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -10,6 +10,7 @@ struct dpll; struct drm_i915_private; struct intel_crtc; struct intel_crtc_state; +enum pipe; void intel_dpll_init_clock_hook(struct drm_i915_private *dev_priv); int vlv_calc_dpll_params(int refclk, struct dpll *clock); @@ -20,4 +21,21 @@ void vlv_compute_dpll(struct intel_crtc *crtc, void chv_compute_dpll(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); +int vlv_force_pll_on(struct drm_i915_private *dev_priv, enum pipe pipe, + const struct dpll *dpll); +void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *crtc_state); +void vlv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void chv_enable_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); +void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_disable_pll(const struct intel_crtc_state *crtc_state); +void vlv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); +void chv_prepare_pll(struct intel_crtc *crtc, + const struct intel_crtc_state *pipe_config); + #endif diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index c4867a8020a5b..f20ba71f43076 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -6,6 +6,7 @@ #include "i915_drv.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dpll.h" #include "intel_pps.h" static void vlv_steal_power_sequencer(struct drm_i915_private *dev_priv, From 2a3014490cd18a5d0a95c6efd406cf90d69e2a44 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:41 +0200 Subject: [PATCH 048/142] drm/i915: migrate i9xx plane get config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate this code out like the skylake code. Signed-off-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/c003bd458a6bcc703e9e2fb05731fb7124012e8c.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/i9xx_plane.c | 119 +++++++++++++++++++ drivers/gpu/drm/i915/display/i9xx_plane.h | 4 + drivers/gpu/drm/i915/display/intel_display.c | 119 ------------------- 3 files changed, 123 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index d116dee201aa0..0523e2c79d161 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -893,3 +893,122 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) return ERR_PTR(ret); } +static int i9xx_format_to_fourcc(int format) +{ + switch (format) { + case DISPPLANE_8BPP: + return DRM_FORMAT_C8; + case DISPPLANE_BGRA555: + return DRM_FORMAT_ARGB1555; + case DISPPLANE_BGRX555: + return DRM_FORMAT_XRGB1555; + case DISPPLANE_BGRX565: + return DRM_FORMAT_RGB565; + default: + case DISPPLANE_BGRX888: + return DRM_FORMAT_XRGB8888; + case DISPPLANE_RGBX888: + return DRM_FORMAT_XBGR8888; + case DISPPLANE_BGRA888: + return DRM_FORMAT_ARGB8888; + case DISPPLANE_RGBA888: + return DRM_FORMAT_ABGR8888; + case DISPPLANE_BGRX101010: + return DRM_FORMAT_XRGB2101010; + case DISPPLANE_RGBX101010: + return DRM_FORMAT_XBGR2101010; + case DISPPLANE_BGRA101010: + return DRM_FORMAT_ARGB2101010; + case DISPPLANE_RGBA101010: + return DRM_FORMAT_ABGR2101010; + case DISPPLANE_RGBX161616: + return DRM_FORMAT_XBGR16161616F; + } +} + +void +i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane = to_intel_plane(crtc->base.primary); + enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; + enum pipe pipe; + u32 val, base, offset; + int fourcc, pixel_format; + unsigned int aligned_height; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + + if (!plane->get_hw_state(plane, &pipe)) + return; + + drm_WARN_ON(dev, pipe != crtc->pipe); + + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) { + drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); + return; + } + + fb = &intel_fb->base; + + fb->dev = dev; + + val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); + + if (INTEL_GEN(dev_priv) >= 4) { + if (val & DISPPLANE_TILED) { + plane_config->tiling = I915_TILING_X; + fb->modifier = I915_FORMAT_MOD_X_TILED; + } + + if (val & DISPPLANE_ROTATE_180) + plane_config->rotation = DRM_MODE_ROTATE_180; + } + + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && + val & DISPPLANE_MIRROR) + plane_config->rotation |= DRM_MODE_REFLECT_X; + + pixel_format = val & DISPPLANE_PIXFORMAT_MASK; + fourcc = i9xx_format_to_fourcc(pixel_format); + fb->format = drm_format_info(fourcc); + + if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { + offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; + } else if (INTEL_GEN(dev_priv) >= 4) { + if (plane_config->tiling) + offset = intel_de_read(dev_priv, + DSPTILEOFF(i9xx_plane)); + else + offset = intel_de_read(dev_priv, + DSPLINOFF(i9xx_plane)); + base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; + } else { + base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); + } + plane_config->base = base; + + val = intel_de_read(dev_priv, PIPESRC(pipe)); + fb->width = ((val >> 16) & 0xfff) + 1; + fb->height = ((val >> 0) & 0xfff) + 1; + + val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane)); + fb->pitches[0] = val & 0xffffffc0; + + aligned_height = intel_fb_align_height(fb, 0, fb->height); + + plane_config->size = fb->pitches[0] * aligned_height; + + drm_dbg_kms(&dev_priv->drm, + "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", + crtc->base.name, plane->base.name, fb->width, fb->height, + fb->format->cpp[0] * 8, base, fb->pitches[0], + plane_config->size); + + plane_config->fb = intel_fb; +} + diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.h b/drivers/gpu/drm/i915/display/i9xx_plane.h index ca963c2a84573..027b660539845 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.h +++ b/drivers/gpu/drm/i915/display/i9xx_plane.h @@ -10,6 +10,8 @@ enum pipe; struct drm_i915_private; +struct intel_crtc; +struct intel_initial_plane_config; struct intel_plane; struct intel_plane_state; @@ -21,4 +23,6 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state); struct intel_plane * intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe); +void i9xx_get_initial_plane_config(struct intel_crtc *crtc, + struct intel_initial_plane_config *plane_config); #endif diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ef29065ea72e0..492ef7507cb3c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2209,39 +2209,6 @@ intel_plane_compute_gtt(struct intel_plane_state *plane_state) return intel_plane_check_stride(plane_state); } -static int i9xx_format_to_fourcc(int format) -{ - switch (format) { - case DISPPLANE_8BPP: - return DRM_FORMAT_C8; - case DISPPLANE_BGRA555: - return DRM_FORMAT_ARGB1555; - case DISPPLANE_BGRX555: - return DRM_FORMAT_XRGB1555; - case DISPPLANE_BGRX565: - return DRM_FORMAT_RGB565; - default: - case DISPPLANE_BGRX888: - return DRM_FORMAT_XRGB8888; - case DISPPLANE_RGBX888: - return DRM_FORMAT_XBGR8888; - case DISPPLANE_BGRA888: - return DRM_FORMAT_ARGB8888; - case DISPPLANE_RGBA888: - return DRM_FORMAT_ABGR8888; - case DISPPLANE_BGRX101010: - return DRM_FORMAT_XRGB2101010; - case DISPPLANE_RGBX101010: - return DRM_FORMAT_XBGR2101010; - case DISPPLANE_BGRA101010: - return DRM_FORMAT_ARGB2101010; - case DISPPLANE_RGBA101010: - return DRM_FORMAT_ABGR2101010; - case DISPPLANE_RGBX161616: - return DRM_FORMAT_XBGR16161616F; - } -} - static struct i915_vma * initial_plane_vma(struct drm_i915_private *i915, struct intel_initial_plane_config *plane_config) @@ -5914,92 +5881,6 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); } -static void -i9xx_get_initial_plane_config(struct intel_crtc *crtc, - struct intel_initial_plane_config *plane_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_plane *plane = to_intel_plane(crtc->base.primary); - enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; - enum pipe pipe; - u32 val, base, offset; - int fourcc, pixel_format; - unsigned int aligned_height; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - - if (!plane->get_hw_state(plane, &pipe)) - return; - - drm_WARN_ON(dev, pipe != crtc->pipe); - - intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) { - drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n"); - return; - } - - fb = &intel_fb->base; - - fb->dev = dev; - - val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane)); - - if (INTEL_GEN(dev_priv) >= 4) { - if (val & DISPPLANE_TILED) { - plane_config->tiling = I915_TILING_X; - fb->modifier = I915_FORMAT_MOD_X_TILED; - } - - if (val & DISPPLANE_ROTATE_180) - plane_config->rotation = DRM_MODE_ROTATE_180; - } - - if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B && - val & DISPPLANE_MIRROR) - plane_config->rotation |= DRM_MODE_REFLECT_X; - - pixel_format = val & DISPPLANE_PIXFORMAT_MASK; - fourcc = i9xx_format_to_fourcc(pixel_format); - fb->format = drm_format_info(fourcc); - - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { - offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; - } else if (INTEL_GEN(dev_priv) >= 4) { - if (plane_config->tiling) - offset = intel_de_read(dev_priv, - DSPTILEOFF(i9xx_plane)); - else - offset = intel_de_read(dev_priv, - DSPLINOFF(i9xx_plane)); - base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & 0xfffff000; - } else { - base = intel_de_read(dev_priv, DSPADDR(i9xx_plane)); - } - plane_config->base = base; - - val = intel_de_read(dev_priv, PIPESRC(pipe)); - fb->width = ((val >> 16) & 0xfff) + 1; - fb->height = ((val >> 0) & 0xfff) + 1; - - val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane)); - fb->pitches[0] = val & 0xffffffc0; - - aligned_height = intel_fb_align_height(fb, 0, fb->height); - - plane_config->size = fb->pitches[0] * aligned_height; - - drm_dbg_kms(&dev_priv->drm, - "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - crtc->base.name, plane->base.name, fb->width, fb->height, - fb->format->cpp[0] * 8, base, fb->pitches[0], - plane_config->size); - - plane_config->fb = intel_fb; -} - static void chv_crtc_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { From 714b1cdb02ee670be1ec5b1190377fef3845acd9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Feb 2021 16:48:42 +0200 Subject: [PATCH 049/142] drm/i915: refactor skylake scaler code into new file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the code from various places and consolidates it into one new file. v2: - rename skl_program_plane -> skl_program_plane_scaler (Ville) - also move skl_pfit_enable, and consequently make some skl_scaler_* functions static to skl_scaler.c (Ville) Signed-off-by: Dave Airlie Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/2fa703ffc7b96a41c392fd5ebbd2e6e4ffb6fb05.1612536383.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/icl_dsi.c | 1 + drivers/gpu/drm/i915/display/intel_atomic.c | 2 +- drivers/gpu/drm/i915/display/intel_ddi.c | 1 + drivers/gpu/drm/i915/display/intel_display.c | 488 +-------------- drivers/gpu/drm/i915/display/intel_display.h | 6 - drivers/gpu/drm/i915/display/intel_dp_mst.c | 1 + drivers/gpu/drm/i915/display/intel_sprite.c | 62 -- drivers/gpu/drm/i915/display/intel_sprite.h | 7 - drivers/gpu/drm/i915/display/skl_scaler.c | 556 ++++++++++++++++++ drivers/gpu/drm/i915/display/skl_scaler.h | 29 + .../drm/i915/display/skl_universal_plane.c | 3 +- .../drm/i915/display/skl_universal_plane.h | 4 + drivers/gpu/drm/i915/display/vlv_dsi.c | 1 + 14 files changed, 598 insertions(+), 564 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.c create mode 100644 drivers/gpu/drm/i915/display/skl_scaler.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 40cba6f0792de..b4f0c0942fc92 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -224,6 +224,7 @@ i915-y += \ display/intel_tc.o \ display/intel_vga.o \ display/i9xx_plane.o \ + display/skl_scaler.o \ display/skl_universal_plane.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 9eeec6fadec72..7ef6b89c79d91 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -35,6 +35,7 @@ #include "intel_dsi.h" #include "intel_panel.h" #include "intel_vdsc.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static int header_credits_available(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index e00fdc47c0eb9..27f7d7109ca3b 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -40,7 +40,7 @@ #include "intel_global_state.h" #include "intel_hdcp.h" #include "intel_psr.h" -#include "intel_sprite.h" +#include "skl_universal_plane.h" /** * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property. diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f4746c1edabe8..3c4003605f93c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -54,6 +54,7 @@ #include "intel_tc.h" #include "intel_vdsc.h" #include "intel_vrr.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static const u8 index_to_dp_signal_levels[] = { diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 492ef7507cb3c..788ce9496d983 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -94,6 +94,7 @@ #include "intel_tc.h" #include "intel_vga.h" #include "i9xx_plane.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static void i9xx_crtc_clock_get(struct intel_crtc *crtc, @@ -2524,38 +2525,6 @@ intel_plane_fence_y_offset(const struct intel_plane_state *plane_state) return y; } -static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) -{ - struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - unsigned long irqflags; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0); - intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); - intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - -/* - * This function detaches (aka. unbinds) unused scalers in hardware - */ -static void skl_detach_scalers(const struct intel_crtc_state *crtc_state) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); - const struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - int i; - - /* loop through and disable scalers that aren't in use */ - for (i = 0; i < intel_crtc->num_scalers; i++) { - if (!scaler_state->scalers[i].in_use) - skl_detach_scaler(intel_crtc, i); - } -} - static int __intel_display_resume(struct drm_device *dev, struct drm_atomic_state *state, @@ -3120,461 +3089,6 @@ static void cpt_verify_modeset(struct drm_i915_private *dev_priv, } } -/* - * The hardware phase 0.0 refers to the center of the pixel. - * We want to start from the top/left edge which is phase - * -0.5. That matches how the hardware calculates the scaling - * factors (from top-left of the first pixel to bottom-right - * of the last pixel, as opposed to the pixel centers). - * - * For 4:2:0 subsampled chroma planes we obviously have to - * adjust that so that the chroma sample position lands in - * the right spot. - * - * Note that for packed YCbCr 4:2:2 formats there is no way to - * control chroma siting. The hardware simply replicates the - * chroma samples for both of the luma samples, and thus we don't - * actually get the expected MPEG2 chroma siting convention :( - * The same behaviour is observed on pre-SKL platforms as well. - * - * Theory behind the formula (note that we ignore sub-pixel - * source coordinates): - * s = source sample position - * d = destination sample position - * - * Downscaling 4:1: - * -0.5 - * | 0.0 - * | | 1.5 (initial phase) - * | | | - * v v v - * | s | s | s | s | - * | d | - * - * Upscaling 1:4: - * -0.5 - * | -0.375 (initial phase) - * | | 0.0 - * | | | - * v v v - * | s | - * | d | d | d | d | - */ -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) -{ - int phase = -0x8000; - u16 trip = 0; - - if (chroma_cosited) - phase += (sub - 1) * 0x8000 / sub; - - phase += scale / (2 * sub); - - /* - * Hardware initial phase limited to [-0.5:1.5]. - * Since the max hardware scale factor is 3.0, we - * should never actually excdeed 1.0 here. - */ - WARN_ON(phase < -0x8000 || phase > 0x18000); - - if (phase < 0) - phase = 0x10000 + phase; - else - trip = PS_PHASE_TRIP; - - return ((phase >> 2) & PS_PHASE_MASK) | trip; -} - -#define SKL_MIN_SRC_W 8 -#define SKL_MAX_SRC_W 4096 -#define SKL_MIN_SRC_H 8 -#define SKL_MAX_SRC_H 4096 -#define SKL_MIN_DST_W 8 -#define SKL_MAX_DST_W 4096 -#define SKL_MIN_DST_H 8 -#define SKL_MAX_DST_H 4096 -#define ICL_MAX_SRC_W 5120 -#define ICL_MAX_SRC_H 4096 -#define ICL_MAX_DST_W 5120 -#define ICL_MAX_DST_H 4096 -#define SKL_MIN_YUV_420_SRC_W 16 -#define SKL_MIN_YUV_420_SRC_H 16 - -static int -skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, - unsigned int scaler_user, int *scaler_id, - int src_w, int src_h, int dst_w, int dst_h, - const struct drm_format_info *format, - u64 modifier, bool need_scaler) -{ - struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - struct intel_crtc *intel_crtc = - to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - - /* - * Src coordinates are already rotated by 270 degrees for - * the 90/270 degree plane rotation cases (to match the - * GTT mapping), hence no need to account for rotation here. - */ - if (src_w != dst_w || src_h != dst_h) - need_scaler = true; - - /* - * Scaling/fitting not supported in IF-ID mode in GEN9+ - * TODO: Interlace fetch mode doesn't support YUV420 planar formats. - * Once NV12 is enabled, handle it here while allocating scaler - * for NV12. - */ - if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable && - need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - drm_dbg_kms(&dev_priv->drm, - "Pipe/Plane scaling not supported with IF-ID mode\n"); - return -EINVAL; - } - - /* - * if plane is being disabled or scaler is no more required or force detach - * - free scaler binded to this plane/crtc - * - in order to do this, update crtc->scaler_usage - * - * Here scaler state in crtc_state is set free so that - * scaler can be assigned to other user. Actual register - * update to free the scaler is done in plane/panel-fit programming. - * For this purpose crtc/plane_state->scaler_id isn't reset here. - */ - if (force_detach || !need_scaler) { - if (*scaler_id >= 0) { - scaler_state->scaler_users &= ~(1 << scaler_user); - scaler_state->scalers[*scaler_id].in_use = 0; - - drm_dbg_kms(&dev_priv->drm, - "scaler_user index %u.%u: " - "Staged freeing scaler id %d scaler_users = 0x%x\n", - intel_crtc->pipe, scaler_user, *scaler_id, - scaler_state->scaler_users); - *scaler_id = -1; - } - return 0; - } - - if (format && intel_format_info_is_yuv_semiplanar(format, modifier) && - (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) { - drm_dbg_kms(&dev_priv->drm, - "Planar YUV: src dimensions not met\n"); - return -EINVAL; - } - - /* range checks */ - if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || - dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || - (INTEL_GEN(dev_priv) >= 11 && - (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || - dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || - (INTEL_GEN(dev_priv) < 11 && - (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || - dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { - drm_dbg_kms(&dev_priv->drm, - "scaler_user index %u.%u: src %ux%u dst %ux%u " - "size is out of scaler range\n", - intel_crtc->pipe, scaler_user, src_w, src_h, - dst_w, dst_h); - return -EINVAL; - } - - /* mark this plane as a scaler user in crtc_state */ - scaler_state->scaler_users |= (1 << scaler_user); - drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " - "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", - intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, - scaler_state->scaler_users); - - return 0; -} - -static int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) -{ - const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; - int width, height; - - if (crtc_state->pch_pfit.enabled) { - width = drm_rect_width(&crtc_state->pch_pfit.dst); - height = drm_rect_height(&crtc_state->pch_pfit.dst); - } else { - width = pipe_mode->crtc_hdisplay; - height = pipe_mode->crtc_vdisplay; - } - return skl_update_scaler(crtc_state, !crtc_state->hw.active, - SKL_CRTC_INDEX, - &crtc_state->scaler_state.scaler_id, - crtc_state->pipe_src_w, crtc_state->pipe_src_h, - width, height, NULL, 0, - crtc_state->pch_pfit.enabled); -} - -/** - * skl_update_scaler_plane - Stages update to scaler state for a given plane. - * @crtc_state: crtc's scaler state - * @plane_state: atomic plane state to update - * - * Return - * 0 - scaler_usage updated successfully - * error - requested scaling cannot be supported or other error condition - */ -static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) -{ - struct intel_plane *intel_plane = - to_intel_plane(plane_state->uapi.plane); - struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); - struct drm_framebuffer *fb = plane_state->hw.fb; - int ret; - bool force_detach = !fb || !plane_state->uapi.visible; - bool need_scaler = false; - - /* Pre-gen11 and SDR planes always need a scaler for planar formats. */ - if (!icl_is_hdr_plane(dev_priv, intel_plane->id) && - fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) - need_scaler = true; - - ret = skl_update_scaler(crtc_state, force_detach, - drm_plane_index(&intel_plane->base), - &plane_state->scaler_id, - drm_rect_width(&plane_state->uapi.src) >> 16, - drm_rect_height(&plane_state->uapi.src) >> 16, - drm_rect_width(&plane_state->uapi.dst), - drm_rect_height(&plane_state->uapi.dst), - fb ? fb->format : NULL, - fb ? fb->modifier : 0, - need_scaler); - - if (ret || plane_state->scaler_id < 0) - return ret; - - /* check colorkey */ - if (plane_state->ckey.flags) { - drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] scaling with color key not allowed", - intel_plane->base.base.id, - intel_plane->base.name); - return -EINVAL; - } - - /* Check src format */ - switch (fb->format->format) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - case DRM_FORMAT_NV12: - case DRM_FORMAT_XYUV8888: - case DRM_FORMAT_P010: - case DRM_FORMAT_P012: - case DRM_FORMAT_P016: - case DRM_FORMAT_Y210: - case DRM_FORMAT_Y212: - case DRM_FORMAT_Y216: - case DRM_FORMAT_XVYU2101010: - case DRM_FORMAT_XVYU12_16161616: - case DRM_FORMAT_XVYU16161616: - break; - case DRM_FORMAT_XBGR16161616F: - case DRM_FORMAT_ABGR16161616F: - case DRM_FORMAT_XRGB16161616F: - case DRM_FORMAT_ARGB16161616F: - if (INTEL_GEN(dev_priv) >= 11) - break; - fallthrough; - default: - drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", - intel_plane->base.base.id, intel_plane->base.name, - fb->base.id, fb->format->format); - return -EINVAL; - } - - return 0; -} - -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) -{ - struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); - int i; - - for (i = 0; i < crtc->num_scalers; i++) - skl_detach_scaler(crtc, i); -} - -static int cnl_coef_tap(int i) -{ - return i % 7; -} - -static u16 cnl_nearest_filter_coef(int t) -{ - return t == 3 ? 0x0800 : 0x3000; -} - -/* - * Theory behind setting nearest-neighbor integer scaling: - * - * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. - * The letter represents the filter tap (D is the center tap) and the number - * represents the coefficient set for a phase (0-16). - * - * +------------+------------------------+------------------------+ - * |Index value | Data value coeffient 1 | Data value coeffient 2 | - * +------------+------------------------+------------------------+ - * | 00h | B0 | A0 | - * +------------+------------------------+------------------------+ - * | 01h | D0 | C0 | - * +------------+------------------------+------------------------+ - * | 02h | F0 | E0 | - * +------------+------------------------+------------------------+ - * | 03h | A1 | G0 | - * +------------+------------------------+------------------------+ - * | 04h | C1 | B1 | - * +------------+------------------------+------------------------+ - * | ... | ... | ... | - * +------------+------------------------+------------------------+ - * | 38h | B16 | A16 | - * +------------+------------------------+------------------------+ - * | 39h | D16 | C16 | - * +------------+------------------------+------------------------+ - * | 3Ah | F16 | C16 | - * +------------+------------------------+------------------------+ - * | 3Bh | Reserved | G16 | - * +------------+------------------------+------------------------+ - * - * To enable nearest-neighbor scaling: program scaler coefficents with - * the center tap (Dxx) values set to 1 and all other values set to 0 as per - * SCALER_COEFFICIENT_FORMAT - * - */ - -static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, - enum pipe pipe, int id, int set) -{ - int i; - - intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), - PS_COEE_INDEX_AUTO_INC); - - for (i = 0; i < 17 * 7; i += 2) { - u32 tmp; - int t; - - t = cnl_coef_tap(i); - tmp = cnl_nearest_filter_coef(t); - - t = cnl_coef_tap(i + 1); - tmp |= cnl_nearest_filter_coef(t) << 16; - - intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set), - tmp); - } - - intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0); -} - -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) -{ - if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) { - return (PS_FILTER_PROGRAMMED | - PS_Y_VERT_FILTER_SELECT(set) | - PS_Y_HORZ_FILTER_SELECT(set) | - PS_UV_VERT_FILTER_SELECT(set) | - PS_UV_HORZ_FILTER_SELECT(set)); - } - - return PS_FILTER_MEDIUM; -} - -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, - int id, int set, enum drm_scaling_filter filter) -{ - switch (filter) { - case DRM_SCALING_FILTER_DEFAULT: - break; - case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: - cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set); - break; - default: - MISSING_CASE(filter); - } -} - -static void skl_pfit_enable(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); - const struct intel_crtc_scaler_state *scaler_state = - &crtc_state->scaler_state; - struct drm_rect src = { - .x2 = crtc_state->pipe_src_w << 16, - .y2 = crtc_state->pipe_src_h << 16, - }; - const struct drm_rect *dst = &crtc_state->pch_pfit.dst; - u16 uv_rgb_hphase, uv_rgb_vphase; - enum pipe pipe = crtc->pipe; - int width = drm_rect_width(dst); - int height = drm_rect_height(dst); - int x = dst->x1; - int y = dst->y1; - int hscale, vscale; - unsigned long irqflags; - int id; - u32 ps_ctrl; - - if (!crtc_state->pch_pfit.enabled) - return; - - if (drm_WARN_ON(&dev_priv->drm, - crtc_state->scaler_state.scaler_id < 0)) - return; - - hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX); - vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX); - - uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); - uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); - - id = scaler_state->scaler_id; - - ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0); - ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode; - - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); - - skl_scaler_setup_filter(dev_priv, pipe, id, 0, - crtc_state->hw.scaling_filter); - - intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl); - - intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id), - PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase)); - intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id), - PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase)); - intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id), - x << 16 | y); - intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id), - width << 16 | height); - - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); -} - static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index c80e5a3356ef3..e3757ecabbf78 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -618,12 +618,6 @@ enum intel_display_power_domain intel_legacy_aux_to_power_domain(enum aux_ch aux_ch); void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); - -u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_center); -void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); -u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set); -void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, - int id, int set, enum drm_scaling_filter filter); void ilk_pfit_disable(const struct intel_crtc_state *old_crtc_state); int bdw_get_pipemisc_bpp(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index b4621ed0127e7..8e316146b6d16 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -39,6 +39,7 @@ #include "intel_dp_mst.h" #include "intel_dpio_phy.h" #include "intel_hdcp.h" +#include "skl_scaler.h" static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 46fcb5b9983f2..4cbdb8fd4bb12 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -138,68 +138,6 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } -void -skl_program_scaler(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->hw.fb; - enum pipe pipe = plane->pipe; - int scaler_id = plane_state->scaler_id; - const struct intel_scaler *scaler = - &crtc_state->scaler_state.scalers[scaler_id]; - int crtc_x = plane_state->uapi.dst.x1; - int crtc_y = plane_state->uapi.dst.y1; - u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); - u32 crtc_h = drm_rect_height(&plane_state->uapi.dst); - u16 y_hphase, uv_rgb_hphase; - u16 y_vphase, uv_rgb_vphase; - int hscale, vscale; - u32 ps_ctrl; - - hscale = drm_rect_calc_hscale(&plane_state->uapi.src, - &plane_state->uapi.dst, - 0, INT_MAX); - vscale = drm_rect_calc_vscale(&plane_state->uapi.src, - &plane_state->uapi.dst, - 0, INT_MAX); - - /* TODO: handle sub-pixel coordinates */ - if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && - !icl_is_hdr_plane(dev_priv, plane->id)) { - y_hphase = skl_scaler_calc_phase(1, hscale, false); - y_vphase = skl_scaler_calc_phase(1, vscale, false); - - /* MPEG2 chroma siting convention */ - uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true); - uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false); - } else { - /* not used */ - y_hphase = 0; - y_vphase = 0; - - uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); - uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); - } - - ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0); - ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode; - - skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0, - plane_state->hw.scaling_filter); - - intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); - intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id), - PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); - intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id), - PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); - intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id), - (crtc_x << 16) | crtc_y); - intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id), - (crtc_w << 16) | crtc_h); -} - static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ diff --git a/drivers/gpu/drm/i915/display/intel_sprite.h b/drivers/gpu/drm/i915/display/intel_sprite.h index 418897f953fc2..f6989da2dc4bd 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.h +++ b/drivers/gpu/drm/i915/display/intel_sprite.h @@ -45,10 +45,6 @@ static inline u8 icl_hdr_plane_mask(void) BIT(PLANE_SPRITE0) | BIT(PLANE_SPRITE1); } -bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, - enum plane_id plane_id); -bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); - int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, @@ -56,7 +52,4 @@ int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state, int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); -void skl_program_scaler(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); #endif /* __INTEL_SPRITE_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c b/drivers/gpu/drm/i915/display/skl_scaler.c new file mode 100644 index 0000000000000..b37a87bb190f2 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_scaler.c @@ -0,0 +1,556 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2020 Intel Corporation + */ +#include "intel_display_types.h" +#include "skl_scaler.h" +#include "skl_universal_plane.h" + +/* + * The hardware phase 0.0 refers to the center of the pixel. + * We want to start from the top/left edge which is phase + * -0.5. That matches how the hardware calculates the scaling + * factors (from top-left of the first pixel to bottom-right + * of the last pixel, as opposed to the pixel centers). + * + * For 4:2:0 subsampled chroma planes we obviously have to + * adjust that so that the chroma sample position lands in + * the right spot. + * + * Note that for packed YCbCr 4:2:2 formats there is no way to + * control chroma siting. The hardware simply replicates the + * chroma samples for both of the luma samples, and thus we don't + * actually get the expected MPEG2 chroma siting convention :( + * The same behaviour is observed on pre-SKL platforms as well. + * + * Theory behind the formula (note that we ignore sub-pixel + * source coordinates): + * s = source sample position + * d = destination sample position + * + * Downscaling 4:1: + * -0.5 + * | 0.0 + * | | 1.5 (initial phase) + * | | | + * v v v + * | s | s | s | s | + * | d | + * + * Upscaling 1:4: + * -0.5 + * | -0.375 (initial phase) + * | | 0.0 + * | | | + * v v v + * | s | + * | d | d | d | d | + */ +static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) +{ + int phase = -0x8000; + u16 trip = 0; + + if (chroma_cosited) + phase += (sub - 1) * 0x8000 / sub; + + phase += scale / (2 * sub); + + /* + * Hardware initial phase limited to [-0.5:1.5]. + * Since the max hardware scale factor is 3.0, we + * should never actually excdeed 1.0 here. + */ + WARN_ON(phase < -0x8000 || phase > 0x18000); + + if (phase < 0) + phase = 0x10000 + phase; + else + trip = PS_PHASE_TRIP; + + return ((phase >> 2) & PS_PHASE_MASK) | trip; +} + +#define SKL_MIN_SRC_W 8 +#define SKL_MAX_SRC_W 4096 +#define SKL_MIN_SRC_H 8 +#define SKL_MAX_SRC_H 4096 +#define SKL_MIN_DST_W 8 +#define SKL_MAX_DST_W 4096 +#define SKL_MIN_DST_H 8 +#define SKL_MAX_DST_H 4096 +#define ICL_MAX_SRC_W 5120 +#define ICL_MAX_SRC_H 4096 +#define ICL_MAX_DST_W 5120 +#define ICL_MAX_DST_H 4096 +#define SKL_MIN_YUV_420_SRC_W 16 +#define SKL_MIN_YUV_420_SRC_H 16 + +static int +skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, + unsigned int scaler_user, int *scaler_id, + int src_w, int src_h, int dst_w, int dst_h, + const struct drm_format_info *format, + u64 modifier, bool need_scaler) +{ + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct intel_crtc *intel_crtc = + to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + /* + * Src coordinates are already rotated by 270 degrees for + * the 90/270 degree plane rotation cases (to match the + * GTT mapping), hence no need to account for rotation here. + */ + if (src_w != dst_w || src_h != dst_h) + need_scaler = true; + + /* + * Scaling/fitting not supported in IF-ID mode in GEN9+ + * TODO: Interlace fetch mode doesn't support YUV420 planar formats. + * Once NV12 is enabled, handle it here while allocating scaler + * for NV12. + */ + if (INTEL_GEN(dev_priv) >= 9 && crtc_state->hw.enable && + need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + drm_dbg_kms(&dev_priv->drm, + "Pipe/Plane scaling not supported with IF-ID mode\n"); + return -EINVAL; + } + + /* + * if plane is being disabled or scaler is no more required or force detach + * - free scaler binded to this plane/crtc + * - in order to do this, update crtc->scaler_usage + * + * Here scaler state in crtc_state is set free so that + * scaler can be assigned to other user. Actual register + * update to free the scaler is done in plane/panel-fit programming. + * For this purpose crtc/plane_state->scaler_id isn't reset here. + */ + if (force_detach || !need_scaler) { + if (*scaler_id >= 0) { + scaler_state->scaler_users &= ~(1 << scaler_user); + scaler_state->scalers[*scaler_id].in_use = 0; + + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: " + "Staged freeing scaler id %d scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, *scaler_id, + scaler_state->scaler_users); + *scaler_id = -1; + } + return 0; + } + + if (format && intel_format_info_is_yuv_semiplanar(format, modifier) && + (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) { + drm_dbg_kms(&dev_priv->drm, + "Planar YUV: src dimensions not met\n"); + return -EINVAL; + } + + /* range checks */ + if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H || + dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H || + (INTEL_GEN(dev_priv) >= 11 && + (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H || + dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) || + (INTEL_GEN(dev_priv) < 11 && + (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || + dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) { + drm_dbg_kms(&dev_priv->drm, + "scaler_user index %u.%u: src %ux%u dst %ux%u " + "size is out of scaler range\n", + intel_crtc->pipe, scaler_user, src_w, src_h, + dst_w, dst_h); + return -EINVAL; + } + + /* mark this plane as a scaler user in crtc_state */ + scaler_state->scaler_users |= (1 << scaler_user); + drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: " + "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, + scaler_state->scaler_users); + + return 0; +} + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + int width, height; + + if (crtc_state->pch_pfit.enabled) { + width = drm_rect_width(&crtc_state->pch_pfit.dst); + height = drm_rect_height(&crtc_state->pch_pfit.dst); + } else { + width = pipe_mode->crtc_hdisplay; + height = pipe_mode->crtc_vdisplay; + } + return skl_update_scaler(crtc_state, !crtc_state->hw.active, + SKL_CRTC_INDEX, + &crtc_state->scaler_state.scaler_id, + crtc_state->pipe_src_w, crtc_state->pipe_src_h, + width, height, NULL, 0, + crtc_state->pch_pfit.enabled); +} + +/** + * skl_update_scaler_plane - Stages update to scaler state for a given plane. + * @crtc_state: crtc's scaler state + * @plane_state: atomic plane state to update + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *intel_plane = + to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); + struct drm_framebuffer *fb = plane_state->hw.fb; + int ret; + bool force_detach = !fb || !plane_state->uapi.visible; + bool need_scaler = false; + + /* Pre-gen11 and SDR planes always need a scaler for planar formats. */ + if (!icl_is_hdr_plane(dev_priv, intel_plane->id) && + fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) + need_scaler = true; + + ret = skl_update_scaler(crtc_state, force_detach, + drm_plane_index(&intel_plane->base), + &plane_state->scaler_id, + drm_rect_width(&plane_state->uapi.src) >> 16, + drm_rect_height(&plane_state->uapi.src) >> 16, + drm_rect_width(&plane_state->uapi.dst), + drm_rect_height(&plane_state->uapi.dst), + fb ? fb->format : NULL, + fb ? fb->modifier : 0, + need_scaler); + + if (ret || plane_state->scaler_id < 0) + return ret; + + /* check colorkey */ + if (plane_state->ckey.flags) { + drm_dbg_kms(&dev_priv->drm, + "[PLANE:%d:%s] scaling with color key not allowed", + intel_plane->base.base.id, + intel_plane->base.name); + return -EINVAL; + } + + /* Check src format */ + switch (fb->format->format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_NV12: + case DRM_FORMAT_XYUV8888: + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + case DRM_FORMAT_Y210: + case DRM_FORMAT_Y212: + case DRM_FORMAT_Y216: + case DRM_FORMAT_XVYU2101010: + case DRM_FORMAT_XVYU12_16161616: + case DRM_FORMAT_XVYU16161616: + break; + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_ARGB16161616F: + if (INTEL_GEN(dev_priv) >= 11) + break; + fallthrough; + default: + drm_dbg_kms(&dev_priv->drm, + "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n", + intel_plane->base.base.id, intel_plane->base.name, + fb->base.id, fb->format->format); + return -EINVAL; + } + + return 0; +} + +static int cnl_coef_tap(int i) +{ + return i % 7; +} + +static u16 cnl_nearest_filter_coef(int t) +{ + return t == 3 ? 0x0800 : 0x3000; +} + +/* + * Theory behind setting nearest-neighbor integer scaling: + * + * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. + * The letter represents the filter tap (D is the center tap) and the number + * represents the coefficient set for a phase (0-16). + * + * +------------+------------------------+------------------------+ + * |Index value | Data value coeffient 1 | Data value coeffient 2 | + * +------------+------------------------+------------------------+ + * | 00h | B0 | A0 | + * +------------+------------------------+------------------------+ + * | 01h | D0 | C0 | + * +------------+------------------------+------------------------+ + * | 02h | F0 | E0 | + * +------------+------------------------+------------------------+ + * | 03h | A1 | G0 | + * +------------+------------------------+------------------------+ + * | 04h | C1 | B1 | + * +------------+------------------------+------------------------+ + * | ... | ... | ... | + * +------------+------------------------+------------------------+ + * | 38h | B16 | A16 | + * +------------+------------------------+------------------------+ + * | 39h | D16 | C16 | + * +------------+------------------------+------------------------+ + * | 3Ah | F16 | C16 | + * +------------+------------------------+------------------------+ + * | 3Bh | Reserved | G16 | + * +------------+------------------------+------------------------+ + * + * To enable nearest-neighbor scaling: program scaler coefficents with + * the center tap (Dxx) values set to 1 and all other values set to 0 as per + * SCALER_COEFFICIENT_FORMAT + * + */ + +static void cnl_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, + enum pipe pipe, int id, int set) +{ + int i; + + intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), + PS_COEE_INDEX_AUTO_INC); + + for (i = 0; i < 17 * 7; i += 2) { + u32 tmp; + int t; + + t = cnl_coef_tap(i); + tmp = cnl_nearest_filter_coef(t); + + t = cnl_coef_tap(i + 1); + tmp |= cnl_nearest_filter_coef(t) << 16; + + intel_de_write_fw(dev_priv, CNL_PS_COEF_DATA_SET(pipe, id, set), + tmp); + } + + intel_de_write_fw(dev_priv, CNL_PS_COEF_INDEX_SET(pipe, id, set), 0); +} + +static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) +{ + if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) { + return (PS_FILTER_PROGRAMMED | + PS_Y_VERT_FILTER_SELECT(set) | + PS_Y_HORZ_FILTER_SELECT(set) | + PS_UV_VERT_FILTER_SELECT(set) | + PS_UV_HORZ_FILTER_SELECT(set)); + } + + return PS_FILTER_MEDIUM; +} + +static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, + int id, int set, enum drm_scaling_filter filter) +{ + switch (filter) { + case DRM_SCALING_FILTER_DEFAULT: + break; + case DRM_SCALING_FILTER_NEAREST_NEIGHBOR: + cnl_program_nearest_filter_coefs(dev_priv, pipe, id, set); + break; + default: + MISSING_CASE(filter); + } +} + +void skl_pfit_enable(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); + const struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct drm_rect src = { + .x2 = crtc_state->pipe_src_w << 16, + .y2 = crtc_state->pipe_src_h << 16, + }; + const struct drm_rect *dst = &crtc_state->pch_pfit.dst; + u16 uv_rgb_hphase, uv_rgb_vphase; + enum pipe pipe = crtc->pipe; + int width = drm_rect_width(dst); + int height = drm_rect_height(dst); + int x = dst->x1; + int y = dst->y1; + int hscale, vscale; + unsigned long irqflags; + int id; + u32 ps_ctrl; + + if (!crtc_state->pch_pfit.enabled) + return; + + if (drm_WARN_ON(&dev_priv->drm, + crtc_state->scaler_state.scaler_id < 0)) + return; + + hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX); + vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX); + + uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); + uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); + + id = scaler_state->scaler_id; + + ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0); + ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + skl_scaler_setup_filter(dev_priv, pipe, id, 0, + crtc_state->hw.scaling_filter); + + intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl); + + intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id), + PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase)); + intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id), + PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase)); + intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id), + x << 16 | y); + intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id), + width << 16 | height); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +void +skl_program_plane_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + enum pipe pipe = plane->pipe; + int scaler_id = plane_state->scaler_id; + const struct intel_scaler *scaler = + &crtc_state->scaler_state.scalers[scaler_id]; + int crtc_x = plane_state->uapi.dst.x1; + int crtc_y = plane_state->uapi.dst.y1; + u32 crtc_w = drm_rect_width(&plane_state->uapi.dst); + u32 crtc_h = drm_rect_height(&plane_state->uapi.dst); + u16 y_hphase, uv_rgb_hphase; + u16 y_vphase, uv_rgb_vphase; + int hscale, vscale; + u32 ps_ctrl; + + hscale = drm_rect_calc_hscale(&plane_state->uapi.src, + &plane_state->uapi.dst, + 0, INT_MAX); + vscale = drm_rect_calc_vscale(&plane_state->uapi.src, + &plane_state->uapi.dst, + 0, INT_MAX); + + /* TODO: handle sub-pixel coordinates */ + if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) && + !icl_is_hdr_plane(dev_priv, plane->id)) { + y_hphase = skl_scaler_calc_phase(1, hscale, false); + y_vphase = skl_scaler_calc_phase(1, vscale, false); + + /* MPEG2 chroma siting convention */ + uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true); + uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false); + } else { + /* not used */ + y_hphase = 0; + y_vphase = 0; + + uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false); + uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false); + } + + ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0); + ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode; + + skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0, + plane_state->hw.scaling_filter); + + intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); + intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id), + PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase)); + intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id), + PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase)); + intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id), + (crtc_x << 16) | crtc_y); + intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id), + (crtc_w << 16) | crtc_h); +} + +static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + unsigned long irqflags; + + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + + intel_de_write_fw(dev_priv, SKL_PS_CTRL(intel_crtc->pipe, id), 0); + intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); + intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); + + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); +} + +/* + * This function detaches (aka. unbinds) unused scalers in hardware + */ +void skl_detach_scalers(const struct intel_crtc_state *crtc_state) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + int i; + + /* loop through and disable scalers that aren't in use */ + for (i = 0; i < intel_crtc->num_scalers; i++) { + if (!scaler_state->scalers[i].in_use) + skl_detach_scaler(intel_crtc, i); + } +} + +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) +{ + struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); + int i; + + for (i = 0; i < crtc->num_scalers; i++) + skl_detach_scaler(crtc, i); +} diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h b/drivers/gpu/drm/i915/display/skl_scaler.h new file mode 100644 index 0000000000000..0097d5d08e102 --- /dev/null +++ b/drivers/gpu/drm/i915/display/skl_scaler.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2020 Intel Corporation + */ +#ifndef INTEL_SCALER_H +#define INTEL_SCALER_H + +#include + +enum drm_scaling_filter; +struct drm_i915_private; +struct intel_crtc_state; +struct intel_plane_state; +struct intel_plane; +enum pipe; + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); + +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); + +void skl_pfit_enable(const struct intel_crtc_state *crtc_state); + +void skl_program_plane_scaler(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state); +void skl_detach_scalers(const struct intel_crtc_state *crtc_state); +void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state); +#endif diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 4ae1a2ef29eca..1f335cb09149e 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -14,6 +14,7 @@ #include "intel_pm.h" #include "intel_psr.h" #include "intel_sprite.h" +#include "skl_scaler.h" #include "skl_universal_plane.h" static const u32 skl_plane_formats[] = { @@ -1054,7 +1055,7 @@ skl_program_plane(struct intel_plane *plane, intel_plane_ggtt_offset(plane_state) + surf_addr); if (plane_state->scaler_id >= 0) - skl_program_scaler(plane, crtc_state, plane_state); + skl_program_plane_scaler(plane, crtc_state, plane_state); spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.h b/drivers/gpu/drm/i915/display/skl_universal_plane.h index 70eb5010cd284..8182666536308 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.h @@ -30,4 +30,8 @@ int skl_ccs_to_main_plane(const struct drm_framebuffer *fb, int ccs_plane); int skl_calc_main_surface_offset(const struct intel_plane_state *plane_state, int *x, int *y, u32 *offset); +bool icl_is_nv12_y_plane(struct drm_i915_private *dev_priv, + enum plane_id plane_id); +bool icl_is_hdr_plane(struct drm_i915_private *dev_priv, enum plane_id plane_id); + #endif diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index f94025ec603a6..1059a26c1f581 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -38,6 +38,7 @@ #include "intel_fifo_underrun.h" #include "intel_panel.h" #include "intel_sideband.h" +#include "skl_scaler.h" /* return pixels in terms of txbyteclkhs */ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, From 81637a6ede89b95b6ea7b2f8c594676881110890 Mon Sep 17 00:00:00 2001 From: Ankit Nautiyal Date: Mon, 8 Feb 2021 11:25:54 +0530 Subject: [PATCH 050/142] drm/i915: Fix HAS_LSPCON macro for platforms between GEN9 and GEN10 Legacy LSPCON chip from MCA and Parade is only used for platforms between GEN9 and GEN10. Fixing the HAS_LSPCON macro to reflect the same. Signed-off-by: Ankit Nautiyal Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210208055554.24357-1-ankit.k.nautiyal@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 017208ff8df41..d8f418eaeb782 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1722,7 +1722,7 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) #define HAS_GMCH(dev_priv) (INTEL_INFO(dev_priv)->display.has_gmch) -#define HAS_LSPCON(dev_priv) (INTEL_GEN(dev_priv) >= 9) +#define HAS_LSPCON(dev_priv) (IS_GEN_RANGE(dev_priv, 9, 10)) /* DPF == dynamic parity feature */ #define HAS_L3_DPF(dev_priv) (INTEL_INFO(dev_priv)->has_l3_dpf) From e22fa6f0a9760297295c621fdcd4e29cf32fcfbd Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Mon, 30 Nov 2020 18:18:55 +0530 Subject: [PATCH 051/142] drm/i915/rkl: Remove require_force_probe protection Removing force probe protection from RKL platform. Did not observe warnings, errors, flickering or any visual defects while doing ordinary tasks like browsing and editing documents in a two monitor setup. Signed-off-by: Tejas Upadhyay Acked-by: Chris Wilson Signed-off-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20201130124855.319226-1-tejaskumarx.surendrakumar.upadhyay@intel.com --- drivers/gpu/drm/i915/i915_pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 73a10dc876429..e7919958fc1b0 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -896,7 +896,6 @@ static const struct intel_device_info rkl_info = { .pipe_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), .cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | BIT(TRANSCODER_C), - .require_force_probe = 1, .display.has_hti = 1, .display.has_psr_hw_tracking = 0, .platform_engine_mask = From 77892f4f050e73e5998c4f3a12b1e459680be7f6 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Mon, 8 Feb 2021 09:40:27 -0800 Subject: [PATCH 052/142] i915/perf: Store a mask of valid OA formats for a platform Validity of an OA format is checked by using a sparse array of formats per gen. Instead maintain a mask of supported formats for a platform in the perf object. v2: Use set_bit and test_bit style for the format_mask (Chris) Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20210208174029.45621-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 63 +++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_perf_types.h | 8 ++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 112ba5f2ce90e..b94b00607d54f 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -3524,6 +3524,18 @@ static u64 oa_exponent_to_ns(struct i915_perf *perf, int exponent) 2ULL << exponent); } +static __always_inline bool +oa_format_valid(struct i915_perf *perf, enum drm_i915_oa_format format) +{ + return test_bit(format, perf->format_mask); +} + +static __always_inline void +oa_format_add(struct i915_perf *perf, enum drm_i915_oa_format format) +{ + __set_bit(format, perf->format_mask); +} + /** * read_properties_unlocked - validate + copy userspace stream open properties * @perf: i915 perf instance @@ -3615,7 +3627,7 @@ static int read_properties_unlocked(struct i915_perf *perf, value); return -EINVAL; } - if (!perf->oa_formats[value].size) { + if (!oa_format_valid(perf, value)) { DRM_DEBUG("Unsupported OA report format %llu\n", value); return -EINVAL; @@ -4259,6 +4271,53 @@ static struct ctl_table dev_root[] = { {} }; +static void oa_init_supported_formats(struct i915_perf *perf) +{ + struct drm_i915_private *i915 = perf->i915; + enum intel_platform platform = INTEL_INFO(i915)->platform; + + switch (platform) { + case INTEL_HASWELL: + oa_format_add(perf, I915_OA_FORMAT_A13); + oa_format_add(perf, I915_OA_FORMAT_A13); + oa_format_add(perf, I915_OA_FORMAT_A29); + oa_format_add(perf, I915_OA_FORMAT_A13_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_B4_C8); + oa_format_add(perf, I915_OA_FORMAT_A45_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_B4_C8_A16); + oa_format_add(perf, I915_OA_FORMAT_C4_B8); + break; + + case INTEL_BROADWELL: + case INTEL_CHERRYVIEW: + case INTEL_SKYLAKE: + case INTEL_BROXTON: + case INTEL_KABYLAKE: + case INTEL_GEMINILAKE: + case INTEL_COFFEELAKE: + case INTEL_COMETLAKE: + case INTEL_CANNONLAKE: + case INTEL_ICELAKE: + case INTEL_ELKHARTLAKE: + case INTEL_JASPERLAKE: + oa_format_add(perf, I915_OA_FORMAT_A12); + oa_format_add(perf, I915_OA_FORMAT_A12_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_A32u40_A4u32_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_C4_B8); + break; + + case INTEL_TIGERLAKE: + case INTEL_ROCKETLAKE: + case INTEL_DG1: + case INTEL_ALDERLAKE_S: + oa_format_add(perf, I915_OA_FORMAT_A32u40_A4u32_B8_C8); + break; + + default: + MISSING_CASE(platform); + } +} + /** * i915_perf_init - initialize i915-perf state on module bind * @i915: i915 device instance @@ -4408,6 +4467,8 @@ void i915_perf_init(struct drm_i915_private *i915) 500 * 1000 /* 500us */); perf->i915 = i915; + + oa_init_supported_formats(perf); } } diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index a36a455ae3369..aa14354a51203 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "gt/intel_sseu.h" #include "i915_reg.h" @@ -441,6 +442,13 @@ struct i915_perf { struct i915_oa_ops ops; const struct i915_oa_format *oa_formats; + /** + * Use a format mask to store the supported formats + * for a platform. + */ +#define FORMAT_MASK_SIZE DIV_ROUND_UP(I915_OA_FORMAT_MAX - 1, BITS_PER_LONG) + unsigned long format_mask[FORMAT_MASK_SIZE]; + atomic64_t noa_programming_delay; }; From 0f15c5b00634898f573f478f3700b5f4b7a2b727 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Mon, 8 Feb 2021 09:40:28 -0800 Subject: [PATCH 053/142] i915/perf: Move OA formats to single array Variations in OA formats in the different gens has led to creation of several sparse arrays to store the formats. Move oa formats into a single array and format_mask to check for platform specific oa formats. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20210208174029.45621-2-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index b94b00607d54f..adf7c2b2d428b 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -302,7 +302,7 @@ static u32 i915_oa_max_sample_rate = 100000; * code assumes all reports have a power-of-two size and ~(size - 1) can * be used as a mask to align the OA tail pointer. */ -static const struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = { +static const struct i915_oa_format oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A13] = { 0, 64 }, [I915_OA_FORMAT_A29] = { 1, 128 }, [I915_OA_FORMAT_A13_B8_C8] = { 2, 128 }, @@ -311,17 +311,9 @@ static const struct i915_oa_format hsw_oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A45_B8_C8] = { 5, 256 }, [I915_OA_FORMAT_B4_C8_A16] = { 6, 128 }, [I915_OA_FORMAT_C4_B8] = { 7, 64 }, -}; - -static const struct i915_oa_format gen8_plus_oa_formats[I915_OA_FORMAT_MAX] = { [I915_OA_FORMAT_A12] = { 0, 64 }, [I915_OA_FORMAT_A12_B8_C8] = { 2, 128 }, [I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 }, - [I915_OA_FORMAT_C4_B8] = { 7, 64 }, -}; - -static const struct i915_oa_format gen12_oa_formats[I915_OA_FORMAT_MAX] = { - [I915_OA_FORMAT_A32u40_A4u32_B8_C8] = { 5, 256 }, }; #define SAMPLE_OA_REPORT (1<<0) @@ -4333,6 +4325,7 @@ void i915_perf_init(struct drm_i915_private *i915) /* XXX const struct i915_perf_ops! */ + perf->oa_formats = oa_formats; if (IS_HASWELL(i915)) { perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; perf->ops.is_valid_mux_reg = hsw_is_valid_mux_addr; @@ -4343,8 +4336,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.oa_disable = gen7_oa_disable; perf->ops.read = gen7_oa_read; perf->ops.oa_hw_tail_read = gen7_oa_hw_tail_read; - - perf->oa_formats = hsw_oa_formats; } else if (HAS_LOGICAL_RING_CONTEXTS(i915)) { /* Note: that although we could theoretically also support the * legacy ringbuffer mode on BDW (and earlier iterations of @@ -4355,8 +4346,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->ops.read = gen8_oa_read; if (IS_GEN_RANGE(i915, 8, 9)) { - perf->oa_formats = gen8_plus_oa_formats; - perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; perf->ops.is_valid_mux_reg = @@ -4387,8 +4376,6 @@ void i915_perf_init(struct drm_i915_private *i915) perf->gen8_valid_ctx_bit = BIT(16); } } else if (IS_GEN_RANGE(i915, 10, 11)) { - perf->oa_formats = gen8_plus_oa_formats; - perf->ops.is_valid_b_counter_reg = gen7_is_valid_b_counter_addr; perf->ops.is_valid_mux_reg = @@ -4411,8 +4398,6 @@ void i915_perf_init(struct drm_i915_private *i915) } perf->gen8_valid_ctx_bit = BIT(16); } else if (IS_GEN(i915, 12)) { - perf->oa_formats = gen12_oa_formats; - perf->ops.is_valid_b_counter_reg = gen12_is_valid_b_counter_addr; perf->ops.is_valid_mux_reg = From 5e4b7385f374e10e94e6378cf7d030b66a342a0c Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Mon, 8 Feb 2021 09:40:29 -0800 Subject: [PATCH 054/142] i915/perf: Add additional OA formats for gen12 Gen12 supports additional OA formats as compared to what was added earlier. Include the additional OA formats. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20210208174029.45621-3-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index adf7c2b2d428b..e08c0db82f4b5 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -4292,17 +4292,14 @@ static void oa_init_supported_formats(struct i915_perf *perf) case INTEL_ICELAKE: case INTEL_ELKHARTLAKE: case INTEL_JASPERLAKE: - oa_format_add(perf, I915_OA_FORMAT_A12); - oa_format_add(perf, I915_OA_FORMAT_A12_B8_C8); - oa_format_add(perf, I915_OA_FORMAT_A32u40_A4u32_B8_C8); - oa_format_add(perf, I915_OA_FORMAT_C4_B8); - break; - case INTEL_TIGERLAKE: case INTEL_ROCKETLAKE: case INTEL_DG1: case INTEL_ALDERLAKE_S: + oa_format_add(perf, I915_OA_FORMAT_A12); + oa_format_add(perf, I915_OA_FORMAT_A12_B8_C8); oa_format_add(perf, I915_OA_FORMAT_A32u40_A4u32_B8_C8); + oa_format_add(perf, I915_OA_FORMAT_C4_B8); break; default: From f48993e5d26b079e8c80fff002499a213dbdb1b4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 8 Feb 2021 17:43:03 +0200 Subject: [PATCH 055/142] drm/i915/tgl+: Make sure TypeC FIA is powered up when initializing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TypeC FIA can be powered down if the TC-COLD power state is allowed, so block the TC-COLD state when initializing the FIA. Note that this isn't needed on ICL where the FIA is never modular and which has no generic way to block TC-COLD (except for platforms with a legacy TypeC port and on those too only via these legacy ports, not via a DP-alt/TBT port). Cc: # v5.10+ Cc: José Roberto de Souza Reported-by: Paul Menzel Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/3027 Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20210208154303.6839-1-imre.deak@intel.com Reviewed-by: Jos� Roberto de Souza --- drivers/gpu/drm/i915/display/intel_tc.c | 67 ++++++++++++++----------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 27dc2dad6809c..2cefc13535a0f 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -23,36 +23,6 @@ static const char *tc_port_mode_name(enum tc_port_mode mode) return names[mode]; } -static void -tc_port_load_fia_params(struct drm_i915_private *i915, - struct intel_digital_port *dig_port) -{ - enum port port = dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(i915, port); - u32 modular_fia; - - if (INTEL_INFO(i915)->display.has_modular_fia) { - modular_fia = intel_uncore_read(&i915->uncore, - PORT_TX_DFLEXDPSP(FIA1)); - drm_WARN_ON(&i915->drm, modular_fia == 0xffffffff); - modular_fia &= MODULAR_FIA_MASK; - } else { - modular_fia = 0; - } - - /* - * Each Modular FIA instance houses 2 TC ports. In SOC that has more - * than two TC ports, there are multiple instances of Modular FIA. - */ - if (modular_fia) { - dig_port->tc_phy_fia = tc_port / 2; - dig_port->tc_phy_fia_idx = tc_port % 2; - } else { - dig_port->tc_phy_fia = FIA1; - dig_port->tc_phy_fia_idx = tc_port; - } -} - static enum intel_display_power_domain tc_cold_get_power_domain(struct intel_digital_port *dig_port) { @@ -646,6 +616,43 @@ void intel_tc_port_put_link(struct intel_digital_port *dig_port) mutex_unlock(&dig_port->tc_lock); } +static bool +tc_has_modular_fia(struct drm_i915_private *i915, struct intel_digital_port *dig_port) +{ + intel_wakeref_t wakeref; + u32 val; + + if (!INTEL_INFO(i915)->display.has_modular_fia) + return false; + + wakeref = tc_cold_block(dig_port); + val = intel_uncore_read(&i915->uncore, PORT_TX_DFLEXDPSP(FIA1)); + tc_cold_unblock(dig_port, wakeref); + + drm_WARN_ON(&i915->drm, val == 0xffffffff); + + return val & MODULAR_FIA_MASK; +} + +static void +tc_port_load_fia_params(struct drm_i915_private *i915, struct intel_digital_port *dig_port) +{ + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(i915, port); + + /* + * Each Modular FIA instance houses 2 TC ports. In SOC that has more + * than two TC ports, there are multiple instances of Modular FIA. + */ + if (tc_has_modular_fia(i915, dig_port)) { + dig_port->tc_phy_fia = tc_port / 2; + dig_port->tc_phy_fia_idx = tc_port % 2; + } else { + dig_port->tc_phy_fia = FIA1; + dig_port->tc_phy_fia_idx = tc_port; + } +} + void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) { struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); From 59fb8218c8e5001f854e7d5fdb5fb135cba58102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Feb 2021 04:19:16 +0200 Subject: [PATCH 056/142] drm/i915: Disallow plane x+w>stride on ilk+ with X-tiling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ilk+ planes get notably unhappy when the plane x+w exceeds the stride. This wasn't a problem previously because we always aligned SURF to the closest tile boundary so the x offset never got particularly large. But now with async flips we have to align to 256KiB instead and thus this becomes a real issue. On ilk/snb/ivb it looks like the accesses just wrap early to the next tile row when scanout goes past the SURF+n*stride boundary, hsw/bdw suffer more heavily and start to underrun constantly. i965/g4x appear to be immune. vlv/chv I've not yet checked. Let's borrow another trick from the skl+ code and search backwards for a better SURF offset in the hopes of getting the x offset below the limit. IIRC when I ran into a similar issue on skl years ago it was causing the hardware to fall over pretty hard as well. And let's be consistent and include i965/g4x in the check as well, just in case I just got super lucky somehow when I wasn't able to reproduce the issue. Not that it really matters since we still use 4k SURF alignment for i965/g4x anyway. Fixes: 6ede6b0616b2 ("drm/i915: Implement async flips for vlv/chv") Fixes: 4bb18054adc4 ("drm/i915: Implement async flip for ilk/snb") Fixes: 2a636e240c77 ("drm/i915: Implement async flip for ivb/hsw") Fixes: cda195f13abd ("drm/i915: Implement async flips for bdw") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210209021918.16234-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/display/i9xx_plane.c | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/i915/display/i9xx_plane.c b/drivers/gpu/drm/i915/display/i9xx_plane.c index 0523e2c79d161..8a52beaed2daa 100644 --- a/drivers/gpu/drm/i915/display/i9xx_plane.c +++ b/drivers/gpu/drm/i915/display/i9xx_plane.c @@ -255,6 +255,33 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) else offset = 0; + /* + * When using an X-tiled surface the plane starts to + * misbehave if the x offset + width exceeds the stride. + * hsw/bdw: underrun galore + * ilk/snb/ivb: wrap to the next tile row mid scanout + * i965/g4x: so far appear immune to this + * vlv/chv: TODO check + * + * Linear surfaces seem to work just fine, even on hsw/bdw + * despite them not using the linear offset anymore. + */ + if (INTEL_GEN(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) { + u32 alignment = intel_surf_alignment(fb, 0); + int cpp = fb->format->cpp[0]; + + while ((src_x + src_w) * cpp > plane_state->color_plane[0].stride) { + if (offset == 0) { + drm_dbg_kms(&dev_priv->drm, + "Unable to find suitable display surface offset due to X-tiling\n"); + return -EINVAL; + } + + offset = intel_plane_adjust_aligned_offset(&src_x, &src_y, plane_state, 0, + offset, offset - alignment); + } + } + /* * Put the final coordinates back so that the src * coordinate checks will see the right values. From 553c23bdb4775130f333f07a51b047276bc53f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Feb 2021 04:19:17 +0200 Subject: [PATCH 057/142] drm/i915: Fix overlay frontbuffer tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't have a persistent fb holding a reference to the frontbuffer object, so every time we do the get+put we throw the frontbuffer object immediately away. And so the next time around we get a pristine frontbuffer object with bits==0 even for the old vma. This confuses the frontbuffer tracking code which understandably expects the old frontbuffer to have the overlay's bit set. Fix this by hanging on to the frontbuffer reference until the next flip. And just to make this a bit more clear let's track the frontbuffer explicitly instead of just grabbing it via the old vma. Cc: stable@vger.kernel.org Cc: Chris Wilson Cc: Joonas Lahtinen Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/1136 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210209021918.16234-2-ville.syrjala@linux.intel.com Fixes: 8e7cb1799b4f ("drm/i915: Extract intel_frontbuffer active tracking") Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/display/intel_overlay.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index cd1eb71d6e358..16bc155df9dcc 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -183,6 +183,7 @@ struct intel_overlay { struct intel_crtc *crtc; struct i915_vma *vma; struct i915_vma *old_vma; + struct intel_frontbuffer *frontbuffer; bool active; bool pfit_active; u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */ @@ -283,21 +284,19 @@ static void intel_overlay_flip_prepare(struct intel_overlay *overlay, struct i915_vma *vma) { enum pipe pipe = overlay->crtc->pipe; - struct intel_frontbuffer *from = NULL, *to = NULL; + struct intel_frontbuffer *frontbuffer = NULL; drm_WARN_ON(&overlay->i915->drm, overlay->old_vma); - if (overlay->vma) - from = intel_frontbuffer_get(overlay->vma->obj); if (vma) - to = intel_frontbuffer_get(vma->obj); + frontbuffer = intel_frontbuffer_get(vma->obj); - intel_frontbuffer_track(from, to, INTEL_FRONTBUFFER_OVERLAY(pipe)); + intel_frontbuffer_track(overlay->frontbuffer, frontbuffer, + INTEL_FRONTBUFFER_OVERLAY(pipe)); - if (to) - intel_frontbuffer_put(to); - if (from) - intel_frontbuffer_put(from); + if (overlay->frontbuffer) + intel_frontbuffer_put(overlay->frontbuffer); + overlay->frontbuffer = frontbuffer; intel_frontbuffer_flip_prepare(overlay->i915, INTEL_FRONTBUFFER_OVERLAY(pipe)); From 5ffb9afaa909f1a254adab67f2d0557a5cead2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Feb 2021 04:19:18 +0200 Subject: [PATCH 058/142] drm/i915: Warn when releasing a frontbuffer while in use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's scream if we are about to release a frontbuffer which is still in use. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210209021918.16234-3-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/display/intel_frontbuffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index d898b370d7a4f..b2744c5c3653a 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -224,6 +224,8 @@ static void frontbuffer_release(struct kref *ref) struct drm_i915_gem_object *obj = front->obj; struct i915_vma *vma; + drm_WARN_ON(obj->base.dev, atomic_read(&front->bits)); + spin_lock(&obj->vma.lock); for_each_ggtt_vma(vma, obj) vma->display_alignment = I915_GTT_MIN_ALIGNMENT; From b305fc7490b39de8ad8f06c760e2f5c556889e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 09:42:38 -0800 Subject: [PATCH 059/142] drm/i915/display: Add DDR5 and LPDDR5 BW buddy page entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the right BW buddy page mask for new memory types. BSpec: 49218 Cc: Clint Taylor Cc: Matt Roper Cc: Lucas De Marchi Signed-off-by: José Roberto de Souza Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210209174238.153278-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_display_power.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e17b1ca356c3c..f00c1750febd3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -5317,17 +5317,25 @@ struct buddy_page_mask { static const struct buddy_page_mask tgl_buddy_page_masks[] = { { .num_channels = 1, .type = INTEL_DRAM_DDR4, .page_mask = 0xF }, + { .num_channels = 1, .type = INTEL_DRAM_DDR5, .page_mask = 0xF }, { .num_channels = 2, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x1C }, + { .num_channels = 2, .type = INTEL_DRAM_LPDDR5, .page_mask = 0x1C }, { .num_channels = 2, .type = INTEL_DRAM_DDR4, .page_mask = 0x1F }, + { .num_channels = 2, .type = INTEL_DRAM_DDR5, .page_mask = 0x1E }, { .num_channels = 4, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x38 }, + { .num_channels = 4, .type = INTEL_DRAM_LPDDR5, .page_mask = 0x38 }, {} }; static const struct buddy_page_mask wa_1409767108_buddy_page_masks[] = { { .num_channels = 1, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x1 }, { .num_channels = 1, .type = INTEL_DRAM_DDR4, .page_mask = 0x1 }, + { .num_channels = 1, .type = INTEL_DRAM_DDR5, .page_mask = 0x1 }, + { .num_channels = 1, .type = INTEL_DRAM_LPDDR5, .page_mask = 0x1 }, { .num_channels = 2, .type = INTEL_DRAM_LPDDR4, .page_mask = 0x3 }, { .num_channels = 2, .type = INTEL_DRAM_DDR4, .page_mask = 0x3 }, + { .num_channels = 2, .type = INTEL_DRAM_DDR5, .page_mask = 0x3 }, + { .num_channels = 2, .type = INTEL_DRAM_LPDDR5, .page_mask = 0x3 }, {} }; From aaab24bb25e9fc4c8f3a1d9a593d3ace2c4af243 Mon Sep 17 00:00:00 2001 From: Uma Shankar Date: Thu, 11 Feb 2021 17:12:09 +0530 Subject: [PATCH 060/142] drm/i915/display: Handle lane polarity for DDI port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lane Reversal is required for some of the DDI ports. This information is populated in VBT and driver should read the same and set the polarity while enabling the port. This patch handles the same. It helps fix a display blankout issue on DP ports on certain platforms. Signed-off-by: Uma Shankar Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210211114209.23866-1-uma.shankar@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 17 +++++++++++++++++ drivers/gpu/drm/i915/display/intel_bios.h | 2 ++ drivers/gpu/drm/i915/display/intel_ddi.c | 3 +++ 3 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 7118530a1c38e..dd51413e7f459 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -2674,6 +2674,23 @@ intel_bios_is_lspcon_present(const struct drm_i915_private *i915, return HAS_LSPCON(i915) && child && child->lspcon; } +/** + * intel_bios_is_lane_reversal_needed - if lane reversal needed on port + * @i915: i915 device instance + * @port: port to check + * + * Return true if port requires lane reversal + */ +bool +intel_bios_is_lane_reversal_needed(const struct drm_i915_private *i915, + enum port port) +{ + const struct child_device_config *child = + i915->vbt.ddi_port_info[port].child; + + return child && child->lane_reversal; +} + enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv, enum port port) { diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index e29e79faa01b9..f25190ecfe97d 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -241,6 +241,8 @@ bool intel_bios_is_port_hpd_inverted(const struct drm_i915_private *i915, enum port port); bool intel_bios_is_lspcon_present(const struct drm_i915_private *i915, enum port port); +bool intel_bios_is_lane_reversal_needed(const struct drm_i915_private *i915, + enum port port); enum aux_ch intel_bios_port_aux_ch(struct drm_i915_private *dev_priv, enum port port); bool intel_bios_get_dsc_params(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3c4003605f93c..2d6906f6995f9 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4082,6 +4082,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_de_read(dev_priv, DDI_BUF_CTL(port)) & (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES); + if (intel_bios_is_lane_reversal_needed(dev_priv, port)) + dig_port->saved_port_bits |= DDI_BUF_PORT_REVERSAL; + dig_port->dp.output_reg = INVALID_MMIO_REG; dig_port->max_lanes = intel_ddi_max_lanes(dig_port); dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port); From 4b97039e90bf895a7a1db47411079f0cffe395f6 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 9 Feb 2021 14:13:05 -0500 Subject: [PATCH 061/142] drm/i915/gen9_bc: Recognize TGP PCH + CML combos Since Intel has introduced the gen9_bc platform, a combination of Tigerpoint PCHs and CML CPUs, let's recognize such platforms as valid and avoid WARNing on them. Changes since v4: * Split this into it's own patch - vsyrjala Cc: Matt Roper Cc: Jani Nikula Cc: Ville Syrjala [originally from Tejas's work] Signed-off-by: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210209212832.1401815-2-lyude@redhat.com --- drivers/gpu/drm/i915/intel_pch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pch.c b/drivers/gpu/drm/i915/intel_pch.c index 4813207fc053f..7476f0e063c6c 100644 --- a/drivers/gpu/drm/i915/intel_pch.c +++ b/drivers/gpu/drm/i915/intel_pch.c @@ -121,7 +121,8 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id) case INTEL_PCH_TGP2_DEVICE_ID_TYPE: drm_dbg_kms(&dev_priv->drm, "Found Tiger Lake LP PCH\n"); drm_WARN_ON(&dev_priv->drm, !IS_TIGERLAKE(dev_priv) && - !IS_ROCKETLAKE(dev_priv)); + !IS_ROCKETLAKE(dev_priv) && + !IS_GEN9_BC(dev_priv)); return PCH_TGP; case INTEL_PCH_JSP_DEVICE_ID_TYPE: case INTEL_PCH_JSP2_DEVICE_ID_TYPE: From d20630802f9fc8daf3026bc96b35c02ad17693b5 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 9 Feb 2021 14:07:45 -0500 Subject: [PATCH 062/142] drm/i915/gen9_bc: Introduce TGP PCH DDC pin mappings With the introduction of gen9_bc, where Intel combines Cometlake CPUs with a Tigerpoint PCH, we'll need to introduce new DDC pin mappings for this platform in order to make all of the display connectors work. So, let's do that. Changes since v4: * Split this into it's own patch - vsyrjala Changes since v5: * Rename gen9bc_port_to_ddc_pin() to gen9bc_tgp_port_to_ddc_pin() Cc: Matt Roper Cc: Jani Nikula Cc: Ville Syrjala [originally from Tejas's work] Signed-off-by: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210209212832.1401815-3-lyude@redhat.com --- drivers/gpu/drm/i915/display/intel_bios.c | 9 +++++++++ drivers/gpu/drm/i915/display/intel_hdmi.c | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index dd51413e7f459..7902d4c2673ec 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1638,6 +1638,12 @@ static const u8 adls_ddc_pin_map[] = { [ADLS_DDC_BUS_PORT_TC4] = GMBUS_PIN_12_TC4_ICP, }; +static const u8 gen9bc_tgp_ddc_pin_map[] = { + [DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT, + [DDC_BUS_DDI_C] = GMBUS_PIN_9_TC1_ICP, + [DDC_BUS_DDI_D] = GMBUS_PIN_10_TC2_ICP, +}; + static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) { const u8 *ddc_pin_map; @@ -1651,6 +1657,9 @@ static u8 map_ddc_pin(struct drm_i915_private *dev_priv, u8 vbt_pin) } else if (IS_ROCKETLAKE(dev_priv) && INTEL_PCH_TYPE(dev_priv) == PCH_TGP) { ddc_pin_map = rkl_pch_tgp_ddc_pin_map; n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map); + } else if (HAS_PCH_TGP(dev_priv) && IS_GEN9_BC(dev_priv)) { + ddc_pin_map = gen9bc_tgp_ddc_pin_map; + n_entries = ARRAY_SIZE(gen9bc_tgp_ddc_pin_map); } else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) { ddc_pin_map = icp_ddc_pin_map; n_entries = ARRAY_SIZE(icp_ddc_pin_map); diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index dad54e116bc48..7f384f259fc80 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3138,6 +3138,24 @@ static u8 rkl_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) return GMBUS_PIN_1_BXT + phy; } +static u8 gen9bc_tgp_port_to_ddc_pin(struct drm_i915_private *i915, enum port port) +{ + enum phy phy = intel_port_to_phy(i915, port); + + drm_WARN_ON(&i915->drm, port == PORT_A); + + /* + * Pin mapping for GEN9 BC depends on which PCH is present. With TGP, + * final two outputs use type-c pins, even though they're actually + * combo outputs. With CMP, the traditional DDI A-D pins are used for + * all outputs. + */ + if (INTEL_PCH_TYPE(i915) >= PCH_TGP && phy >= PHY_C) + return GMBUS_PIN_9_TC1_ICP + phy - PHY_C; + + return GMBUS_PIN_1_BXT + phy; +} + static u8 dg1_port_to_ddc_pin(struct drm_i915_private *dev_priv, enum port port) { return intel_port_to_phy(dev_priv, port) + 1; @@ -3202,6 +3220,8 @@ static u8 intel_hdmi_ddc_pin(struct intel_encoder *encoder) ddc_pin = dg1_port_to_ddc_pin(dev_priv, port); else if (IS_ROCKETLAKE(dev_priv)) ddc_pin = rkl_port_to_ddc_pin(dev_priv, port); + else if (IS_GEN9_BC(dev_priv) && HAS_PCH_TGP(dev_priv)) + ddc_pin = gen9bc_tgp_port_to_ddc_pin(dev_priv, port); else if (HAS_PCH_MCC(dev_priv)) ddc_pin = mcc_port_to_ddc_pin(dev_priv, port); else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) From 885d3e5b6f08afda80e55d2682237a2bc599a7fd Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 24 Jun 2020 17:11:16 -0700 Subject: [PATCH 063/142] drm/i915/display: fix comment on skl straps We are not checking for specific SKUs and feedback from HW team is that it may not work since it was supposed to be fixed by the same time straps stopped to be used. So, just update comment. v2: Instead of removing the check, just update the comment since feedback from HW team was that it actually may not work Signed-off-by: Lucas De Marchi Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20200625001120.22810-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 788ce9496d983..6e71d39f343e2 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -11943,8 +11943,9 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) /* * Haswell uses DDI functions to detect digital outputs. - * On SKL pre-D0 the strap isn't connected, so we assume - * it's there. + * On SKL pre-D0 the strap isn't connected. Later SKUs may or + * may not have it - it was supposed to be fixed by the same + * time we stopped using straps. Assume it's there. */ found = intel_de_read(dev_priv, DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED; /* WaIgnoreDDIAStrap: skl */ From 357b5592e018b0faa9d49f1f8b58a4966391bcbd Mon Sep 17 00:00:00 2001 From: Anshuman Gupta Date: Thu, 11 Feb 2021 19:35:02 +0530 Subject: [PATCH 064/142] drm/i915/debugfs: HDCP capability enc NULL check DP-MST connector encoder initializes at modeset Adding a connector->encoder NULL check in order to avoid any NULL pointer dereference. intel_hdcp_enable() already handle this but debugfs can also invoke the intel_{hdcp,hdcp2_capable}. Handling it gracefully. v2: - Use necessary lock and NULL check in i915_hdcp_sink_capability_show. [Imre] Reviewed-by: Imre Deak Signed-off-by: Anshuman Gupta Link: https://patchwork.freedesktop.org/patch/msgid/20210211140502.22786-1-anshuman.gupta@intel.com --- .../drm/i915/display/intel_display_debugfs.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index d6e4a9237bda2..8af663b84314b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -2198,16 +2198,27 @@ DEFINE_SHOW_ATTRIBUTE(i915_panel); static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data) { struct drm_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->dev); struct intel_connector *intel_connector = to_intel_connector(connector); + int ret; - if (connector->status != connector_status_connected) - return -ENODEV; + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); + if (ret) + return ret; + + if (!connector->encoder || connector->status != connector_status_connected) { + ret = -ENODEV; + goto out; + } seq_printf(m, "%s:%d HDCP version: ", connector->name, connector->base.id); intel_hdcp_info(m, intel_connector); - return 0; +out: + drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); + + return ret; } DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); From e074ffe6ef342b9a9a5a8a2c3f719d9305a3e71b Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Wed, 10 Feb 2021 11:01:06 -0800 Subject: [PATCH 065/142] i915/perf: Drop the check for report reason in OA After fixing the OA_TAIL_PTR corruption, there are no more reports with reason field of zero. Drop the check for report reason. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Lionel Landwerlin Signed-off-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20210210190106.8586-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index e08c0db82f4b5..736c09891e245 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -725,11 +725,6 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream, (IS_GEN(stream->perf->i915, 12) ? OAREPORT_REASON_MASK_EXTENDED : OAREPORT_REASON_MASK)); - if (reason == 0) { - if (__ratelimit(&stream->perf->spurious_report_rs)) - DRM_NOTE("Skipping spurious, invalid OA report\n"); - continue; - } ctx_id = report32[2] & stream->specific_ctx_id_mask; From c8455098c67914c59d07f01819469e2e6f76f358 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 9 Feb 2021 14:16:28 -0500 Subject: [PATCH 066/142] drm/i915/gen9_bc: Introduce HPD pin mappings for TGP PCH + CML combos Next, let's start introducing the HPD pin mappings for Intel's new gen9_bc platform in order to make hotplugging display connectors work. Since gen9_bc is just a TGP PCH along with a CML CPU, except with the same HPD mappings as ICL, we simply add a skl_hpd_pin function that is shared between gen9 and gen9_bc which handles both the traditional gen9 HPD pin mappings and the Icelake HPD pin mappings that gen9_bc uses. Changes since v4: * Split this into its own commit * Introduce skl_hpd_pin() like vsyrjala suggested and use that instead of sticking our HPD pin mappings in TGP code Cc: Matt Roper Cc: Jani Nikula Cc: Ville Syrjala [originally from Tejas's work] Signed-off-by: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210209212832.1401815-4-lyude@redhat.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2d6906f6995f9..3b97c00918123 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3954,6 +3954,14 @@ static enum hpd_pin cnl_hpd_pin(struct drm_i915_private *dev_priv, return HPD_PORT_A + port - PORT_A; } +static enum hpd_pin skl_hpd_pin(struct drm_i915_private *dev_priv, enum port port) +{ + if (HAS_PCH_TGP(dev_priv)) + return icl_hpd_pin(dev_priv, port); + + return HPD_PORT_A + port - PORT_A; +} + #define port_tc_name(port) ((port) - PORT_TC1 + '1') #define tc_port_name(tc_port) ((tc_port) - TC_PORT_1 + '1') @@ -4070,6 +4078,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->hpd_pin = icl_hpd_pin(dev_priv, port); else if (IS_GEN(dev_priv, 10)) encoder->hpd_pin = cnl_hpd_pin(dev_priv, port); + else if (IS_GEN(dev_priv, 9)) + encoder->hpd_pin = skl_hpd_pin(dev_priv, port); else encoder->hpd_pin = intel_hpd_pin_default(dev_priv, port); From 70da7521e11939ebf2e3d2b4cd91d30d0d02e3c4 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 9 Feb 2021 15:11:09 -0500 Subject: [PATCH 067/142] drm/i915/gen9_bc: Add W/A for missing STRAP config on TGP PCH + CML combos Apparently the new gen9_bc platforms that Intel has introduced don't provide us with a STRAP config register to read from for initializing DDI B, C, and D detection. So, workaround this by hard-coding our strap config in intel_setup_outputs(). Changes since v4: * Split this into it's own commit Cc: Matt Roper Cc: Jani Nikula Cc: Ville Syrjala [originally from Tejas's work] Signed-off-by: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210209212832.1401815-5-lyude@redhat.com --- drivers/gpu/drm/i915/display/intel_display.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 6e71d39f343e2..8df65d6984766 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -11954,7 +11954,14 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) /* DDI B, C, D, and F detection is indicated by the SFUSE_STRAP * register */ - found = intel_de_read(dev_priv, SFUSE_STRAP); + if (HAS_PCH_TGP(dev_priv)) { + /* W/A due to lack of STRAP config on TGP PCH*/ + found = (SFUSE_STRAP_DDIB_DETECTED | + SFUSE_STRAP_DDIC_DETECTED | + SFUSE_STRAP_DDID_DETECTED); + } else { + found = intel_de_read(dev_priv, SFUSE_STRAP); + } if (found & SFUSE_STRAP_DDIB_DETECTED) intel_ddi_init(dev_priv, PORT_B); From a321c3c6d8dda2a34d4b5d76115a9a42f67158a3 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 12 Feb 2021 14:20:49 -0800 Subject: [PATCH 068/142] drm/i915: FPGA_DBG is display-specific Although the bspec's description doesn't make it very clear, the hardware architects have confirmed that the FPGA_DBG register that we use to check for unclaimed MMIO accesses is display-specific and will only properly flag unclaimed MMIO transactions for registers in the display range. If a platform doesn't have display, FPGA_DBG itself will not be available and should not be checked. Let's move the feature flag into intel_device_info.display to more accurately reflect this. Given that we now know FPGA_DBG is display-specific, it could be argued that we should only check it on out intel_de_*() functions. However let's not make that change right now; keeping the checks in all of the existing locations still helps us catch cases where regular intel_uncore_*() functions use bad MMIO offset math / base addresses and accidentally wind up landing within an unused area within the display MMIO range. It will also help catch cases where userspace-initiated MMIO (e.g., IGT's intel_reg tool) attempt to read bad offsets within the display range. v2: Add missing hunk with the update to the HAS_FPGA_DBG_UNCLAIMED macro. (CI) Cc: Lucas De Marchi Signed-off-by: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20210212222049.3516344-1-matthew.d.roper@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_pci.c | 4 ++-- drivers/gpu/drm/i915/intel_device_info.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d8f418eaeb782..0816c39e51ddb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1690,7 +1690,7 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) #define HAS_DP_MST(dev_priv) (INTEL_INFO(dev_priv)->display.has_dp_mst) #define HAS_DDI(dev_priv) (INTEL_INFO(dev_priv)->display.has_ddi) -#define HAS_FPGA_DBG_UNCLAIMED(dev_priv) (INTEL_INFO(dev_priv)->has_fpga_dbg) +#define HAS_FPGA_DBG_UNCLAIMED(dev_priv) (INTEL_INFO(dev_priv)->display.has_fpga_dbg) #define HAS_PSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_psr) #define HAS_PSR_HW_TRACKING(dev_priv) \ (INTEL_INFO(dev_priv)->display.has_psr_hw_tracking) diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index e7919958fc1b0..914ae9dc6612b 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -536,7 +536,7 @@ static const struct intel_device_info vlv_info = { .cpu_transcoder_mask = BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | \ BIT(TRANSCODER_C) | BIT(TRANSCODER_EDP), \ .display.has_ddi = 1, \ - .has_fpga_dbg = 1, \ + .display.has_fpga_dbg = 1, \ .display.has_psr = 1, \ .display.has_psr_hw_tracking = 1, \ .display.has_dp_mst = 1, \ @@ -688,7 +688,7 @@ static const struct intel_device_info skl_gt4_info = { BIT(TRANSCODER_DSI_A) | BIT(TRANSCODER_DSI_C), \ .has_64bit_reloc = 1, \ .display.has_ddi = 1, \ - .has_fpga_dbg = 1, \ + .display.has_fpga_dbg = 1, \ .display.has_fbc = 1, \ .display.has_hdcp = 1, \ .display.has_psr = 1, \ diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 79dab5a6f2724..efd138761e141 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -117,7 +117,6 @@ enum intel_ppgtt_type { func(has_64bit_reloc); \ func(gpu_reset_clobbers_display); \ func(has_reset_engine); \ - func(has_fpga_dbg); \ func(has_global_mocs); \ func(has_gt_uc); \ func(has_l3_dpf); \ @@ -144,6 +143,7 @@ enum intel_ppgtt_type { func(has_dsb); \ func(has_dsc); \ func(has_fbc); \ + func(has_fpga_dbg); \ func(has_gmch); \ func(has_hdcp); \ func(has_hotplug); \ From 29b6f88d60ddcaf813d1adc757d84fad4a6153c6 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 12 Feb 2021 13:19:25 -0800 Subject: [PATCH 069/142] drm/i915: Try to detect sudden loss of MMIO access In rare circumstances bugs in PCI programming, broken BIOS, or failing hardware can cause the CPU to lose access to the MMIO BAR on dgfx platforms. This is a pretty catastrophic failure since all register reads come back with values of 0xFFFFFFFF. Let's check for this special case while doing our usual checks for unclaimed registers; the FPGA_DBG register we use for those checks on modern platforms has some unused bits that will always read back as 0 when things are behaving properly; we can use them as canaries to detect when MMIO itself has suddenly broken and try to print a more informative error message in the logs. v2: Let the detection function still return 'true' if we've lost our MMIO access. We'll still get an extra false positive message about an unclaimed register access, but we'll still honor the 'mmio_debug' limit and not spam the log. (Lucas) Cc: Lucas De Marchi Signed-off-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20210212211925.3418280-2-matthew.d.roper@intel.com Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/i915/intel_uncore.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 5098f95d71b03..661b50191f2ba 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -465,6 +465,22 @@ fpga_check_for_unclaimed_mmio(struct intel_uncore *uncore) if (likely(!(dbg & FPGA_DBG_RM_NOCLAIM))) return false; + /* + * Bugs in PCI programming (or failing hardware) can occasionally cause + * us to lose access to the MMIO BAR. When this happens, register + * reads will come back with 0xFFFFFFFF for every register and things + * go bad very quickly. Let's try to detect that special case and at + * least try to print a more informative message about what has + * happened. + * + * During normal operation the FPGA_DBG register has several unused + * bits that will always read back as 0's so we can use them as canaries + * to recognize when MMIO accesses are just busted. + */ + if (unlikely(dbg == ~0)) + drm_err(&uncore->i915->drm, + "Lost access to MMIO BAR; all registers now read back as 0xFFFFFFFF!\n"); + __raw_uncore_write32(uncore, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); return true; From ec3e00b4ee2768a457d9b6278c0dfac05473abd1 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 12 Feb 2021 20:27:53 -0800 Subject: [PATCH 070/142] drm/i915: stop registering if drm_dev_register() fails If drm_dev_register() fails there is no reason to continue registering the driver and initializing. Signed-off-by: Lucas De Marchi Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20210213042756.953007-1-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 57d693eb24f36..67e4d91df0c08 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -664,17 +664,19 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) intel_vgpu_register(dev_priv); /* Reveal our presence to userspace */ - if (drm_dev_register(dev, 0) == 0) { - i915_debugfs_register(dev_priv); - if (HAS_DISPLAY(dev_priv)) - intel_display_debugfs_register(dev_priv); - i915_setup_sysfs(dev_priv); - - /* Depends on sysfs having been initialized */ - i915_perf_register(dev_priv); - } else + if (drm_dev_register(dev, 0)) { drm_err(&dev_priv->drm, "Failed to register driver for userspace access!\n"); + return; + } + + i915_debugfs_register(dev_priv); + if (HAS_DISPLAY(dev_priv)) + intel_display_debugfs_register(dev_priv); + i915_setup_sysfs(dev_priv); + + /* Depends on sysfs having been initialized */ + i915_perf_register(dev_priv); if (HAS_DISPLAY(dev_priv)) { /* Must be done after probing outputs */ From ef7eff1aae10acd81ab266e7d843e0db52279d16 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 12 Feb 2021 20:27:54 -0800 Subject: [PATCH 071/142] drm/i915: group display-related register calls intel_gt_driver_register() may be called earlier than intel_opregion_register() and acpi_video_register(), so move it up. intel_display_debugfs_register() may be called later, together with the other display-related initializations. There is a slight change in behavior that sysfs files will show up before the display-related debugfs files, but that shouldn't be a problem - userspace shouldn't be relying in debugfs. This allows us to group all the display-related calls under a single check for "HAS_DISPLAY()" that can be later moved to a better place. Signed-off-by: Lucas De Marchi Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20210213042756.953007-2-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/i915_drv.c | 64 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 67e4d91df0c08..4e8caf88f32ca 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -671,38 +671,39 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) } i915_debugfs_register(dev_priv); - if (HAS_DISPLAY(dev_priv)) - intel_display_debugfs_register(dev_priv); i915_setup_sysfs(dev_priv); /* Depends on sysfs having been initialized */ i915_perf_register(dev_priv); + intel_gt_driver_register(&dev_priv->gt); + if (HAS_DISPLAY(dev_priv)) { + intel_display_debugfs_register(dev_priv); + /* Must be done after probing outputs */ intel_opregion_register(dev_priv); acpi_video_register(); - } - intel_gt_driver_register(&dev_priv->gt); - - intel_audio_init(dev_priv); + intel_audio_init(dev_priv); - /* - * Some ports require correctly set-up hpd registers for detection to - * work properly (leading to ghost connected connector status), e.g. VGA - * on gm45. Hence we can only set up the initial fbdev config after hpd - * irqs are fully enabled. We do it last so that the async config - * cannot run before the connectors are registered. - */ - intel_fbdev_initial_config_async(dev); + /* + * Some ports require correctly set-up hpd registers for + * detection to work properly (leading to ghost connected + * connector status), e.g. VGA on gm45. Hence we can only set + * up the initial fbdev config after hpd irqs are fully + * enabled. We do it last so that the async config cannot run + * before the connectors are registered. + */ + intel_fbdev_initial_config_async(dev); - /* - * We need to coordinate the hotplugs with the asynchronous fbdev - * configuration, for which we use the fbdev->async_cookie. - */ - if (HAS_DISPLAY(dev_priv)) + /* + * We need to coordinate the hotplugs with the asynchronous + * fbdev configuration, for which we use the + * fbdev->async_cookie. + */ drm_kms_helper_poll_init(dev); + } intel_power_domains_enable(dev_priv); intel_runtime_pm_enable(&dev_priv->runtime_pm); @@ -726,20 +727,23 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) intel_runtime_pm_disable(&dev_priv->runtime_pm); intel_power_domains_disable(dev_priv); - intel_fbdev_unregister(dev_priv); - intel_audio_deinit(dev_priv); + if (HAS_DISPLAY(dev_priv)) { + intel_fbdev_unregister(dev_priv); + intel_audio_deinit(dev_priv); + + /* + * After flushing the fbdev (incl. a late async config which + * will have delayed queuing of a hotplug event), then flush + * the hotplug events. + */ + drm_kms_helper_poll_fini(&dev_priv->drm); + drm_atomic_helper_shutdown(&dev_priv->drm); - /* - * After flushing the fbdev (incl. a late async config which will - * have delayed queuing of a hotplug event), then flush the hotplug - * events. - */ - drm_kms_helper_poll_fini(&dev_priv->drm); - drm_atomic_helper_shutdown(&dev_priv->drm); + acpi_video_unregister(); + intel_opregion_unregister(dev_priv); + } intel_gt_driver_unregister(&dev_priv->gt); - acpi_video_unregister(); - intel_opregion_unregister(dev_priv); i915_perf_unregister(dev_priv); i915_pmu_unregister(dev_priv); From 141b415f9f9fd23ecd1ebebc14f7e1d3765d74d1 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 12 Feb 2021 20:27:55 -0800 Subject: [PATCH 072/142] drm/i915/display: move register functions to display/ Now that all display-related functions are grouped in i915_driver_register(), move them to display/ so we reduce the amount of display calls from the rest of the driver. Signed-off-by: Lucas De Marchi Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20210213042756.953007-3-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 53 ++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_display.h | 3 ++ drivers/gpu/drm/i915/i915_drv.c | 45 +---------------- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8df65d6984766..b777497285da1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -24,6 +24,7 @@ * Eric Anholt */ +#include #include #include #include @@ -43,6 +44,7 @@ #include #include +#include "display/intel_audio.h" #include "display/intel_crt.h" #include "display/intel_ddi.h" #include "display/intel_display_debugfs.h" @@ -13954,6 +13956,57 @@ void intel_modeset_driver_remove_nogem(struct drm_i915_private *i915) intel_bios_driver_remove(i915); } +void intel_display_driver_register(struct drm_i915_private *i915) +{ + if (!HAS_DISPLAY(i915)) + return; + + intel_display_debugfs_register(i915); + + /* Must be done after probing outputs */ + intel_opregion_register(i915); + acpi_video_register(); + + intel_audio_init(i915); + + /* + * Some ports require correctly set-up hpd registers for + * detection to work properly (leading to ghost connected + * connector status), e.g. VGA on gm45. Hence we can only set + * up the initial fbdev config after hpd irqs are fully + * enabled. We do it last so that the async config cannot run + * before the connectors are registered. + */ + intel_fbdev_initial_config_async(&i915->drm); + + /* + * We need to coordinate the hotplugs with the asynchronous + * fbdev configuration, for which we use the + * fbdev->async_cookie. + */ + drm_kms_helper_poll_init(&i915->drm); +} + +void intel_display_driver_unregister(struct drm_i915_private *i915) +{ + if (!HAS_DISPLAY(i915)) + return; + + intel_fbdev_unregister(i915); + intel_audio_deinit(i915); + + /* + * After flushing the fbdev (incl. a late async config which + * will have delayed queuing of a hotplug event), then flush + * the hotplug events. + */ + drm_kms_helper_poll_fini(&i915->drm); + drm_atomic_helper_shutdown(&i915->drm); + + acpi_video_unregister(); + intel_opregion_unregister(i915); +} + #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) struct intel_display_error_state { diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index e3757ecabbf78..375ec2bccebd6 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -654,6 +654,9 @@ u32 intel_plane_adjust_aligned_offset(int *x, int *y, unsigned int intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane); unsigned int intel_tile_height(const struct drm_framebuffer *fb, int color_plane); +void intel_display_driver_register(struct drm_i915_private *i915); +void intel_display_driver_unregister(struct drm_i915_private *i915); + /* modesetting */ void intel_modeset_init_hw(struct drm_i915_private *i915); int intel_modeset_init_noirq(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 4e8caf88f32ca..fd93fedb0ec85 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -51,7 +50,6 @@ #include "display/intel_bw.h" #include "display/intel_cdclk.h" #include "display/intel_csr.h" -#include "display/intel_display_debugfs.h" #include "display/intel_display_types.h" #include "display/intel_dp.h" #include "display/intel_fbdev.h" @@ -678,32 +676,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) intel_gt_driver_register(&dev_priv->gt); - if (HAS_DISPLAY(dev_priv)) { - intel_display_debugfs_register(dev_priv); - - /* Must be done after probing outputs */ - intel_opregion_register(dev_priv); - acpi_video_register(); - - intel_audio_init(dev_priv); - - /* - * Some ports require correctly set-up hpd registers for - * detection to work properly (leading to ghost connected - * connector status), e.g. VGA on gm45. Hence we can only set - * up the initial fbdev config after hpd irqs are fully - * enabled. We do it last so that the async config cannot run - * before the connectors are registered. - */ - intel_fbdev_initial_config_async(dev); - - /* - * We need to coordinate the hotplugs with the asynchronous - * fbdev configuration, for which we use the - * fbdev->async_cookie. - */ - drm_kms_helper_poll_init(dev); - } + intel_display_driver_register(dev_priv); intel_power_domains_enable(dev_priv); intel_runtime_pm_enable(&dev_priv->runtime_pm); @@ -727,21 +700,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) intel_runtime_pm_disable(&dev_priv->runtime_pm); intel_power_domains_disable(dev_priv); - if (HAS_DISPLAY(dev_priv)) { - intel_fbdev_unregister(dev_priv); - intel_audio_deinit(dev_priv); - - /* - * After flushing the fbdev (incl. a late async config which - * will have delayed queuing of a hotplug event), then flush - * the hotplug events. - */ - drm_kms_helper_poll_fini(&dev_priv->drm); - drm_atomic_helper_shutdown(&dev_priv->drm); - - acpi_video_unregister(); - intel_opregion_unregister(dev_priv); - } + intel_display_driver_unregister(dev_priv); intel_gt_driver_unregister(&dev_priv->gt); From f3243b75dbc7f305806adaaca379338e25dba755 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 12 Feb 2021 20:27:56 -0800 Subject: [PATCH 073/142] drm/i915: move intel_init_audio_hooks inside display intel_init_audio_hooks() sets up hooks in the display struct and only makes sense when we have display. Move it inside intel_init_display_hooks() so it isn't called when we don't have display. Signed-off-by: Lucas De Marchi Reviewed-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20210213042756.953007-4-lucas.demarchi@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 1 + drivers/gpu/drm/i915/i915_drv.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b777497285da1..0b5bc18c4076e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12488,6 +12488,7 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { void intel_init_display_hooks(struct drm_i915_private *dev_priv) { intel_init_cdclk_hooks(dev_priv); + intel_init_audio_hooks(dev_priv); intel_dpll_init_clock_hook(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index fd93fedb0ec85..fb35fcf698f8a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -46,7 +46,6 @@ #include #include "display/intel_acpi.h" -#include "display/intel_audio.h" #include "display/intel_bw.h" #include "display/intel_cdclk.h" #include "display/intel_csr.h" @@ -349,7 +348,6 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) intel_irq_init(dev_priv); intel_init_display_hooks(dev_priv); intel_init_clock_gating_hooks(dev_priv); - intel_init_audio_hooks(dev_priv); intel_detect_preproduction_hw(dev_priv); From ad9529824cafbee214dbf580228e4c390dc61a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:20 +0200 Subject: [PATCH 074/142] drm/i915: Use intel_ddi_clk_select() for FDI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to put all DDI clock routing code into one place. Unify the FDI enable sequence to use the standard function instead of hand rolling its own. The disable sequence already uses the normal thing. Cc: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-2-ville.syrjala@linux.intel.com Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +++--- drivers/gpu/drm/i915/display/intel_ddi.h | 3 ++- drivers/gpu/drm/i915/display/intel_fdi.c | 7 +++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 3b97c00918123..cfa87dc7aa659 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -186,7 +186,7 @@ static void intel_wait_ddi_buf_active(struct drm_i915_private *dev_priv, port_name(port)); } -u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) +static u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll) { switch (pll->info->id) { case DPLL_ID_WRPLL1: @@ -1847,8 +1847,8 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); } -static void intel_ddi_clk_select(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +void intel_ddi_clk_select(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index f9a916cad7e75..e618e1c802528 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -28,7 +28,8 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state); -u32 hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll); +void intel_ddi_clk_select(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index 77df675e607e9..dbd6be3342c08 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -565,7 +565,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - u32 temp, i, rx_ctl_val, ddi_pll_sel; + u32 temp, i, rx_ctl_val; int n_entries; intel_ddi_get_buf_trans_fdi(dev_priv, &n_entries); @@ -595,9 +595,8 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), rx_ctl_val); /* Configure Port Clock Select */ - ddi_pll_sel = hsw_pll_to_ddi_pll_sel(crtc_state->shared_dpll); - intel_de_write(dev_priv, PORT_CLK_SEL(PORT_E), ddi_pll_sel); - drm_WARN_ON(&dev_priv->drm, ddi_pll_sel != PORT_CLK_SEL_SPLL); + drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll->info->id != DPLL_ID_SPLL); + intel_ddi_clk_select(encoder, crtc_state); /* Start the training iterating through available voltages and emphasis, * testing each value twice. */ From c133df699412ef2ab06509507a970a8e2533a716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:21 +0200 Subject: [PATCH 075/142] drm/i915: Introduce .{enable,disable}_clock() encoder vfuncs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code dealing with the clock routing for DDI encoders is a maintenance nightmare. Let's start cleaning it up by allowing the encoder to provide vfuncs for enablign/disabling the clock. We leave them initially unimplemented, falling back to the old if-else approach. v2: Convert the FDI enable sequence Reviewed-by: Lucas De Marchi #v2 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-3-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 29 +++++++++++++++---- drivers/gpu/drm/i915/display/intel_ddi.h | 4 +-- .../drm/i915/display/intel_display_types.h | 6 ++++ drivers/gpu/drm/i915/display/intel_fdi.c | 2 +- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index cfa87dc7aa659..f62fcb785a2ec 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1929,6 +1929,23 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder) } } +void intel_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + if (encoder->enable_clock) + encoder->enable_clock(encoder, crtc_state); + else + intel_ddi_clk_select(encoder, crtc_state); +} + +static void intel_ddi_disable_clock(struct intel_encoder *encoder) +{ + if (encoder->disable_clock) + encoder->disable_clock(encoder); + else + intel_ddi_clk_disable(encoder); +} + static void icl_program_mg_dp_mode(struct intel_digital_port *dig_port, const struct intel_crtc_state *crtc_state) @@ -2173,7 +2190,7 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, * hsw_crtc_enable()->intel_enable_shared_dpll(). We need only * configure the PLL to port mapping here. */ - intel_ddi_clk_select(encoder, crtc_state); + intel_ddi_enable_clock(encoder, crtc_state); /* 5. If IO power is controlled through PWR_WELL_CTL, Enable IO Power */ if (!intel_phy_is_tc(dev_priv, phy) || @@ -2294,7 +2311,7 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_pps_on(intel_dp); - intel_ddi_clk_select(encoder, crtc_state); + intel_ddi_enable_clock(encoder, crtc_state); if (!intel_phy_is_tc(dev_priv, phy) || dig_port->tc_mode != TC_PORT_TBT_ALT) { @@ -2369,7 +2386,7 @@ static void intel_ddi_pre_enable_hdmi(struct intel_atomic_state *state, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); intel_dp_dual_mode_set_tmds_output(intel_hdmi, true); - intel_ddi_clk_select(encoder, crtc_state); + intel_ddi_enable_clock(encoder, crtc_state); drm_WARN_ON(&dev_priv->drm, dig_port->ddi_io_wakeref); dig_port->ddi_io_wakeref = intel_display_power_get(dev_priv, @@ -2521,7 +2538,7 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, dig_port->ddi_io_power_domain, fetch_and_zero(&dig_port->ddi_io_wakeref)); - intel_ddi_clk_disable(encoder); + intel_ddi_disable_clock(encoder); } static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state, @@ -2544,7 +2561,7 @@ static void intel_ddi_post_disable_hdmi(struct intel_atomic_state *state, dig_port->ddi_io_power_domain, fetch_and_zero(&dig_port->ddi_io_wakeref)); - intel_ddi_clk_disable(encoder); + intel_ddi_disable_clock(encoder); intel_dp_dual_mode_set_tmds_output(intel_hdmi, false); } @@ -2644,7 +2661,7 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, intel_de_write(dev_priv, FDI_RX_CTL(PIPE_A), val); intel_disable_ddi_buf(encoder, old_crtc_state); - intel_ddi_clk_disable(encoder); + intel_ddi_disable_clock(encoder); val = intel_de_read(dev_priv, FDI_RX_MISC(PIPE_A)); val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index e618e1c802528..1aa0eedbf3421 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -28,8 +28,8 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state); -void intel_ddi_clk_select(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state); +void intel_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index ebaa9d0ed376b..07b7f5eae5877 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -220,6 +220,12 @@ struct intel_encoder { * encoders have been disabled and suspended. */ void (*shutdown)(struct intel_encoder *encoder); + /* + * Enable/disable the clock to the port. + */ + void (*enable_clock)(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); + void (*disable_clock)(struct intel_encoder *encoder); enum hpd_pin hpd_pin; enum intel_display_power_domain power_domain; /* for communication with audio component; protected by av_mutex */ diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index dbd6be3342c08..60b29110099a0 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -596,7 +596,7 @@ void hsw_fdi_link_train(struct intel_encoder *encoder, /* Configure Port Clock Select */ drm_WARN_ON(&dev_priv->drm, crtc_state->shared_dpll->info->id != DPLL_ID_SPLL); - intel_ddi_clk_select(encoder, crtc_state); + intel_ddi_enable_clock(encoder, crtc_state); /* Start the training iterating through available voltages and emphasis, * testing each value twice. */ From d135368d1632b77da3804c65309392011f8de687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:22 +0200 Subject: [PATCH 076/142] drm/i915: Extract hsw_ddi_{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yank out the HSW/BDW code from intel_ddi_clk_{select,disable}() and put it into the new encoder .{enable,disable}_clock() vfuncs. v2: s/dev_priv/i915/ (Lucas) v3: Deal with FDI Reviewed-by: Lucas De Marchi #v2 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_crt.c | 2 ++ drivers/gpu/drm/i915/display/intel_ddi.c | 32 +++++++++++++++++++----- drivers/gpu/drm/i915/display/intel_ddi.h | 3 +++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 077ebc7e63965..91a8a42b4aa26 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -1076,6 +1076,8 @@ void intel_crt_init(struct drm_i915_private *dev_priv) crt->base.enable = hsw_enable_crt; crt->base.disable = hsw_disable_crt; crt->base.post_disable = hsw_post_disable_crt; + crt->base.enable_clock = hsw_ddi_enable_clock; + crt->base.disable_clock = hsw_ddi_disable_clock; } else { if (HAS_PCH_SPLIT(dev_priv)) { crt->base.compute_config = pch_crt_compute_config; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f62fcb785a2ec..2a0723f564180 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1898,9 +1898,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder, intel_de_write(dev_priv, DPLL_CTRL2, val); - } else if (INTEL_GEN(dev_priv) < 9) { - intel_de_write(dev_priv, PORT_CLK_SEL(port), - hsw_pll_to_ddi_pll_sel(pll)); } mutex_unlock(&dev_priv->dpll.lock); @@ -1923,12 +1920,30 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder) } else if (IS_GEN9_BC(dev_priv)) { intel_de_write(dev_priv, DPLL_CTRL2, intel_de_read(dev_priv, DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port)); - } else if (INTEL_GEN(dev_priv) < 9) { - intel_de_write(dev_priv, PORT_CLK_SEL(port), - PORT_CLK_SEL_NONE); } } +void hsw_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum port port = encoder->port; + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + intel_de_write(i915, PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll)); +} + +void hsw_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + intel_de_write(i915, PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); +} + void intel_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -4083,6 +4098,11 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; + if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { + encoder->enable_clock = hsw_ddi_enable_clock; + encoder->disable_clock = hsw_ddi_disable_clock; + } + if (IS_DG1(dev_priv)) encoder->hpd_pin = dg1_hpd_pin(dev_priv, port); else if (IS_ROCKETLAKE(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 1aa0eedbf3421..4a0c1d5c85e7a 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -30,6 +30,9 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, const struct drm_connector_state *old_conn_state); void intel_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); +void hsw_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state); +void hsw_ddi_disable_clock(struct intel_encoder *encoder); void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, From 38e31f1acd643f27881e2a5a3e117e265b38d78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:23 +0200 Subject: [PATCH 077/142] drm/i915: Extract skl_ddi_{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the DDI clock routing clode for skl/derivatives into the new encoder vfuncs. v2: s/dev_priv/i915/ (Lucas) Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-5-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 53 +++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 2a0723f564180..dba6c98a8ccfc 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1887,17 +1887,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder, val = intel_de_read(dev_priv, DPCLKA_CFGCR0); val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); intel_de_write(dev_priv, DPCLKA_CFGCR0, val); - } else if (IS_GEN9_BC(dev_priv)) { - /* DDI -> PLL mapping */ - val = intel_de_read(dev_priv, DPLL_CTRL2); - - val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) | - DPLL_CTRL2_DDI_CLK_SEL_MASK(port)); - val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) | - DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); - - intel_de_write(dev_priv, DPLL_CTRL2, val); - } mutex_unlock(&dev_priv->dpll.lock); @@ -1917,12 +1906,43 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder) } else if (IS_CANNONLAKE(dev_priv)) { intel_de_write(dev_priv, DPCLKA_CFGCR0, intel_de_read(dev_priv, DPCLKA_CFGCR0) | DPCLKA_CFGCR0_DDI_CLK_OFF(port)); - } else if (IS_GEN9_BC(dev_priv)) { - intel_de_write(dev_priv, DPLL_CTRL2, - intel_de_read(dev_priv, DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port)); } } +static void skl_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum port port = encoder->port; + u32 val; + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + mutex_lock(&i915->dpll.lock); + + val = intel_de_read(i915, DPLL_CTRL2); + + val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) | + DPLL_CTRL2_DDI_CLK_SEL_MASK(port)); + val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) | + DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); + + intel_de_write(i915, DPLL_CTRL2, val); + + mutex_unlock(&i915->dpll.lock); +} + +static void skl_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + intel_de_write(i915, DPLL_CTRL2, + intel_de_read(i915, DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port)); +} + void hsw_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -4098,7 +4118,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { + if (IS_GEN9_BC(dev_priv)) { + encoder->enable_clock = skl_ddi_enable_clock; + encoder->disable_clock = skl_ddi_disable_clock; + } else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { encoder->enable_clock = hsw_ddi_enable_clock; encoder->disable_clock = hsw_ddi_disable_clock; } From 2c7b1d340f194cff57373500240b3a44f20059cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:24 +0200 Subject: [PATCH 078/142] drm/i195: Extract cnl_ddi_{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the DDI clock routing for CNL into the new vfuncs. v2: s/dev_priv/i915/ (Lucas) Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 62 ++++++++++++++++-------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index dba6c98a8ccfc..637cc39194eba 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1853,7 +1853,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; enum phy phy = intel_port_to_phy(dev_priv, port); - u32 val; const struct intel_shared_dpll *pll = crtc_state->shared_dpll; if (drm_WARN_ON(&dev_priv->drm, !pll)) @@ -1872,21 +1871,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder, */ intel_de_write(dev_priv, DDI_CLK_SEL(port), DDI_CLK_SEL_MG); - } else if (IS_CANNONLAKE(dev_priv)) { - /* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */ - val = intel_de_read(dev_priv, DPCLKA_CFGCR0); - val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); - intel_de_write(dev_priv, DPCLKA_CFGCR0, val); - - /* - * Configure DPCLKA_CFGCR0 to turn on the clock for the DDI. - * This step and the step before must be done with separate - * register writes. - */ - val = intel_de_read(dev_priv, DPCLKA_CFGCR0); - val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); - intel_de_write(dev_priv, DPCLKA_CFGCR0, val); } mutex_unlock(&dev_priv->dpll.lock); @@ -1903,12 +1887,47 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder) (IS_JSL_EHL(dev_priv) && port >= PORT_C)) intel_de_write(dev_priv, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); - } else if (IS_CANNONLAKE(dev_priv)) { - intel_de_write(dev_priv, DPCLKA_CFGCR0, - intel_de_read(dev_priv, DPCLKA_CFGCR0) | DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } } +static void cnl_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum port port = encoder->port; + u32 val; + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + mutex_lock(&i915->dpll.lock); + + val = intel_de_read(i915, DPCLKA_CFGCR0); + val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); + val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); + intel_de_write(i915, DPCLKA_CFGCR0, val); + + /* + * "This step and the step before must be + * done with separate register writes." + */ + val = intel_de_read(i915, DPCLKA_CFGCR0); + val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); + intel_de_write(i915, DPCLKA_CFGCR0, val); + + mutex_unlock(&i915->dpll.lock); +} + +static void cnl_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + intel_de_write(i915, DPCLKA_CFGCR0, + intel_de_read(i915, DPCLKA_CFGCR0) | DPCLKA_CFGCR0_DDI_CLK_OFF(port)); +} + static void skl_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -4118,7 +4137,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_GEN9_BC(dev_priv)) { + if (IS_CANNONLAKE(dev_priv)) { + encoder->enable_clock = cnl_ddi_enable_clock; + encoder->disable_clock = cnl_ddi_disable_clock; + } else if (IS_GEN9_BC(dev_priv)) { encoder->enable_clock = skl_ddi_enable_clock; encoder->disable_clock = skl_ddi_disable_clock; } else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { From 35bb6b1a0d19ef619cdfe2bcf6d95c0625f9492e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:25 +0200 Subject: [PATCH 079/142] drm/i915: Convert DG1 over to .{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace dg1_{map,unmap}_plls_to_ports() with the appropriate encoder vfuncs. And let's relocate the disable function next to the enable function while at it. Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-7-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 43 ++++++++++++------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 637cc39194eba..4a0798b5cc303 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1599,8 +1599,8 @@ static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, return 0; } -static void dg1_map_plls_to_ports(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void dg1_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; @@ -1633,6 +1633,19 @@ static void dg1_map_plls_to_ports(struct intel_encoder *encoder, mutex_unlock(&dev_priv->dpll.lock); } +static void dg1_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + + mutex_lock(&dev_priv->dpll.lock); + + intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0, + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); + + mutex_unlock(&dev_priv->dpll.lock); +} + static void icl_map_plls_to_ports(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1685,19 +1698,6 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, mutex_unlock(&dev_priv->dpll.lock); } -static void dg1_unmap_plls_to_ports(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - - mutex_lock(&dev_priv->dpll.lock); - - intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0, - DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); - - mutex_unlock(&dev_priv->dpll.lock); -} - static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2479,9 +2479,7 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state, drm_WARN_ON(&dev_priv->drm, crtc_state->has_pch_encoder); - if (IS_DG1(dev_priv)) - dg1_map_plls_to_ports(encoder, crtc_state); - else if (INTEL_GEN(dev_priv) >= 11) + if (!IS_DG1(dev_priv) && INTEL_GEN(dev_priv) >= 11) icl_map_plls_to_ports(encoder, crtc_state); intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); @@ -2682,9 +2680,7 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state, intel_ddi_post_disable_dp(state, encoder, old_crtc_state, old_conn_state); - if (IS_DG1(dev_priv)) - dg1_unmap_plls_to_ports(encoder); - else if (INTEL_GEN(dev_priv) >= 11) + if (!IS_DG1(dev_priv) && INTEL_GEN(dev_priv) >= 11) icl_unmap_plls_to_ports(encoder); if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port) @@ -4137,7 +4133,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_CANNONLAKE(dev_priv)) { + if (IS_DG1(dev_priv)) { + encoder->enable_clock = dg1_ddi_enable_clock; + encoder->disable_clock = dg1_ddi_disable_clock; + } else if (IS_CANNONLAKE(dev_priv)) { encoder->enable_clock = cnl_ddi_enable_clock; encoder->disable_clock = cnl_ddi_disable_clock; } else if (IS_GEN9_BC(dev_priv)) { From 36ecb0ec105412aa7e7c89991a7cff90bf90b2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:26 +0200 Subject: [PATCH 080/142] drm/i915: Extract icl+ .{enable,disable}_clock() vfuncs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For ICL+ we have several styles of clock routing for DDIs: 1) TC DDI + TC PHY -> needs DDI_CLK_SEL==MG/TBT part form intel_ddi_clk_{select,disable}() and ICL_DPCLKA_CFGCR0_TC_CLK_OFF part form icl_{map,unmap}_plls_to_ports() 2) ICL/TGL combo DDI + combo PHY -> just need the stuff from icl_{map,unmap}_plls_to_ports() 3) JSL/EHL TC DDI + combo PHY -> needs DDI_CLK_SEL==MG part from intel_ddi_clk_{select,disable}() and the full combo style clock selection from icl_{map,unmap}_plls_to_ports() 4) ADLS/RKL -> these use both TC and combo DDIs with combo PHYs, however they always use the full combo style clock selection as per icl_{map,unmap}_plls_to_ports() and do not use DDI_CLK_SEL at all, thus get treated the same as 2) We extract all that from the current mess in the following way: 1) icl_ddi_tc_{enable,disable}_clock() 2) icl_ddi_combo_{enable,disable}_clock() 3) jsl_ddi_tc_{enable,disable}_clock() 4) for now we reuse icl_ddi_combo_{enable,disable}_clock() here v2: s/dev_priv/i915/ (Lucas) Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-8-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 157 ++++++++++++++--------- 1 file changed, 99 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 4a0798b5cc303..c325e54fb3e7a 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1646,8 +1646,8 @@ static void dg1_ddi_disable_clock(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpll.lock); } -static void icl_map_plls_to_ports(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; @@ -1675,22 +1675,20 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, drm_WARN_ON(&dev_priv->drm, (val & icl_dpclka_cfgcr0_clk_off(dev_priv, phy)) == 0); - if (intel_phy_is_combo(dev_priv, phy)) { - /* - * Even though this register references DDIs, note that we - * want to pass the PHY rather than the port (DDI). For - * ICL, port=phy in all cases so it doesn't matter, but for - * EHL the bspec notes the following: - * - * "DDID clock tied to DDIA clock, so DPCLKA_CFGCR0 DDIA - * Clock Select chooses the PLL for both DDIA and DDID and - * drives port A in all cases." - */ - val &= ~mask; - val |= sel; - intel_de_write(dev_priv, reg, val); - intel_de_posting_read(dev_priv, reg); - } + /* + * Even though this register references DDIs, note that we + * want to pass the PHY rather than the port (DDI). For + * ICL, port=phy in all cases so it doesn't matter, but for + * EHL the bspec notes the following: + * + * "DDID clock tied to DDIA clock, so DPCLKA_CFGCR0 DDIA + * Clock Select chooses the PLL for both DDIA and DDID and + * drives port A in all cases." + */ + val &= ~mask; + val |= sel; + intel_de_write(dev_priv, reg, val); + intel_de_posting_read(dev_priv, reg); val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, phy); intel_de_write(dev_priv, reg, val); @@ -1698,7 +1696,7 @@ static void icl_map_plls_to_ports(struct intel_encoder *encoder, mutex_unlock(&dev_priv->dpll.lock); } -static void icl_unmap_plls_to_ports(struct intel_encoder *encoder) +static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); @@ -1847,47 +1845,71 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); } -void intel_ddi_clk_select(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void jsl_ddi_tc_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum port port = encoder->port; - enum phy phy = intel_port_to_phy(dev_priv, port); + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + /* + * "For DDIC and DDID, program DDI_CLK_SEL to map the MG clock to the port. + * MG does not exist, but the programming is required to ungate DDIC and DDID." + */ + intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_MG); + + icl_ddi_combo_enable_clock(encoder, crtc_state); +} + +static void jsl_ddi_tc_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + icl_ddi_combo_disable_clock(encoder); + + intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); +} + +static void icl_ddi_tc_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum tc_port tc_port = intel_port_to_tc(i915, encoder->port); + enum port port = encoder->port; - if (drm_WARN_ON(&dev_priv->drm, !pll)) + if (drm_WARN_ON(&i915->drm, !pll)) return; - mutex_lock(&dev_priv->dpll.lock); + intel_de_write(i915, DDI_CLK_SEL(port), + icl_pll_to_ddi_clk_sel(encoder, crtc_state)); - if (INTEL_GEN(dev_priv) >= 11) { - if (!intel_phy_is_combo(dev_priv, phy)) - intel_de_write(dev_priv, DDI_CLK_SEL(port), - icl_pll_to_ddi_clk_sel(encoder, crtc_state)); - else if (IS_JSL_EHL(dev_priv) && port >= PORT_C) - /* - * MG does not exist but the programming is required - * to ungate DDIC and DDID - */ - intel_de_write(dev_priv, DDI_CLK_SEL(port), - DDI_CLK_SEL_MG); - } + mutex_lock(&i915->dpll.lock); - mutex_unlock(&dev_priv->dpll.lock); + intel_de_rmw(i915, ICL_DPCLKA_CFGCR0, + ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port), 0); + + mutex_unlock(&i915->dpll.lock); } -static void intel_ddi_clk_disable(struct intel_encoder *encoder) +static void icl_ddi_tc_disable_clock(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, encoder->port); enum port port = encoder->port; - enum phy phy = intel_port_to_phy(dev_priv, port); - if (INTEL_GEN(dev_priv) >= 11) { - if (!intel_phy_is_combo(dev_priv, phy) || - (IS_JSL_EHL(dev_priv) && port >= PORT_C)) - intel_de_write(dev_priv, DDI_CLK_SEL(port), - DDI_CLK_SEL_NONE); - } + mutex_lock(&i915->dpll.lock); + + intel_de_rmw(i915, ICL_DPCLKA_CFGCR0, + 0, ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port)); + + mutex_unlock(&i915->dpll.lock); + + intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); } static void cnl_ddi_enable_clock(struct intel_encoder *encoder, @@ -1988,16 +2010,12 @@ void intel_ddi_enable_clock(struct intel_encoder *encoder, { if (encoder->enable_clock) encoder->enable_clock(encoder, crtc_state); - else - intel_ddi_clk_select(encoder, crtc_state); } static void intel_ddi_disable_clock(struct intel_encoder *encoder) { if (encoder->disable_clock) encoder->disable_clock(encoder); - else - intel_ddi_clk_disable(encoder); } static void @@ -2479,9 +2497,6 @@ static void intel_ddi_pre_enable(struct intel_atomic_state *state, drm_WARN_ON(&dev_priv->drm, crtc_state->has_pch_encoder); - if (!IS_DG1(dev_priv) && INTEL_GEN(dev_priv) >= 11) - icl_map_plls_to_ports(encoder, crtc_state); - intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { @@ -2680,9 +2695,6 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state, intel_ddi_post_disable_dp(state, encoder, old_crtc_state, old_conn_state); - if (!IS_DG1(dev_priv) && INTEL_GEN(dev_priv) >= 11) - icl_unmap_plls_to_ports(encoder); - if (intel_crtc_has_dp_encoder(old_crtc_state) || is_tc_port) intel_display_power_put(dev_priv, intel_ddi_main_link_aux_domain(dig_port), @@ -4029,6 +4041,16 @@ static enum hpd_pin skl_hpd_pin(struct drm_i915_private *dev_priv, enum port por return HPD_PORT_A + port - PORT_A; } +static bool intel_ddi_is_tc(struct drm_i915_private *i915, enum port port) +{ + if (INTEL_GEN(i915) >= 12) + return port >= PORT_TC1; + else if (INTEL_GEN(i915) >= 11) + return port >= PORT_C; + else + return false; +} + #define port_tc_name(port) ((port) - PORT_TC1 + '1') #define tc_port_name(tc_port) ((tc_port) - TC_PORT_1 + '1') @@ -4133,9 +4155,28 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_DG1(dev_priv)) { + if (IS_ALDERLAKE_S(dev_priv) || IS_ROCKETLAKE(dev_priv)) { + encoder->enable_clock = icl_ddi_combo_enable_clock; + encoder->disable_clock = icl_ddi_combo_disable_clock; + } else if (IS_DG1(dev_priv)) { encoder->enable_clock = dg1_ddi_enable_clock; encoder->disable_clock = dg1_ddi_disable_clock; + } else if (IS_JSL_EHL(dev_priv)) { + if (intel_ddi_is_tc(dev_priv, port)) { + encoder->enable_clock = jsl_ddi_tc_enable_clock; + encoder->disable_clock = jsl_ddi_tc_disable_clock; + } else { + encoder->enable_clock = icl_ddi_combo_enable_clock; + encoder->disable_clock = icl_ddi_combo_disable_clock; + } + } else if (INTEL_GEN(dev_priv) >= 11) { + if (intel_ddi_is_tc(dev_priv, port)) { + encoder->enable_clock = icl_ddi_tc_enable_clock; + encoder->disable_clock = icl_ddi_tc_disable_clock; + } else { + encoder->enable_clock = icl_ddi_combo_enable_clock; + encoder->disable_clock = icl_ddi_combo_disable_clock; + } } else if (IS_CANNONLAKE(dev_priv)) { encoder->enable_clock = cnl_ddi_enable_clock; encoder->disable_clock = cnl_ddi_disable_clock; From 7815ed88c6cfba414a6ed5be6be2318fbe7e8b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:27 +0200 Subject: [PATCH 081/142] drm/i915: Use intel_de_rmw() for DDI clock routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DDI clock routing programming is riddled with shared registers, forcing us to do a lot of RMW. Switch over to intel_de_rmw() to make that a bit less obnoxious. Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-9-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 77 +++++++++--------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c325e54fb3e7a..ef759b148131c 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1605,7 +1605,6 @@ static void dg1_ddi_enable_clock(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - u32 val; /* * If we fail this, something went very wrong: first 2 PLLs should be @@ -1618,17 +1617,12 @@ static void dg1_ddi_enable_clock(struct intel_encoder *encoder, mutex_lock(&dev_priv->dpll.lock); - val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); - drm_WARN_ON(&dev_priv->drm, - (val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)) == 0); - - val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - val |= DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); - intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); - intel_de_posting_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); + intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy)); - val &= ~DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); - intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); + intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy), 0); mutex_unlock(&dev_priv->dpll.lock); } @@ -1640,8 +1634,8 @@ static void dg1_ddi_disable_clock(struct intel_encoder *encoder) mutex_lock(&dev_priv->dpll.lock); - intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), 0, - DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); + intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), + 0, DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); mutex_unlock(&dev_priv->dpll.lock); } @@ -1652,7 +1646,7 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - u32 val, mask, sel; + u32 mask, sel; i915_reg_t reg; if (IS_ALDERLAKE_S(dev_priv)) { @@ -1671,10 +1665,6 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, mutex_lock(&dev_priv->dpll.lock); - val = intel_de_read(dev_priv, reg); - drm_WARN_ON(&dev_priv->drm, - (val & icl_dpclka_cfgcr0_clk_off(dev_priv, phy)) == 0); - /* * Even though this register references DDIs, note that we * want to pass the PHY rather than the port (DDI). For @@ -1685,13 +1675,10 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, * Clock Select chooses the PLL for both DDIA and DDID and * drives port A in all cases." */ - val &= ~mask; - val |= sel; - intel_de_write(dev_priv, reg, val); - intel_de_posting_read(dev_priv, reg); + intel_de_rmw(dev_priv, reg, mask, sel); - val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, phy); - intel_de_write(dev_priv, reg, val); + intel_de_rmw(dev_priv, reg, + icl_dpclka_cfgcr0_clk_off(dev_priv, phy), 0); mutex_unlock(&dev_priv->dpll.lock); } @@ -1700,7 +1687,6 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - u32 val; i915_reg_t reg; mutex_lock(&dev_priv->dpll.lock); @@ -1710,10 +1696,10 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) else reg = ICL_DPCLKA_CFGCR0; - val = intel_de_read(dev_priv, reg); - val |= icl_dpclka_cfgcr0_clk_off(dev_priv, phy); + mutex_lock(&dev_priv->dpll.lock); - intel_de_write(dev_priv, reg, val); + intel_de_rmw(dev_priv, reg, + 0, icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); mutex_unlock(&dev_priv->dpll.lock); } @@ -1918,25 +1904,22 @@ static void cnl_ddi_enable_clock(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum port port = encoder->port; - u32 val; if (drm_WARN_ON(&i915->drm, !pll)) return; mutex_lock(&i915->dpll.lock); - val = intel_de_read(i915, DPCLKA_CFGCR0); - val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); - intel_de_write(i915, DPCLKA_CFGCR0, val); + intel_de_rmw(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port), + DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port)); /* * "This step and the step before must be * done with separate register writes." */ - val = intel_de_read(i915, DPCLKA_CFGCR0); - val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); - intel_de_write(i915, DPCLKA_CFGCR0, val); + intel_de_rmw(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_OFF(port), 0); mutex_unlock(&i915->dpll.lock); } @@ -1946,8 +1929,8 @@ static void cnl_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum port port = encoder->port; - intel_de_write(i915, DPCLKA_CFGCR0, - intel_de_read(i915, DPCLKA_CFGCR0) | DPCLKA_CFGCR0_DDI_CLK_OFF(port)); + intel_de_rmw(i915, DPCLKA_CFGCR0, + 0, DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } static void skl_ddi_enable_clock(struct intel_encoder *encoder, @@ -1956,21 +1939,17 @@ static void skl_ddi_enable_clock(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum port port = encoder->port; - u32 val; if (drm_WARN_ON(&i915->drm, !pll)) return; mutex_lock(&i915->dpll.lock); - val = intel_de_read(i915, DPLL_CTRL2); - - val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) | - DPLL_CTRL2_DDI_CLK_SEL_MASK(port)); - val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) | - DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); - - intel_de_write(i915, DPLL_CTRL2, val); + intel_de_rmw(i915, DPLL_CTRL2, + DPLL_CTRL2_DDI_CLK_OFF(port) | + DPLL_CTRL2_DDI_CLK_SEL_MASK(port), + DPLL_CTRL2_DDI_CLK_SEL(pll->info->id, port) | + DPLL_CTRL2_DDI_SEL_OVERRIDE(port)); mutex_unlock(&i915->dpll.lock); } @@ -1980,8 +1959,8 @@ static void skl_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum port port = encoder->port; - intel_de_write(i915, DPLL_CTRL2, - intel_de_read(i915, DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port)); + intel_de_rmw(i915, DPLL_CTRL2, + 0, DPLL_CTRL2_DDI_CLK_OFF(port)); } void hsw_ddi_enable_clock(struct intel_encoder *encoder, From be317ca0a338ab3976d7c74975458638d0cedf90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:28 +0200 Subject: [PATCH 082/142] drm/i915: Sprinkle a few missing locks around shared DDI clock registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code attempts to protect the RMWs into global clock routing registers with a mutex, but forgets to do so in a few places. Let's remedy that. Note that at the moment we serialize all modesets onto single wq, so this shouldn't actually matter. But maybe one day we wish to attempt parallel modesets again... Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-10-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ef759b148131c..a14baea12800b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1929,8 +1929,12 @@ static void cnl_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum port port = encoder->port; + mutex_lock(&i915->dpll.lock); + intel_de_rmw(i915, DPCLKA_CFGCR0, 0, DPCLKA_CFGCR0_DDI_CLK_OFF(port)); + + mutex_unlock(&i915->dpll.lock); } static void skl_ddi_enable_clock(struct intel_encoder *encoder, @@ -1959,8 +1963,12 @@ static void skl_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum port port = encoder->port; + mutex_lock(&i915->dpll.lock); + intel_de_rmw(i915, DPLL_CTRL2, 0, DPLL_CTRL2_DDI_CLK_OFF(port)); + + mutex_unlock(&i915->dpll.lock); } void hsw_ddi_enable_clock(struct intel_encoder *encoder, From f67a008e02e5751296300f9e7aa1028afc4a4964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:29 +0200 Subject: [PATCH 083/142] drm/i915: Sprinkle WARN(!pll) into icl/dg1 .clock_enable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The other DDI .enable_clock() functions are trying to protect us against pll==NULL. A bit tempted to throw out all the WARNs as just unnecessary noise, but I guess they might have some use when poking around the shared_dpll code (not sure it wouldn't oops elsewhere though). So let's unify it all and sprinkle in the missing WARNs for icl/dg1. Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-11-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index a14baea12800b..9c321b10abbf2 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1606,6 +1606,9 @@ static void dg1_ddi_enable_clock(struct intel_encoder *encoder, struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + if (drm_WARN_ON(&dev_priv->drm, !pll)) + return; + /* * If we fail this, something went very wrong: first 2 PLLs should be * used by first 2 phys and last 2 PLLs by last phys @@ -1663,6 +1666,9 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); } + if (drm_WARN_ON(&dev_priv->drm, !pll)) + return; + mutex_lock(&dev_priv->dpll.lock); /* From 9c6a5c35470b576cc9d8fd1da1eee09f5014b1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:30 +0200 Subject: [PATCH 084/142] drm/i915: Extract _cnl_ddi_{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the DPCLKA_CFGCR handling follows a common pattern. Let's extract that to a small helper that just takes a few parameters each caller can customize. Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-12-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 108 +++++++++-------------- 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9c321b10abbf2..349f0bce93747 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1599,11 +1599,37 @@ static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, return 0; } +static void _cnl_ddi_enable_clock(struct drm_i915_private *i915, i915_reg_t reg, + u32 clk_sel_mask, u32 clk_sel, u32 clk_off) +{ + mutex_lock(&i915->dpll.lock); + + intel_de_rmw(i915, reg, clk_sel_mask, clk_sel); + + /* + * "This step and the step before must be + * done with separate register writes." + */ + intel_de_rmw(i915, reg, clk_off, 0); + + mutex_unlock(&i915->dpll.lock); +} + +static void _cnl_ddi_disable_clock(struct drm_i915_private *i915, i915_reg_t reg, + u32 clk_off) +{ + mutex_lock(&i915->dpll.lock); + + intel_de_rmw(i915, reg, 0, clk_off); + + mutex_unlock(&i915->dpll.lock); +} + static void dg1_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_shared_dpll *pll = crtc_state->shared_dpll; + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); if (drm_WARN_ON(&dev_priv->drm, !pll)) @@ -1618,16 +1644,10 @@ static void dg1_ddi_enable_clock(struct intel_encoder *encoder, (pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C))) return; - mutex_lock(&dev_priv->dpll.lock); - - intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), - DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), - DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy)); - - intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), - DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy), 0); - - mutex_unlock(&dev_priv->dpll.lock); + _cnl_ddi_enable_clock(dev_priv, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } static void dg1_ddi_disable_clock(struct intel_encoder *encoder) @@ -1635,19 +1655,15 @@ static void dg1_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - mutex_lock(&dev_priv->dpll.lock); - - intel_de_rmw(dev_priv, DG1_DPCLKA_CFGCR0(phy), - 0, DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); - - mutex_unlock(&dev_priv->dpll.lock); + _cnl_ddi_disable_clock(dev_priv, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_shared_dpll *pll = crtc_state->shared_dpll; + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); u32 mask, sel; i915_reg_t reg; @@ -1669,24 +1685,8 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, if (drm_WARN_ON(&dev_priv->drm, !pll)) return; - mutex_lock(&dev_priv->dpll.lock); - - /* - * Even though this register references DDIs, note that we - * want to pass the PHY rather than the port (DDI). For - * ICL, port=phy in all cases so it doesn't matter, but for - * EHL the bspec notes the following: - * - * "DDID clock tied to DDIA clock, so DPCLKA_CFGCR0 DDIA - * Clock Select chooses the PLL for both DDIA and DDID and - * drives port A in all cases." - */ - intel_de_rmw(dev_priv, reg, mask, sel); - - intel_de_rmw(dev_priv, reg, - icl_dpclka_cfgcr0_clk_off(dev_priv, phy), 0); - - mutex_unlock(&dev_priv->dpll.lock); + _cnl_ddi_enable_clock(dev_priv, reg, mask, sel, + icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); } static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) @@ -1695,19 +1695,13 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) enum phy phy = intel_port_to_phy(dev_priv, encoder->port); i915_reg_t reg; - mutex_lock(&dev_priv->dpll.lock); - if (IS_ALDERLAKE_S(dev_priv)) reg = ADLS_DPCLKA_CFGCR(phy); else reg = ICL_DPCLKA_CFGCR0; - mutex_lock(&dev_priv->dpll.lock); - - intel_de_rmw(dev_priv, reg, - 0, icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); - - mutex_unlock(&dev_priv->dpll.lock); + _cnl_ddi_disable_clock(dev_priv, reg, + icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); } static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv, @@ -1914,20 +1908,10 @@ static void cnl_ddi_enable_clock(struct intel_encoder *encoder, if (drm_WARN_ON(&i915->drm, !pll)) return; - mutex_lock(&i915->dpll.lock); - - intel_de_rmw(i915, DPCLKA_CFGCR0, - DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port), - DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port)); - - /* - * "This step and the step before must be - * done with separate register writes." - */ - intel_de_rmw(i915, DPCLKA_CFGCR0, - DPCLKA_CFGCR0_DDI_CLK_OFF(port), 0); - - mutex_unlock(&i915->dpll.lock); + _cnl_ddi_enable_clock(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port), + DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port), + DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } static void cnl_ddi_disable_clock(struct intel_encoder *encoder) @@ -1935,12 +1919,8 @@ static void cnl_ddi_disable_clock(struct intel_encoder *encoder) struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum port port = encoder->port; - mutex_lock(&i915->dpll.lock); - - intel_de_rmw(i915, DPCLKA_CFGCR0, - 0, DPCLKA_CFGCR0_DDI_CLK_OFF(port)); - - mutex_unlock(&i915->dpll.lock); + _cnl_ddi_disable_clock(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } static void skl_ddi_enable_clock(struct intel_encoder *encoder, From 40b316d4b0865358a846ca3c9df9d443b10d3c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:31 +0200 Subject: [PATCH 085/142] drm/i915: Split adl-s/rkl from icl_ddi_combo_{enable,disable}_clock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since .{enable,disable}_clock() are already vfuncs it's a bit silly to have if-ladders inside them. Just provide specialized version for adl-s and rkl so we don't need any of that. v2: s/dev_priv/i915/ (Lucas) Fix typos in platform names (Lucas) Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-13-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 91 ++++++++++++++++-------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 349f0bce93747..685fc22d6ccbf 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1625,6 +1625,56 @@ static void _cnl_ddi_disable_clock(struct drm_i915_private *i915, i915_reg_t reg mutex_unlock(&i915->dpll.lock); } +static void adls_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + _cnl_ddi_enable_clock(i915, ADLS_DPCLKA_CFGCR(phy), + ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy), + pll->info->id << ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + +static void adls_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + _cnl_ddi_disable_clock(i915, ADLS_DPCLKA_CFGCR(phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + +static void rkl_ddi_enable_clock(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + const struct intel_shared_dpll *pll = crtc_state->shared_dpll; + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (drm_WARN_ON(&i915->drm, !pll)) + return; + + _cnl_ddi_enable_clock(i915, ICL_DPCLKA_CFGCR0, + RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy), + RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + +static void rkl_ddi_disable_clock(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + _cnl_ddi_disable_clock(i915, ICL_DPCLKA_CFGCR0, + RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + static void dg1_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1665,43 +1715,23 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - u32 mask, sel; - i915_reg_t reg; - - if (IS_ALDERLAKE_S(dev_priv)) { - reg = ADLS_DPCLKA_CFGCR(phy); - mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); - sel = ((pll->info->id) << ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy)); - } else if (IS_ROCKETLAKE(dev_priv)) { - reg = ICL_DPCLKA_CFGCR0; - mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - sel = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); - } else { - reg = ICL_DPCLKA_CFGCR0; - mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - sel = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy); - } if (drm_WARN_ON(&dev_priv->drm, !pll)) return; - _cnl_ddi_enable_clock(dev_priv, reg, mask, sel, - icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); + _cnl_ddi_enable_clock(dev_priv, ICL_DPCLKA_CFGCR0, + ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - i915_reg_t reg; - - if (IS_ALDERLAKE_S(dev_priv)) - reg = ADLS_DPCLKA_CFGCR(phy); - else - reg = ICL_DPCLKA_CFGCR0; - _cnl_ddi_disable_clock(dev_priv, reg, - icl_dpclka_cfgcr0_clk_off(dev_priv, phy)); + _cnl_ddi_disable_clock(dev_priv, ICL_DPCLKA_CFGCR0, + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv, @@ -4128,9 +4158,12 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->cloneable = 0; encoder->pipe_mask = ~0; - if (IS_ALDERLAKE_S(dev_priv) || IS_ROCKETLAKE(dev_priv)) { - encoder->enable_clock = icl_ddi_combo_enable_clock; - encoder->disable_clock = icl_ddi_combo_disable_clock; + if (IS_ALDERLAKE_S(dev_priv)) { + encoder->enable_clock = adls_ddi_enable_clock; + encoder->disable_clock = adls_ddi_disable_clock; + } else if (IS_ROCKETLAKE(dev_priv)) { + encoder->enable_clock = rkl_ddi_enable_clock; + encoder->disable_clock = rkl_ddi_disable_clock; } else if (IS_DG1(dev_priv)) { encoder->enable_clock = dg1_ddi_enable_clock; encoder->disable_clock = dg1_ddi_disable_clock; From 87bd8498690b4adc916ef35dd3b4d72ec83e5fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:32 +0200 Subject: [PATCH 086/142] drm/i915: Use .disable_clock() for pll sanitation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of every new platform having yet another masive copy of the whole PLL sanitation code, let's just reuse the .disable_clock() hook for this purpose. We do need to plug this into the ICL+ DSI code for that, but fortunately it already has a suitable function we can use. We do lose the debug message though on account of not bothering to check if the clock is actually enabled or not before turning it off. We could introduce yet another vfunc to query the current state, but not sure it's worth the hassle? Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-14-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/icl_dsi.c | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 92 +----------------------- 2 files changed, 3 insertions(+), 90 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 7ef6b89c79d91..05d5709ae5378 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1942,6 +1942,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) encoder->pipe_mask = ~0; encoder->power_domain = POWER_DOMAIN_PORT_DSI; encoder->get_power_domains = gen11_dsi_get_power_domains; + encoder->disable_clock = gen11_dsi_gate_clocks; /* register DSI connector with DRM subsystem */ drm_connector_init(dev, connector, &gen11_dsi_connector_funcs, diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 685fc22d6ccbf..03747570fe0dc 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1582,23 +1582,6 @@ hsw_set_signal_levels(struct intel_dp *intel_dp, intel_de_posting_read(dev_priv, DDI_BUF_CTL(port)); } -static u32 icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, - enum phy phy) -{ - if (IS_ROCKETLAKE(dev_priv)) { - return RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); - } else if (intel_phy_is_combo(dev_priv, phy)) { - return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); - } else if (intel_phy_is_tc(dev_priv, phy)) { - enum tc_port tc_port = intel_port_to_tc(dev_priv, - (enum port)phy); - - return ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port); - } - - return 0; -} - static void _cnl_ddi_enable_clock(struct drm_i915_private *i915, i915_reg_t reg, u32 clk_sel_mask, u32 clk_sel, u32 clk_off) { @@ -1734,75 +1717,6 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } -static void dg1_sanitize_port_clk_off(struct drm_i915_private *dev_priv, - u32 port_mask, bool ddi_clk_needed) -{ - enum port port; - u32 val; - - for_each_port_masked(port, port_mask) { - enum phy phy = intel_port_to_phy(dev_priv, port); - bool ddi_clk_off; - - val = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)); - ddi_clk_off = val & DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); - - if (ddi_clk_needed == !ddi_clk_off) - continue; - - /* - * Punt on the case now where clock is gated, but it would - * be needed by the port. Something else is really broken then. - */ - if (drm_WARN_ON(&dev_priv->drm, ddi_clk_needed)) - continue; - - drm_notice(&dev_priv->drm, - "PHY %c is disabled with an ungated DDI clock, gate it\n", - phy_name(phy)); - val |= DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy); - intel_de_write(dev_priv, DG1_DPCLKA_CFGCR0(phy), val); - } -} - -static void icl_sanitize_port_clk_off(struct drm_i915_private *dev_priv, - u32 port_mask, bool ddi_clk_needed) -{ - enum port port; - bool ddi_clk_off; - u32 val; - i915_reg_t reg; - - for_each_port_masked(port, port_mask) { - enum phy phy = intel_port_to_phy(dev_priv, port); - - if (IS_ALDERLAKE_S(dev_priv)) - reg = ADLS_DPCLKA_CFGCR(phy); - else - reg = ICL_DPCLKA_CFGCR0; - - val = intel_de_read(dev_priv, reg); - ddi_clk_off = val & icl_dpclka_cfgcr0_clk_off(dev_priv, - phy); - - if (ddi_clk_needed == !ddi_clk_off) - continue; - - /* - * Punt on the case now where clock is gated, but it would - * be needed by the port. Something else is really broken then. - */ - if (drm_WARN_ON(&dev_priv->drm, ddi_clk_needed)) - continue; - - drm_notice(&dev_priv->drm, - "PHY %c is disabled/in DSI mode with an ungated DDI clock, gate it\n", - phy_name(phy)); - val |= icl_dpclka_cfgcr0_clk_off(dev_priv, phy); - intel_de_write(dev_priv, reg, val); - } -} - void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -1855,10 +1769,8 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) ddi_clk_needed = false; } - if (IS_DG1(dev_priv)) - dg1_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); - else - icl_sanitize_port_clk_off(dev_priv, port_mask, ddi_clk_needed); + if (!ddi_clk_needed && encoder->disable_clock) + encoder->disable_clock(encoder); } static void jsl_ddi_tc_enable_clock(struct intel_encoder *encoder, From dc1ddac65664524b15f013e6eb56365b957b23bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:33 +0200 Subject: [PATCH 087/142] drm/i915: Relocate icl_sanitize_encoder_pll_mapping() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move icl_sanitize_encoder_pll_mapping() out from the middle of the .{enable,disable}_clock() functions. Reviewed-by: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-15-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 112 +++++++++++------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 03747570fe0dc..f7ba5b6b8828f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1717,62 +1717,6 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } -void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - u32 port_mask; - bool ddi_clk_needed; - - /* - * In case of DP MST, we sanitize the primary encoder only, not the - * virtual ones. - */ - if (encoder->type == INTEL_OUTPUT_DP_MST) - return; - - if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) { - u8 pipe_mask; - bool is_mst; - - intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst); - /* - * In the unlikely case that BIOS enables DP in MST mode, just - * warn since our MST HW readout is incomplete. - */ - if (drm_WARN_ON(&dev_priv->drm, is_mst)) - return; - } - - port_mask = BIT(encoder->port); - ddi_clk_needed = encoder->base.crtc; - - if (encoder->type == INTEL_OUTPUT_DSI) { - struct intel_encoder *other_encoder; - - port_mask = intel_dsi_encoder_ports(encoder); - /* - * Sanity check that we haven't incorrectly registered another - * encoder using any of the ports of this DSI encoder. - */ - for_each_intel_encoder(&dev_priv->drm, other_encoder) { - if (other_encoder == encoder) - continue; - - if (drm_WARN_ON(&dev_priv->drm, - port_mask & BIT(other_encoder->port))) - return; - } - /* - * For DSI we keep the ddi clocks gated - * except during enable/disable sequence. - */ - ddi_clk_needed = false; - } - - if (!ddi_clk_needed && encoder->disable_clock) - encoder->disable_clock(encoder); -} - static void jsl_ddi_tc_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1933,6 +1877,62 @@ static void intel_ddi_disable_clock(struct intel_encoder *encoder) encoder->disable_clock(encoder); } +void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + u32 port_mask; + bool ddi_clk_needed; + + /* + * In case of DP MST, we sanitize the primary encoder only, not the + * virtual ones. + */ + if (encoder->type == INTEL_OUTPUT_DP_MST) + return; + + if (!encoder->base.crtc && intel_encoder_is_dp(encoder)) { + u8 pipe_mask; + bool is_mst; + + intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst); + /* + * In the unlikely case that BIOS enables DP in MST mode, just + * warn since our MST HW readout is incomplete. + */ + if (drm_WARN_ON(&dev_priv->drm, is_mst)) + return; + } + + port_mask = BIT(encoder->port); + ddi_clk_needed = encoder->base.crtc; + + if (encoder->type == INTEL_OUTPUT_DSI) { + struct intel_encoder *other_encoder; + + port_mask = intel_dsi_encoder_ports(encoder); + /* + * Sanity check that we haven't incorrectly registered another + * encoder using any of the ports of this DSI encoder. + */ + for_each_intel_encoder(&dev_priv->drm, other_encoder) { + if (other_encoder == encoder) + continue; + + if (drm_WARN_ON(&dev_priv->drm, + port_mask & BIT(other_encoder->port))) + return; + } + /* + * For DSI we keep the ddi clocks gated + * except during enable/disable sequence. + */ + ddi_clk_needed = false; + } + + if (!ddi_clk_needed && encoder->disable_clock) + encoder->disable_clock(encoder); +} + static void icl_program_mg_dp_mode(struct intel_digital_port *dig_port, const struct intel_crtc_state *crtc_state) From 97a24a701c13f608a57a0969fb99b029c24151b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 23:46:34 +0200 Subject: [PATCH 088/142] drm/i915: s/dev_priv/i915/ for the remainder of DDI clock routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the remaining 'dev_priv's to 'i915's in the DDI clock routing functions. Cc: Lucas De Marchi Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205214634.19341-16-ville.syrjala@linux.intel.com Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/i915/display/intel_ddi.c | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index f7ba5b6b8828f..eeae78097a20b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1661,23 +1661,23 @@ static void rkl_ddi_disable_clock(struct intel_encoder *encoder) static void dg1_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (drm_WARN_ON(&dev_priv->drm, !pll)) + if (drm_WARN_ON(&i915->drm, !pll)) return; /* * If we fail this, something went very wrong: first 2 PLLs should be * used by first 2 phys and last 2 PLLs by last phys */ - if (drm_WARN_ON(&dev_priv->drm, + if (drm_WARN_ON(&i915->drm, (pll->info->id < DPLL_ID_DG1_DPLL2 && phy >= PHY_C) || (pll->info->id >= DPLL_ID_DG1_DPLL2 && phy < PHY_C))) return; - _cnl_ddi_enable_clock(dev_priv, DG1_DPCLKA_CFGCR0(phy), + _cnl_ddi_enable_clock(i915, DG1_DPCLKA_CFGCR0(phy), DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), DG1_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy), DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); @@ -1685,24 +1685,24 @@ static void dg1_ddi_enable_clock(struct intel_encoder *encoder, static void dg1_ddi_disable_clock(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - _cnl_ddi_disable_clock(dev_priv, DG1_DPCLKA_CFGCR0(phy), + _cnl_ddi_disable_clock(i915, DG1_DPCLKA_CFGCR0(phy), DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_shared_dpll *pll = crtc_state->shared_dpll; - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + enum phy phy = intel_port_to_phy(i915, encoder->port); - if (drm_WARN_ON(&dev_priv->drm, !pll)) + if (drm_WARN_ON(&i915->drm, !pll)) return; - _cnl_ddi_enable_clock(dev_priv, ICL_DPCLKA_CFGCR0, + _cnl_ddi_enable_clock(i915, ICL_DPCLKA_CFGCR0, ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), ICL_DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, phy), ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); @@ -1710,10 +1710,10 @@ static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); - _cnl_ddi_disable_clock(dev_priv, ICL_DPCLKA_CFGCR0, + _cnl_ddi_disable_clock(i915, ICL_DPCLKA_CFGCR0, ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } @@ -1879,7 +1879,7 @@ static void intel_ddi_disable_clock(struct intel_encoder *encoder) void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 port_mask; bool ddi_clk_needed; @@ -1899,7 +1899,7 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) * In the unlikely case that BIOS enables DP in MST mode, just * warn since our MST HW readout is incomplete. */ - if (drm_WARN_ON(&dev_priv->drm, is_mst)) + if (drm_WARN_ON(&i915->drm, is_mst)) return; } @@ -1914,11 +1914,11 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) * Sanity check that we haven't incorrectly registered another * encoder using any of the ports of this DSI encoder. */ - for_each_intel_encoder(&dev_priv->drm, other_encoder) { + for_each_intel_encoder(&i915->drm, other_encoder) { if (other_encoder == encoder) continue; - if (drm_WARN_ON(&dev_priv->drm, + if (drm_WARN_ON(&i915->drm, port_mask & BIT(other_encoder->port))) return; } From b2423184ac3352a52fc7562fa0e7d23435fe67b9 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 16 Feb 2021 14:29:54 -0700 Subject: [PATCH 089/142] drm/i915: Enable -Wuninitialized -Wunintialized was disabled in commit c5627461490e ("drm/i915: Disable -Wuninitialized") because there were two warnings that were false positives. The first was due to DECLARE_WAIT_QUEUE_HEAD_ONSTACK, which was fixed in LLVM 9.0.0. The second was in busywait_stop, which was fixed in LLVM 10.0.0 (issue 415). The kernel's minimum version for LLVM is 10.0.1 so this warning can be safely enabled, where it has already caught a couple bugs. Link: https://github.com/ClangBuiltLinux/linux/issues/220 Link: https://github.com/ClangBuiltLinux/linux/issues/415 Link: https://github.com/ClangBuiltLinux/linux/issues/499 Link: https://github.com/llvm/llvm-project/commit/2e040398f8d691cc378c1abb098824ff49f3f28f Link: https://github.com/llvm/llvm-project/commit/c667cdc850c2aa821ffeedbc08c24bc985c59edd Fixes: c5627461490e ("drm/i915: Disable -Wuninitialized") References: 2ea4a7ba9bf6 ("drm/i915/gt: Avoid uninitialized use of rpcurupei in frequency_show") References: 2034c2129bc4 ("drm/i915/display: Ensure that ret is always initialized in icl_combo_phy_verify_state") Reported-by: Arnd Bergmann Signed-off-by: Nathan Chancellor Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20210216212953.24458-1-nathan@kernel.org --- drivers/gpu/drm/i915/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b4f0c0942fc92..8af63b2afd26a 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -21,7 +21,6 @@ subdir-ccflags-y += $(call cc-disable-warning, unused-but-set-variable) subdir-ccflags-y += $(call cc-disable-warning, sign-compare) subdir-ccflags-y += $(call cc-disable-warning, sometimes-uninitialized) subdir-ccflags-y += $(call cc-disable-warning, initializer-overrides) -subdir-ccflags-y += $(call cc-disable-warning, uninitialized) subdir-ccflags-y += $(call cc-disable-warning, frame-address) subdir-ccflags-$(CONFIG_DRM_I915_WERROR) += -Werror From 44bd8e1cdc7c1c388b378b2a8ba434bba491afe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Fri, 12 Feb 2021 10:22:00 -0800 Subject: [PATCH 090/142] drm/i915: Remove dead code from skl_pipe_wm_get_hw_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is nothing else to be executed after this if block. Signed-off-by: José Roberto de Souza Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210212182201.155043-2-jose.souza@intel.com --- drivers/gpu/drm/i915/intel_pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8c42fa51c0f6d..8cc67f9c4e586 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6182,9 +6182,6 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, skl_wm_level_from_reg_val(val, &wm->trans_wm); } - - if (!crtc->active) - return; } void skl_wm_get_hw_state(struct drm_i915_private *dev_priv) From 7e07c68f06a248441b485249de4c4115cba262cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Feb 2021 22:23:22 +0200 Subject: [PATCH 091/142] drm/i915: Nuke INTEL_OUTPUT_FORMAT_INVALID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We tend to use output_format!=RGB as a shorthand for YCbCr, but this fails if we have a disabled crtc where output_format==INVALID. We're now getting some fail from intel_color_check() when we have: hw.enable==false hw.ctm!=NULL output_format==INVALID Let's avoid that by throwing INTEL_OUTPUT_FORMAT_INVALID to the dumpster, and thus everything defaults to RGB when the crtc is disabled. This does beg the deeper question of how much of the state should we in fact be validating when hw/uapi.enable==false. And should we even be doing the uapi->hw copy when uapi.enable==false? So far I've not been able to come up with satisfactory answers for myself, so I'm putting it off for the moment. Cc: Lee Shawn C Fixes: 0aa5c3835c8a ("drm/i915: support two CSC module on gen11 and later") Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/2964 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210205202322.27608-1-ville.syrjala@linux.intel.com Reviewed-by: José Roberto de Souza --- drivers/gpu/drm/i915/display/intel_crtc.c | 1 - drivers/gpu/drm/i915/display/intel_display.c | 3 +-- drivers/gpu/drm/i915/display/intel_display_types.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 8bfa8fc2efdbb..88b44ac50aae1 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -116,7 +116,6 @@ void intel_crtc_state_reset(struct intel_crtc_state *crtc_state, crtc_state->cpu_transcoder = INVALID_TRANSCODER; crtc_state->master_transcoder = INVALID_TRANSCODER; crtc_state->hsw_workaround_pipe = INVALID_PIPE; - crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID; crtc_state->scaler_state.scaler_id = -1; crtc_state->mst_master_transcoder = INVALID_TRANSCODER; } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0b5bc18c4076e..8c5e752652260 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -8179,7 +8179,6 @@ static void snprintf_output_types(char *buf, size_t len, } static const char * const output_format_str[] = { - [INTEL_OUTPUT_FORMAT_INVALID] = "Invalid", [INTEL_OUTPUT_FORMAT_RGB] = "RGB", [INTEL_OUTPUT_FORMAT_YCBCR420] = "YCBCR4:2:0", [INTEL_OUTPUT_FORMAT_YCBCR444] = "YCBCR4:4:4", @@ -8188,7 +8187,7 @@ static const char * const output_format_str[] = { static const char *output_formats(enum intel_output_format format) { if (format >= ARRAY_SIZE(output_format_str)) - format = INTEL_OUTPUT_FORMAT_INVALID; + return "invalid"; return output_format_str[format]; } diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 07b7f5eae5877..f3acc5a3c8145 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -837,7 +837,6 @@ struct intel_crtc_wm_state { }; enum intel_output_format { - INTEL_OUTPUT_FORMAT_INVALID, INTEL_OUTPUT_FORMAT_RGB, INTEL_OUTPUT_FORMAT_YCBCR420, INTEL_OUTPUT_FORMAT_YCBCR444, From 1835bf459df752d13f9fbae37a521a471172d3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 17 Feb 2021 18:20:50 +0200 Subject: [PATCH 092/142] drm/i915: Wait for scanout to stop when sanitizing planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we sanitize planes let's wait for the scanout to stop before we let the subsequent code tear down the ggtt mappings and whatnot. Cures an underrun on my ivb when I boot with VT-d enabled and the BIOS fb gets thrown out due to stolen being considered unusable with VT-d active. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210217162050.13803-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson --- drivers/gpu/drm/i915/display/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8c5e752652260..e1060076ac83f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2406,6 +2406,7 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); intel_disable_plane(plane, crtc_state); + intel_wait_for_vblank(dev_priv, crtc->pipe); } static void From b60e320bf35971e67b6afabd5614c6196b3be95d Mon Sep 17 00:00:00 2001 From: Lee Shawn C Date: Thu, 18 Feb 2021 13:23:33 +0800 Subject: [PATCH 093/142] drm/i915/vbt: update DP max link rate table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Bspec #20124, max link rate table for DP was updated at BDB version 230. Max link rate can support upto UHBR. After migrate to BDB v230, the definition for LBR, HBR2 and HBR3 were changed. For backward compatibility. If BDB version was from 216 to 229. Driver have to follow original rule to configure DP max link rate value from VBT. v2: split the mapping table to two for old and new BDB definition. v3: return link rate instead of assigning it. v4: remove the useless variable. Cc: Ville Syrjala Cc: Imre Deak Cc: Jani Nikula Cc: Cooper Chiou Cc: William Tseng Signed-off-by: Lee Shawn C [vsyrjala: Try to retain the comment that VBT version 216 added some of this] Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210218052333.16109-1-shawn.c.lee@intel.com --- drivers/gpu/drm/i915/display/intel_bios.c | 58 ++++++++++++++----- drivers/gpu/drm/i915/display/intel_vbt_defs.h | 23 ++++++-- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 7902d4c2673ec..f3fa1441ce166 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1759,6 +1759,44 @@ static enum port dvo_port_to_port(struct drm_i915_private *dev_priv, dvo_port); } +static int parse_bdb_230_dp_max_link_rate(const int vbt_max_link_rate) +{ + switch (vbt_max_link_rate) { + default: + case BDB_230_VBT_DP_MAX_LINK_RATE_DEF: + return 0; + case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR20: + return 2000000; + case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR13P5: + return 1350000; + case BDB_230_VBT_DP_MAX_LINK_RATE_UHBR10: + return 1000000; + case BDB_230_VBT_DP_MAX_LINK_RATE_HBR3: + return 810000; + case BDB_230_VBT_DP_MAX_LINK_RATE_HBR2: + return 540000; + case BDB_230_VBT_DP_MAX_LINK_RATE_HBR: + return 270000; + case BDB_230_VBT_DP_MAX_LINK_RATE_LBR: + return 162000; + } +} + +static int parse_bdb_216_dp_max_link_rate(const int vbt_max_link_rate) +{ + switch (vbt_max_link_rate) { + default: + case BDB_216_VBT_DP_MAX_LINK_RATE_HBR3: + return 810000; + case BDB_216_VBT_DP_MAX_LINK_RATE_HBR2: + return 540000; + case BDB_216_VBT_DP_MAX_LINK_RATE_HBR: + return 270000; + case BDB_216_VBT_DP_MAX_LINK_RATE_LBR: + return 162000; + } +} + static void parse_ddi_port(struct drm_i915_private *dev_priv, struct display_device_data *devdata, u8 bdb_version) @@ -1884,21 +1922,11 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, /* DP max link rate for CNL+ */ if (bdb_version >= 216) { - switch (child->dp_max_link_rate) { - default: - case VBT_DP_MAX_LINK_RATE_HBR3: - info->dp_max_link_rate = 810000; - break; - case VBT_DP_MAX_LINK_RATE_HBR2: - info->dp_max_link_rate = 540000; - break; - case VBT_DP_MAX_LINK_RATE_HBR: - info->dp_max_link_rate = 270000; - break; - case VBT_DP_MAX_LINK_RATE_LBR: - info->dp_max_link_rate = 162000; - break; - } + if (bdb_version >= 230) + info->dp_max_link_rate = parse_bdb_230_dp_max_link_rate(child->dp_max_link_rate); + else + info->dp_max_link_rate = parse_bdb_216_dp_max_link_rate(child->dp_max_link_rate); + drm_dbg_kms(&dev_priv->drm, "Port %c VBT DP max link rate: %d\n", port_name(port), info->dp_max_link_rate); diff --git a/drivers/gpu/drm/i915/display/intel_vbt_defs.h b/drivers/gpu/drm/i915/display/intel_vbt_defs.h index 6d10fa0377514..dbe24d7e73759 100644 --- a/drivers/gpu/drm/i915/display/intel_vbt_defs.h +++ b/drivers/gpu/drm/i915/display/intel_vbt_defs.h @@ -343,10 +343,21 @@ enum vbt_gmbus_ddi { #define DP_AUX_H 0x80 #define DP_AUX_I 0x90 -#define VBT_DP_MAX_LINK_RATE_HBR3 0 -#define VBT_DP_MAX_LINK_RATE_HBR2 1 -#define VBT_DP_MAX_LINK_RATE_HBR 2 -#define VBT_DP_MAX_LINK_RATE_LBR 3 +/* DP max link rate 216+ */ +#define BDB_216_VBT_DP_MAX_LINK_RATE_HBR3 0 +#define BDB_216_VBT_DP_MAX_LINK_RATE_HBR2 1 +#define BDB_216_VBT_DP_MAX_LINK_RATE_HBR 2 +#define BDB_216_VBT_DP_MAX_LINK_RATE_LBR 3 + +/* DP max link rate 230+ */ +#define BDB_230_VBT_DP_MAX_LINK_RATE_DEF 0 +#define BDB_230_VBT_DP_MAX_LINK_RATE_LBR 1 +#define BDB_230_VBT_DP_MAX_LINK_RATE_HBR 2 +#define BDB_230_VBT_DP_MAX_LINK_RATE_HBR2 3 +#define BDB_230_VBT_DP_MAX_LINK_RATE_HBR3 4 +#define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR10 5 +#define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR13P5 6 +#define BDB_230_VBT_DP_MAX_LINK_RATE_UHBR20 7 /* * The child device config, aka the display device data structure, provides a @@ -445,8 +456,8 @@ struct child_device_config { u16 dp_gpio_pin_num; /* 195 */ u8 dp_iboost_level:4; /* 196 */ u8 hdmi_iboost_level:4; /* 196 */ - u8 dp_max_link_rate:2; /* 216 CNL+ */ - u8 dp_max_link_rate_reserved:6; /* 216 */ + u8 dp_max_link_rate:3; /* 216/230 CNL+ */ + u8 dp_max_link_rate_reserved:5; /* 216/230 */ } __packed; struct bdb_general_definitions { From ffe9aa48d9fc636a8b6d05538d6fb281c1954c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 12:50:36 -0800 Subject: [PATCH 094/142] drm/i915/display: Allow PSR2 selective fetch to be enabled at run-time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now CI is blacklisting module reload, so we need to be able to enable PSR2 selective fetch in run time to test this feature before enable it by default. Changes in IGT will also be needed. v2: - Fixed handling of I915_PSR_DEBUG_ENABLE_SEL_FETCH in intel_psr_debug_set() Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210209205036.351076-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/display/intel_psr.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f3acc5a3c8145..29663db5afcd8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1430,6 +1430,7 @@ struct intel_psr { #define I915_PSR_DEBUG_DISABLE 0x01 #define I915_PSR_DEBUG_ENABLE 0x02 #define I915_PSR_DEBUG_FORCE_PSR1 0x03 +#define I915_PSR_DEBUG_ENABLE_SEL_FETCH 0x4 #define I915_PSR_DEBUG_IRQ 0x10 u32 debug; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index bf214d0e2dec0..43e9e362382b0 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -684,7 +684,8 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, struct intel_plane *plane; int i; - if (!dev_priv->params.enable_psr2_sel_fetch) { + if (!dev_priv->params.enable_psr2_sel_fetch && + intel_dp->psr.debug != I915_PSR_DEBUG_ENABLE_SEL_FETCH) { drm_dbg_kms(&dev_priv->drm, "PSR2 sel fetch not enabled, disabled by parameter\n"); return false; @@ -1448,7 +1449,8 @@ void intel_psr_update(struct intel_dp *intel_dp, enable = crtc_state->has_psr; psr2_enable = crtc_state->has_psr2; - if (enable == psr->enabled && psr2_enable == psr->psr2_enabled) { + if (enable == psr->enabled && psr2_enable == psr->psr2_enabled && + crtc_state->enable_psr2_sel_fetch == psr->psr2_sel_fetch_enabled) { /* Force a PSR exit when enabling CRC to avoid CRC timeouts */ if (crtc_state->crc_enabled && psr->enabled) psr_force_hw_tracking_exit(intel_dp); @@ -1637,7 +1639,7 @@ int intel_psr_debug_set(struct intel_dp *intel_dp, u64 val) int ret; if (val & ~(I915_PSR_DEBUG_IRQ | I915_PSR_DEBUG_MODE_MASK) || - mode > I915_PSR_DEBUG_FORCE_PSR1) { + mode > I915_PSR_DEBUG_ENABLE_SEL_FETCH) { drm_dbg_kms(&dev_priv->drm, "Invalid debug mask %llx\n", val); return -EINVAL; } From a22af61d438e0de3196af21d0387499d999a1698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 10:14:36 -0800 Subject: [PATCH 095/142] drm/i915/display: Rename for_each_intel_encoder.*_can_psr to for_each_intel_encoder.*_with_psr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for_each_intel_encoder.*_"can_psr" sounds strange, in my opinion "with_psr" is better. Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210209181439.215104-1-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_display.h | 4 ++-- drivers/gpu/drm/i915/display/intel_display_debugfs.c | 6 +++--- drivers/gpu/drm/i915/display/intel_psr.c | 12 ++++++------ drivers/gpu/drm/i915/i915_irq.c | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 375ec2bccebd6..0e4c1481fa009 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -418,7 +418,7 @@ enum phy_fia { for_each_if((encoder_mask) & \ drm_encoder_mask(&intel_encoder->base)) -#define for_each_intel_encoder_mask_can_psr(dev, intel_encoder, encoder_mask) \ +#define for_each_intel_encoder_mask_with_psr(dev, intel_encoder, encoder_mask) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ for_each_if(((encoder_mask) & drm_encoder_mask(&(intel_encoder)->base)) && \ intel_encoder_can_psr(intel_encoder)) @@ -427,7 +427,7 @@ enum phy_fia { for_each_intel_encoder(dev, intel_encoder) \ for_each_if(intel_encoder_is_dp(intel_encoder)) -#define for_each_intel_encoder_can_psr(dev, intel_encoder) \ +#define for_each_intel_encoder_with_psr(dev, intel_encoder) \ for_each_intel_encoder((dev), (intel_encoder)) \ for_each_if(intel_encoder_can_psr(intel_encoder)) diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 8af663b84314b..449470ef9f659 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -437,7 +437,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) return -ENODEV; /* Find the first EDP which supports PSR */ - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { intel_dp = enc_to_intel_dp(encoder); break; } @@ -459,7 +459,7 @@ i915_edp_psr_debug_set(void *data, u64 val) if (!HAS_PSR(dev_priv)) return ret; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); drm_dbg_kms(&dev_priv->drm, "Setting PSR debug to %llx\n", val); @@ -484,7 +484,7 @@ i915_edp_psr_debug_get(void *data, u64 *val) if (!HAS_PSR(dev_priv)) return -ENODEV; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); // TODO: split to each transcoder's PSR debug state diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 43e9e362382b0..848be0228106c 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1233,8 +1233,8 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st !crtc_state->enable_psr2_sel_fetch) return; - for_each_intel_encoder_mask_can_psr(&dev_priv->drm, encoder, - crtc_state->uapi.encoder_mask) { + for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder, + crtc_state->uapi.encoder_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (!intel_dp->psr.enabled) @@ -1517,8 +1517,8 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) if (!new_crtc_state->has_psr) return; - for_each_intel_encoder_mask_can_psr(&dev_priv->drm, encoder, - new_crtc_state->uapi.encoder_mask) { + for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder, + new_crtc_state->uapi.encoder_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u32 psr_status; @@ -1732,7 +1732,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, if (origin == ORIGIN_FLIP) return; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { unsigned int pipe_frontbuffer_bits = frontbuffer_bits; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1804,7 +1804,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, { struct intel_encoder *encoder; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { unsigned int pipe_frontbuffer_bits = frontbuffer_bits; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 374a65d053914..013794004da4c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2096,7 +2096,7 @@ static void ivb_display_irq_handler(struct drm_i915_private *dev_priv, if (de_iir & DE_EDP_PSR_INT_HSW) { struct intel_encoder *encoder; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); u32 psr_iir = intel_uncore_read(&dev_priv->uncore, @@ -2323,7 +2323,7 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) u32 psr_iir; i915_reg_t iir_reg; - for_each_intel_encoder_can_psr(&dev_priv->drm, encoder) { + for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (INTEL_GEN(dev_priv) >= 12) From 774ab4ff15c020f5b38b45958ee22193d06a17d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 10:14:37 -0800 Subject: [PATCH 096/142] drm/i915/display: Only write to register in intel_psr2_program_trans_man_trk_ctl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no support for two pipes one transcoder for PSR and if we had that the current code should not use cpu_transcoder. Also I can't see a scenario where crtc_state->enable_psr2_sel_fetch is set and PSR is not enabled and if by a bug it happens PSR HW will just ignore any value in set in PSR2_MAN_TRK_CTL. So dropping all the rest and keeping the same behavior that we have with intel_psr2_program_plane_sel_fetch(). Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210209181439.215104-2-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 848be0228106c..7ce4feaf18a17 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1227,23 +1227,13 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - struct intel_encoder *encoder; if (!HAS_PSR2_SEL_FETCH(dev_priv) || !crtc_state->enable_psr2_sel_fetch) return; - for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder, - crtc_state->uapi.encoder_mask) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - if (!intel_dp->psr.enabled) - continue; - - intel_de_write(dev_priv, - PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), - crtc_state->psr2_man_track_ctl); - } + intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), + crtc_state->psr2_man_track_ctl); } static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state, From 3816139c8a4fe5e1fb901b51e94b98822a6e4108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 10:14:38 -0800 Subject: [PATCH 097/142] drm/i915/display: Remove some redundancy around CAN_PSR() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If source_support is set the platform supports PSR so no need to check it again at every CAN_PSR(). Also removing the intel_dp_is_edp() calls, if sink_support is set the sink connected is for sure a eDP panel. Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210209181439.215104-3-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_display_types.h | 5 ++--- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 29663db5afcd8..900e07bb54cac 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1799,9 +1799,8 @@ dp_to_i915(struct intel_dp *intel_dp) return to_i915(dp_to_dig_port(intel_dp)->base.base.dev); } -#define CAN_PSR(intel_dp) (HAS_PSR(dp_to_i915(intel_dp)) && \ - (intel_dp)->psr.sink_support && \ - (intel_dp)->psr.source_support) +#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ + (intel_dp)->psr.source_support) static inline bool intel_encoder_can_psr(struct intel_encoder *encoder) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 4f89e0de5dde3..0a0cc61344c41 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2358,7 +2358,7 @@ bool intel_dp_initial_fastset_check(struct intel_encoder *encoder, return false; } - if (CAN_PSR(intel_dp) && intel_dp_is_edp(intel_dp)) { + if (CAN_PSR(intel_dp)) { drm_dbg_kms(&i915->drm, "Forcing full modeset to compute PSR state\n"); crtc_state->uapi.mode_changed = true; return false; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 7ce4feaf18a17..581d2e83bbee3 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1964,7 +1964,7 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | DP_PSR_LINK_CRC_ERROR; - if (!CAN_PSR(intel_dp) || !intel_dp_is_edp(intel_dp)) + if (!CAN_PSR(intel_dp)) return; mutex_lock(&psr->lock); @@ -2014,7 +2014,7 @@ bool intel_psr_enabled(struct intel_dp *intel_dp) { bool ret; - if (!CAN_PSR(intel_dp) || !intel_dp_is_edp(intel_dp)) + if (!CAN_PSR(intel_dp)) return false; mutex_lock(&intel_dp->psr.lock); From 1b6872fe1efc5d8d78f5a3a54830e05b557ab3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Tue, 9 Feb 2021 10:14:39 -0800 Subject: [PATCH 098/142] drm/i915/display: Set source_support even if panel do not support PSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will set the right value of source_support when the port encoder/port supports PSR but sink don't. This change will also be needed in future for panel replay as psr struct needs to be initialized even if disconnected or current sink don't support PSR. Cc: Gwan-gyeong Mun Signed-off-by: José Roberto de Souza Reviewed-by: Gwan-gyeong Mun Link: https://patchwork.freedesktop.org/patch/msgid/20210209181439.215104-4-jose.souza@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 581d2e83bbee3..7c6e561f86c16 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -1839,9 +1839,6 @@ void intel_psr_init(struct intel_dp *intel_dp) if (!HAS_PSR(dev_priv)) return; - if (!intel_dp->psr.sink_support) - return; - /* * HSW spec explicitly says PSR is tied to port A. * BDW+ platforms have a instance of PSR registers per transcoder but From c093056b67a3dd45cf6fc2f2b7902053338891f1 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 11 Feb 2021 16:52:11 +0200 Subject: [PATCH 099/142] drm/dp: add MSO related DPCD registers Add DPCD register definitions for eDP 1.4 Multi-SST Operation. Cc: Nischal Varide Cc: dri-devel@lists.freedesktop.org Reviewed-by: Uma Shankar Acked-by: Daniel Vetter Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/ab57627f373ec4a80494bb51ea51080810d9bfb0.1613054234.git.jani.nikula@intel.com --- include/drm/drm_dp_helper.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index edffd1dcca3ed..632ad7faa006e 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1016,6 +1016,11 @@ struct drm_device; #define DP_EDP_REGIONAL_BACKLIGHT_BASE 0x740 /* eDP 1.4 */ #define DP_EDP_REGIONAL_BACKLIGHT_0 0x741 /* eDP 1.4 */ +#define DP_EDP_MSO_LINK_CAPABILITIES 0x7a4 /* eDP 1.4 */ +# define DP_EDP_MSO_NUMBER_OF_LINKS_MASK (7 << 0) +# define DP_EDP_MSO_NUMBER_OF_LINKS_SHIFT 0 +# define DP_EDP_MSO_INDEPENDENT_LINK_BIT (1 << 3) + /* Sideband MSG Buffers */ #define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000 /* 1.2 MST */ #define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200 /* 1.2 MST */ From 8733932a72d73e2ae31e38ca995fb538aa2149e3 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 11 Feb 2021 16:52:12 +0200 Subject: [PATCH 100/142] drm/i915/edp: reject modes with dimensions other than fixed mode Be more strict about filtering modes for eDP. Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/feb4c3b2b9c4da56a840bdb3c0e7fd0e58ee50de.1613054234.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0a0cc61344c41..79f3f0ad907f3 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -789,10 +789,10 @@ intel_dp_mode_valid(struct drm_connector *connector, return MODE_H_ILLEGAL; if (intel_dp_is_edp(intel_dp) && fixed_mode) { - if (mode->hdisplay > fixed_mode->hdisplay) + if (mode->hdisplay != fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > fixed_mode->vdisplay) + if (mode->vdisplay != fixed_mode->vdisplay) return MODE_PANEL; target_clock = fixed_mode->clock; From f886261735fca91e3bdec0e56c86a5e71e4eea67 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 11 Feb 2021 16:52:13 +0200 Subject: [PATCH 101/142] drm/i915/edp: always add fixed mode to probed modes in ->get_modes() Unconditionally add fixed mode to probed modes even if EDID is present and has modes. Prepare for cases where the fixed mode is not present in EDID (such as eDP MSO). Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/6979f123f3e4ed948333f1b181202bbced3c3e85.1613054234.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 79f3f0ad907f3..b080982374277 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5547,19 +5547,18 @@ static int intel_dp_get_modes(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); struct edid *edid; + int num_modes = 0; edid = intel_connector->detect_edid; if (edid) { - int ret = intel_connector_update_modes(connector, edid); + num_modes = intel_connector_update_modes(connector, edid); if (intel_vrr_is_capable(connector)) drm_connector_set_vrr_capable_property(connector, true); - if (ret) - return ret; } - /* if eDP has no EDID, fall back to fixed mode */ + /* Also add fixed mode, which may or may not be present in EDID */ if (intel_dp_is_edp(intel_attached_dp(intel_connector)) && intel_connector->panel.fixed_mode) { struct drm_display_mode *mode; @@ -5568,10 +5567,13 @@ static int intel_dp_get_modes(struct drm_connector *connector) intel_connector->panel.fixed_mode); if (mode) { drm_mode_probed_add(connector, mode); - return 1; + num_modes++; } } + if (num_modes) + return num_modes; + if (!edid) { struct intel_dp *intel_dp = intel_attached_dp(intel_connector); struct drm_display_mode *mode; @@ -5581,11 +5583,11 @@ static int intel_dp_get_modes(struct drm_connector *connector) intel_dp->downstream_ports); if (mode) { drm_mode_probed_add(connector, mode); - return 1; + num_modes++; } } - return 0; + return num_modes; } static int From de46dbe4b755c24e11655f69abb008a9573c9cba Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 11 Feb 2021 16:52:14 +0200 Subject: [PATCH 102/142] drm/i915/edp: read sink MSO configuration for eDP 1.4+ Read and debug log the eDP sink MSO configuration. Do not actually do anything with the information yet besides logging. FIXME: The pixel overlap is present in DisplayID 2.0, but we don't have parsing for that. Assume zero for now. We could also add quirks for non-zero pixel overlap before DisplayID 2.0 parsing. v3: Add placeholder for pixel overlap. v2: Rename intel_dp_mso_init -> intel_edp_mso_init Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/24ef61574e5af12cd86d5b85afbfbd4ac2f9de25.1613054234.git.jani.nikula@intel.com --- .../drm/i915/display/intel_display_types.h | 2 ++ drivers/gpu/drm/i915/display/intel_dp.c | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 900e07bb54cac..1a76e1d9de7ad 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1493,6 +1493,8 @@ struct intel_dp { int max_link_lane_count; /* Max rate for the current link */ int max_link_rate; + int mso_link_count; + int mso_pixel_overlap; /* sink or branch descriptor */ struct drm_dp_desc desc; struct drm_dp_aux aux; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index b080982374277..2ec82a5c9f24b 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3516,6 +3516,37 @@ static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp) } } +static void intel_edp_mso_init(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u8 mso; + + if (intel_dp->edp_dpcd[0] < DP_EDP_14) + return; + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_EDP_MSO_LINK_CAPABILITIES, &mso) != 1) { + drm_err(&i915->drm, "Failed to read MSO cap\n"); + return; + } + + /* Valid configurations are SST or MSO 2x1, 2x2, 4x1 */ + mso &= DP_EDP_MSO_NUMBER_OF_LINKS_MASK; + if (mso % 2 || mso > drm_dp_max_lane_count(intel_dp->dpcd)) { + drm_err(&i915->drm, "Invalid MSO link count cap %u\n", mso); + mso = 0; + } + + if (mso) { + drm_dbg_kms(&i915->drm, "Sink MSO %ux%u configuration\n", + mso, drm_dp_max_lane_count(intel_dp->dpcd) / mso); + drm_err(&i915->drm, "No source MSO support, disabling\n"); + mso = 0; + } + + intel_dp->mso_link_count = mso; + intel_dp->mso_pixel_overlap = 0; /* FIXME: read from DisplayID v2.0 */ +} + static bool intel_edp_init_dpcd(struct intel_dp *intel_dp) { @@ -3599,6 +3630,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp) */ intel_edp_init_source_oui(intel_dp, true); + intel_edp_mso_init(intel_dp); + return true; } From 63e654f65d7cf588813c5b75beafe2d3114719b0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 11 Feb 2021 16:52:15 +0200 Subject: [PATCH 103/142] drm/i915/reg: add stream splitter configuration definitions The splitter configuration is required for eDP MSO. Bspec: 50174 Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/443ad1fbf908800ee4e09315cb6a7ba26c64d136.1613054234.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4977bede07114..ca549d77657bb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -11447,6 +11447,9 @@ enum skl_power_gate { #define BIG_JOINER_ENABLE (1 << 29) #define MASTER_BIG_JOINER_ENABLE (1 << 28) #define VGA_CENTERING_ENABLE (1 << 27) +#define SPLITTER_CONFIGURATION_MASK REG_GENMASK(26, 25) +#define SPLITTER_CONFIGURATION_2_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 0) +#define SPLITTER_CONFIGURATION_4_SEGMENT REG_FIELD_PREP(SPLITTER_CONFIGURATION_MASK, 1) #define _ICL_PIPE_DSS_CTL2_PB 0x78204 #define _ICL_PIPE_DSS_CTL2_PC 0x78404 From 62c211bb9e1bee0083d8061ce0012f538ac754c3 Mon Sep 17 00:00:00 2001 From: Gwan-gyeong Mun Date: Mon, 22 Feb 2021 23:30:06 +0200 Subject: [PATCH 104/142] drm/i915/display: Do not allow DC3CO if PSR SF is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though GEN12+ HW supports PSR + DC3CO, DMC's HW DC3CO exit mechanism has an issue with using of Selective Fecth and PSR2 manual tracking. And as some GEN12+ platforms (RKL, ADL-S) don't support PSR2 HW tracking, Selective Fetch will be enabled by default on that platforms. Therefore if the system enables PSR Selective Fetch / PSR manual tracking, it does not allow DC3CO dc state, in that case. When this DC3CO exit issue is addressed while PSR Selective Fetch is enabled, this restriction should be removed. v2: Address Jose's review comment. - Fix typo - Move check routine of DC3CO ability to tgl_dc3co_exitline_compute_config() v3: Change the check routine of enablement of psr2 sel fetch. (Jose) Cc: José Roberto de Souza Cc: Anshuman Gupta Signed-off-by: Gwan-gyeong Mun Reviewed-by: José Roberto de Souza Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210222213006.1609085-1-gwan-gyeong.mun@intel.com --- drivers/gpu/drm/i915/display/intel_psr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 7c6e561f86c16..cd434285e3b74 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -654,6 +654,13 @@ tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 exit_scanlines; + /* + * DMC's DC3CO exit mechanism has an issue with Selective Fecth + * TODO: when the issue is addressed, this restriction should be removed. + */ + if (crtc_state->enable_psr2_sel_fetch) + return; + if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC3CO)) return; From c73927183f2b85bf1a06d75d2b51be72aff42358 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Feb 2021 23:04:00 +0200 Subject: [PATCH 105/142] drm/i915/tgl+: Sanitize the DDI LANES/IO and AUX power domain names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Bspec the TGL TypeC ports are TC1-6, the AUX power well request flags are USBC1-6/TBT1-6, so for clarity use these names in the port power domain names instead of the D-I terminology (which Bspec uses only for the ICL TypeC ports). A domain name should follow the _ format. Add the new aliases based on this, leaving a change to rename all the rest accordingly for a follow-up. No functional change. v2: Add comment to commit log about unifying domain names. (Jose) Cc: Souza Jose Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20210222210400.940158-1-imre.deak@intel.com --- .../drm/i915/display/intel_display_power.c | 212 ++++++++---------- .../drm/i915/display/intel_display_power.h | 32 +++ 2 files changed, 130 insertions(+), 114 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index f00c1750febd3..7e0eaa8723505 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -2886,24 +2886,24 @@ intel_display_power_put_mask_in_set(struct drm_i915_private *i915, BIT_ULL(POWER_DOMAIN_PIPE_B) | \ BIT_ULL(POWER_DOMAIN_TRANSCODER_B) | \ BIT_ULL(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_E_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_G_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_H_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_I_LANES) | \ - BIT_ULL(POWER_DOMAIN_AUX_D) | \ - BIT_ULL(POWER_DOMAIN_AUX_E) | \ - BIT_ULL(POWER_DOMAIN_AUX_F) | \ - BIT_ULL(POWER_DOMAIN_AUX_G) | \ - BIT_ULL(POWER_DOMAIN_AUX_H) | \ - BIT_ULL(POWER_DOMAIN_AUX_I) | \ - BIT_ULL(POWER_DOMAIN_AUX_D_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_E_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_F_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_G_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_H_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_I_TBT) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC1) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC2) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC3) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC4) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC5) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC6) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC1) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC2) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC3) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC4) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC5) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC6) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT1) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT2) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT3) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT4) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT5) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT6) | \ BIT_ULL(POWER_DOMAIN_VGA) | \ BIT_ULL(POWER_DOMAIN_AUDIO) | \ BIT_ULL(POWER_DOMAIN_INIT)) @@ -2921,18 +2921,12 @@ intel_display_power_put_mask_in_set(struct drm_i915_private *i915, BIT_ULL(POWER_DOMAIN_AUX_C) | \ BIT_ULL(POWER_DOMAIN_INIT)) -#define TGL_DDI_IO_D_TC1_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_D_IO)) -#define TGL_DDI_IO_E_TC2_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_E_IO)) -#define TGL_DDI_IO_F_TC3_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO)) -#define TGL_DDI_IO_G_TC4_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_G_IO)) -#define TGL_DDI_IO_H_TC5_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_H_IO)) -#define TGL_DDI_IO_I_TC6_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_I_IO)) +#define TGL_DDI_IO_TC1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC1) +#define TGL_DDI_IO_TC2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC2) +#define TGL_DDI_IO_TC3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC3) +#define TGL_DDI_IO_TC4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC4) +#define TGL_DDI_IO_TC5_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC5) +#define TGL_DDI_IO_TC6_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_PORT_DDI_IO_TC6) #define TGL_AUX_A_IO_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_IO_A) | \ @@ -2941,44 +2935,34 @@ intel_display_power_put_mask_in_set(struct drm_i915_private *i915, BIT_ULL(POWER_DOMAIN_AUX_B)) #define TGL_AUX_C_IO_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_C)) -#define TGL_AUX_D_TC1_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_D)) -#define TGL_AUX_E_TC2_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_E)) -#define TGL_AUX_F_TC3_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_F)) -#define TGL_AUX_G_TC4_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_G)) -#define TGL_AUX_H_TC5_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_H)) -#define TGL_AUX_I_TC6_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_I)) -#define TGL_AUX_D_TBT1_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_D_TBT)) -#define TGL_AUX_E_TBT2_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_E_TBT)) -#define TGL_AUX_F_TBT3_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_F_TBT)) -#define TGL_AUX_G_TBT4_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_G_TBT)) -#define TGL_AUX_H_TBT5_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_H_TBT)) -#define TGL_AUX_I_TBT6_IO_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_I_TBT)) + +#define TGL_AUX_IO_USBC1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC1) +#define TGL_AUX_IO_USBC2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC2) +#define TGL_AUX_IO_USBC3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC3) +#define TGL_AUX_IO_USBC4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC4) +#define TGL_AUX_IO_USBC5_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC5) +#define TGL_AUX_IO_USBC6_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_USBC6) + +#define TGL_AUX_IO_TBT1_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT1) +#define TGL_AUX_IO_TBT2_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT2) +#define TGL_AUX_IO_TBT3_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT3) +#define TGL_AUX_IO_TBT4_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT4) +#define TGL_AUX_IO_TBT5_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT5) +#define TGL_AUX_IO_TBT6_POWER_DOMAINS BIT_ULL(POWER_DOMAIN_AUX_TBT6) #define TGL_TC_COLD_OFF_POWER_DOMAINS ( \ - BIT_ULL(POWER_DOMAIN_AUX_D) | \ - BIT_ULL(POWER_DOMAIN_AUX_E) | \ - BIT_ULL(POWER_DOMAIN_AUX_F) | \ - BIT_ULL(POWER_DOMAIN_AUX_G) | \ - BIT_ULL(POWER_DOMAIN_AUX_H) | \ - BIT_ULL(POWER_DOMAIN_AUX_I) | \ - BIT_ULL(POWER_DOMAIN_AUX_D_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_E_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_F_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_G_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_H_TBT) | \ - BIT_ULL(POWER_DOMAIN_AUX_I_TBT) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC1) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC2) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC3) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC4) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC5) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC6) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT1) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT2) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT3) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT4) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT5) | \ + BIT_ULL(POWER_DOMAIN_AUX_TBT6) | \ BIT_ULL(POWER_DOMAIN_TC_COLD_OFF)) #define RKL_PW_4_POWER_DOMAINS ( \ @@ -2994,10 +2978,10 @@ intel_display_power_put_mask_in_set(struct drm_i915_private *i915, BIT_ULL(POWER_DOMAIN_AUDIO) | \ BIT_ULL(POWER_DOMAIN_VGA) | \ BIT_ULL(POWER_DOMAIN_TRANSCODER_B) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) | \ - BIT_ULL(POWER_DOMAIN_PORT_DDI_E_LANES) | \ - BIT_ULL(POWER_DOMAIN_AUX_D) | \ - BIT_ULL(POWER_DOMAIN_AUX_E) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC1) | \ + BIT_ULL(POWER_DOMAIN_PORT_DDI_LANES_TC2) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC1) | \ + BIT_ULL(POWER_DOMAIN_AUX_USBC2) | \ BIT_ULL(POWER_DOMAIN_INIT)) /* @@ -4145,8 +4129,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { } }, { - .name = "DDI D TC1 IO", - .domains = TGL_DDI_IO_D_TC1_POWER_DOMAINS, + .name = "DDI IO TC1", + .domains = TGL_DDI_IO_TC1_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4155,8 +4139,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "DDI E TC2 IO", - .domains = TGL_DDI_IO_E_TC2_POWER_DOMAINS, + .name = "DDI IO TC2", + .domains = TGL_DDI_IO_TC2_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4165,8 +4149,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "DDI F TC3 IO", - .domains = TGL_DDI_IO_F_TC3_POWER_DOMAINS, + .name = "DDI IO TC3", + .domains = TGL_DDI_IO_TC3_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4175,8 +4159,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "DDI G TC4 IO", - .domains = TGL_DDI_IO_G_TC4_POWER_DOMAINS, + .name = "DDI IO TC4", + .domains = TGL_DDI_IO_TC4_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4185,8 +4169,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "DDI H TC5 IO", - .domains = TGL_DDI_IO_H_TC5_POWER_DOMAINS, + .name = "DDI IO TC5", + .domains = TGL_DDI_IO_TC5_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4195,8 +4179,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "DDI I TC6 IO", - .domains = TGL_DDI_IO_I_TC6_POWER_DOMAINS, + .name = "DDI IO TC6", + .domains = TGL_DDI_IO_TC6_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4241,8 +4225,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX D TC1", - .domains = TGL_AUX_D_TC1_IO_POWER_DOMAINS, + .name = "AUX USBC1", + .domains = TGL_AUX_IO_USBC1_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4252,8 +4236,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX E TC2", - .domains = TGL_AUX_E_TC2_IO_POWER_DOMAINS, + .name = "AUX USBC2", + .domains = TGL_AUX_IO_USBC2_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4263,8 +4247,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX F TC3", - .domains = TGL_AUX_F_TC3_IO_POWER_DOMAINS, + .name = "AUX USBC3", + .domains = TGL_AUX_IO_USBC3_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4274,8 +4258,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX G TC4", - .domains = TGL_AUX_G_TC4_IO_POWER_DOMAINS, + .name = "AUX USBC4", + .domains = TGL_AUX_IO_USBC4_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4285,8 +4269,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX H TC5", - .domains = TGL_AUX_H_TC5_IO_POWER_DOMAINS, + .name = "AUX USBC5", + .domains = TGL_AUX_IO_USBC5_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4296,8 +4280,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX I TC6", - .domains = TGL_AUX_I_TC6_IO_POWER_DOMAINS, + .name = "AUX USBC6", + .domains = TGL_AUX_IO_USBC6_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4307,8 +4291,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX D TBT1", - .domains = TGL_AUX_D_TBT1_IO_POWER_DOMAINS, + .name = "AUX TBT1", + .domains = TGL_AUX_IO_TBT1_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4318,8 +4302,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX E TBT2", - .domains = TGL_AUX_E_TBT2_IO_POWER_DOMAINS, + .name = "AUX TBT2", + .domains = TGL_AUX_IO_TBT2_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4329,8 +4313,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX F TBT3", - .domains = TGL_AUX_F_TBT3_IO_POWER_DOMAINS, + .name = "AUX TBT3", + .domains = TGL_AUX_IO_TBT3_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4340,8 +4324,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX G TBT4", - .domains = TGL_AUX_G_TBT4_IO_POWER_DOMAINS, + .name = "AUX TBT4", + .domains = TGL_AUX_IO_TBT4_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4351,8 +4335,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX H TBT5", - .domains = TGL_AUX_H_TBT5_IO_POWER_DOMAINS, + .name = "AUX TBT5", + .domains = TGL_AUX_IO_TBT5_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4362,8 +4346,8 @@ static const struct i915_power_well_desc tgl_power_wells[] = { }, }, { - .name = "AUX I TBT6", - .domains = TGL_AUX_I_TBT6_IO_POWER_DOMAINS, + .name = "AUX TBT6", + .domains = TGL_AUX_IO_TBT6_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4471,8 +4455,8 @@ static const struct i915_power_well_desc rkl_power_wells[] = { } }, { - .name = "DDI D TC1 IO", - .domains = TGL_DDI_IO_D_TC1_POWER_DOMAINS, + .name = "DDI IO TC1", + .domains = TGL_DDI_IO_TC1_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4481,8 +4465,8 @@ static const struct i915_power_well_desc rkl_power_wells[] = { }, }, { - .name = "DDI E TC2 IO", - .domains = TGL_DDI_IO_E_TC2_POWER_DOMAINS, + .name = "DDI IO TC2", + .domains = TGL_DDI_IO_TC2_POWER_DOMAINS, .ops = &hsw_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4511,8 +4495,8 @@ static const struct i915_power_well_desc rkl_power_wells[] = { }, }, { - .name = "AUX D TC1", - .domains = TGL_AUX_D_TC1_IO_POWER_DOMAINS, + .name = "AUX USBC1", + .domains = TGL_AUX_IO_USBC1_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { @@ -4521,8 +4505,8 @@ static const struct i915_power_well_desc rkl_power_wells[] = { }, }, { - .name = "AUX E TC2", - .domains = TGL_AUX_E_TC2_IO_POWER_DOMAINS, + .name = "AUX USBC2", + .domains = TGL_AUX_IO_USBC2_POWER_DOMAINS, .ops = &icl_aux_power_well_ops, .id = DISP_PW_ID_NONE, { diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index bc30c479be534..f3ca5d5c97781 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -41,6 +41,14 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_G_LANES, POWER_DOMAIN_PORT_DDI_H_LANES, POWER_DOMAIN_PORT_DDI_I_LANES, + + POWER_DOMAIN_PORT_DDI_LANES_TC1 = POWER_DOMAIN_PORT_DDI_D_LANES, /* tgl+ */ + POWER_DOMAIN_PORT_DDI_LANES_TC2, + POWER_DOMAIN_PORT_DDI_LANES_TC3, + POWER_DOMAIN_PORT_DDI_LANES_TC4, + POWER_DOMAIN_PORT_DDI_LANES_TC5, + POWER_DOMAIN_PORT_DDI_LANES_TC6, + POWER_DOMAIN_PORT_DDI_A_IO, POWER_DOMAIN_PORT_DDI_B_IO, POWER_DOMAIN_PORT_DDI_C_IO, @@ -50,6 +58,14 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_G_IO, POWER_DOMAIN_PORT_DDI_H_IO, POWER_DOMAIN_PORT_DDI_I_IO, + + POWER_DOMAIN_PORT_DDI_IO_TC1 = POWER_DOMAIN_PORT_DDI_D_IO, /* tgl+ */ + POWER_DOMAIN_PORT_DDI_IO_TC2, + POWER_DOMAIN_PORT_DDI_IO_TC3, + POWER_DOMAIN_PORT_DDI_IO_TC4, + POWER_DOMAIN_PORT_DDI_IO_TC5, + POWER_DOMAIN_PORT_DDI_IO_TC6, + POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, @@ -64,6 +80,14 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_G, POWER_DOMAIN_AUX_H, POWER_DOMAIN_AUX_I, + + POWER_DOMAIN_AUX_USBC1 = POWER_DOMAIN_AUX_D, /* tgl+ */ + POWER_DOMAIN_AUX_USBC2, + POWER_DOMAIN_AUX_USBC3, + POWER_DOMAIN_AUX_USBC4, + POWER_DOMAIN_AUX_USBC5, + POWER_DOMAIN_AUX_USBC6, + POWER_DOMAIN_AUX_IO_A, POWER_DOMAIN_AUX_C_TBT, POWER_DOMAIN_AUX_D_TBT, @@ -72,6 +96,14 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_G_TBT, POWER_DOMAIN_AUX_H_TBT, POWER_DOMAIN_AUX_I_TBT, + + POWER_DOMAIN_AUX_TBT1 = POWER_DOMAIN_AUX_D_TBT, /* tgl+ */ + POWER_DOMAIN_AUX_TBT2, + POWER_DOMAIN_AUX_TBT3, + POWER_DOMAIN_AUX_TBT4, + POWER_DOMAIN_AUX_TBT5, + POWER_DOMAIN_AUX_TBT6, + POWER_DOMAIN_GMBUS, POWER_DOMAIN_MODESET, POWER_DOMAIN_GT_IRQ, From 6a4500c7b83f9e4470dd20cf89f691abd132d090 Mon Sep 17 00:00:00 2001 From: Colin Xu Date: Fri, 26 Feb 2021 12:45:59 +0800 Subject: [PATCH 106/142] drm/i915/gvt: Get accurate vGPU virtual display refresh rate from vreg Guest OS builds up its timing mode list based on the virtual EDID as simulated by GVT. However since there are several timings supported in the virtual EDID, and each timing can also support several modes (resolution and refresh rate), current emulated vblank period (16ms) may not always be correct and could lead to miss-sync behavior in guest. Guest driver will setup new resolution and program vregs accordingly and it should always follows GEN PRM. Based on the simulated display regs by GVT, it's safe to decode the actual refresh rate using by guest from vreg only. Current implementation only enables PIPE_A and PIPE_A is always tied to TRANSCODER_A in HW. GVT may simulate DP monitor on PORT_B or PORT_D based on the caller. So we can find out which DPLL is used by PORT_x which connected to TRANSCODER_A and calculate the DP bit rate from the DPLL frequency. Then DP stream clock (pixel clock) can be calculated from DP link M/N and DP bit rate. Finally, get the refresh rate from pixel clock, H total and V total. The per-vGPU accurate refresh rate is not used yet but only stored, until per-vGPU vblank timer is enabled. Then each vGPU can have different and accurate refresh rate per-guest driver configuration. Refer to PRM for GEN display and VESA timing standard for more details. V2: Rebase to 5.11. Correctly calculate DP link rate for BDW and BXT. Use GVT_DEFAULT_REFRESH_RATE instead of hardcoded to 60 as init refresh. Typo fix. (zhenyu) Signed-off-by: Colin Xu Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20210226044559.283622-1-colin.xu@intel.com Reviewed-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/display.c | 2 + drivers/gpu/drm/i915/gvt/display.h | 3 + drivers/gpu/drm/i915/gvt/gvt.h | 1 + drivers/gpu/drm/i915/gvt/handlers.c | 256 +++++++++++++++++++++++++++- 4 files changed, 260 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index a15f875396576..b7dc2894c94b8 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -529,6 +529,8 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num, port->dpcd->data[DPCD_SINK_COUNT] = 0x1; port->type = type; port->id = resolution; + port->vrefresh_k = GVT_DEFAULT_REFRESH_RATE * MSEC_PER_SEC; + vgpu->display.port_num = port_num; emulate_monitor_status_change(vgpu); diff --git a/drivers/gpu/drm/i915/gvt/display.h b/drivers/gpu/drm/i915/gvt/display.h index b59b34046e1e2..2481a2ae1f687 100644 --- a/drivers/gpu/drm/i915/gvt/display.h +++ b/drivers/gpu/drm/i915/gvt/display.h @@ -157,6 +157,7 @@ enum intel_vgpu_edid { GVT_EDID_NUM, }; +#define GVT_DEFAULT_REFRESH_RATE 60 struct intel_vgpu_port { /* per display EDID information */ struct intel_vgpu_edid_data *edid; @@ -164,6 +165,8 @@ struct intel_vgpu_port { struct intel_vgpu_dpcd_data *dpcd; int type; enum intel_vgpu_edid id; + /* x1000 to get accurate 59.94, 24.976, 29.94, etc. in timing std. */ + u32 vrefresh_k; }; static inline char *vgpu_edid_str(enum intel_vgpu_edid id) diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index 62a4807424bb1..a0f54ff556953 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -133,6 +133,7 @@ struct intel_vgpu_display { struct intel_vgpu_i2c_edid i2c_edid; struct intel_vgpu_port ports[I915_MAX_PORTS]; struct intel_vgpu_sbi sbi; + enum port port_num; }; struct vgpu_sched_ctl { diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 0d124ced5f940..ebd3173b6c391 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -39,6 +39,7 @@ #include "i915_drv.h" #include "gvt.h" #include "i915_pvinfo.h" +#include "display/intel_display_types.h" /* XXX FIXME i915 has changed PP_XXX definition */ #define PCH_PP_STATUS _MMIO(0xc7200) @@ -443,6 +444,254 @@ static int dpy_reg_mmio_read(struct intel_vgpu *vgpu, unsigned int offset, return 0; } +/* + * Only PIPE_A is enabled in current vGPU display and PIPE_A is tied to + * TRANSCODER_A in HW. DDI/PORT could be PORT_x depends on + * setup_virtual_dp_monitor(). + * emulate_monitor_status_change() set up PLL for PORT_x as the initial enabled + * DPLL. Later guest driver may setup a different DPLLx when setting mode. + * So the correct sequence to find DP stream clock is: + * Check TRANS_DDI_FUNC_CTL on TRANSCODER_A to get PORT_x. + * Check correct PLLx for PORT_x to get PLL frequency and DP bitrate. + * Then Refresh rate then can be calculated based on follow equations: + * Pixel clock = h_total * v_total * refresh_rate + * stream clock = Pixel clock + * ls_clk = DP bitrate + * Link M/N = strm_clk / ls_clk + */ + +static u32 bdw_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) +{ + u32 dp_br = 0; + u32 ddi_pll_sel = vgpu_vreg_t(vgpu, PORT_CLK_SEL(port)); + + switch (ddi_pll_sel) { + case PORT_CLK_SEL_LCPLL_2700: + dp_br = 270000 * 2; + break; + case PORT_CLK_SEL_LCPLL_1350: + dp_br = 135000 * 2; + break; + case PORT_CLK_SEL_LCPLL_810: + dp_br = 81000 * 2; + break; + case PORT_CLK_SEL_SPLL: + { + switch (vgpu_vreg_t(vgpu, SPLL_CTL) & SPLL_FREQ_MASK) { + case SPLL_FREQ_810MHz: + dp_br = 81000 * 2; + break; + case SPLL_FREQ_1350MHz: + dp_br = 135000 * 2; + break; + case SPLL_FREQ_2700MHz: + dp_br = 270000 * 2; + break; + default: + gvt_dbg_dpy("vgpu-%d PORT_%c can't get freq from SPLL 0x%08x\n", + vgpu->id, port_name(port), vgpu_vreg_t(vgpu, SPLL_CTL)); + break; + } + break; + } + case PORT_CLK_SEL_WRPLL1: + case PORT_CLK_SEL_WRPLL2: + { + u32 wrpll_ctl; + int refclk, n, p, r; + + if (ddi_pll_sel == PORT_CLK_SEL_WRPLL1) + wrpll_ctl = vgpu_vreg_t(vgpu, WRPLL_CTL(DPLL_ID_WRPLL1)); + else + wrpll_ctl = vgpu_vreg_t(vgpu, WRPLL_CTL(DPLL_ID_WRPLL2)); + + switch (wrpll_ctl & WRPLL_REF_MASK) { + case WRPLL_REF_PCH_SSC: + refclk = vgpu->gvt->gt->i915->dpll.ref_clks.ssc; + break; + case WRPLL_REF_LCPLL: + refclk = 2700000; + break; + default: + gvt_dbg_dpy("vgpu-%d PORT_%c WRPLL can't get refclk 0x%08x\n", + vgpu->id, port_name(port), wrpll_ctl); + goto out; + } + + r = wrpll_ctl & WRPLL_DIVIDER_REF_MASK; + p = (wrpll_ctl & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT; + n = (wrpll_ctl & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT; + + dp_br = (refclk * n / 10) / (p * r) * 2; + break; + } + default: + gvt_dbg_dpy("vgpu-%d PORT_%c has invalid clock select 0x%08x\n", + vgpu->id, port_name(port), vgpu_vreg_t(vgpu, PORT_CLK_SEL(port))); + break; + } + +out: + return dp_br; +} + +static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) +{ + u32 dp_br = 0; + int refclk = vgpu->gvt->gt->i915->dpll.ref_clks.nssc; + enum dpio_phy phy = DPIO_PHY0; + enum dpio_channel ch = DPIO_CH0; + struct dpll clock = {0}; + u32 temp; + + /* Port to PHY mapping is fixed, see bxt_ddi_phy_info{} */ + switch (port) { + case PORT_A: + phy = DPIO_PHY1; + ch = DPIO_CH0; + break; + case PORT_B: + phy = DPIO_PHY0; + ch = DPIO_CH0; + break; + case PORT_C: + phy = DPIO_PHY0; + ch = DPIO_CH1; + break; + default: + gvt_dbg_dpy("vgpu-%d no PHY for PORT_%c\n", vgpu->id, port_name(port)); + goto out; + } + + temp = vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port)); + if (!(temp & PORT_PLL_ENABLE) || !(temp & PORT_PLL_LOCK)) { + gvt_dbg_dpy("vgpu-%d PORT_%c PLL_ENABLE 0x%08x isn't enabled or locked\n", + vgpu->id, port_name(port), temp); + goto out; + } + + clock.m1 = 2; + clock.m2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 0)) & PORT_PLL_M2_MASK) << 22; + if (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 3)) & PORT_PLL_M2_FRAC_ENABLE) + clock.m2 |= vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 2)) & PORT_PLL_M2_FRAC_MASK; + clock.n = (vgpu_vreg_t(vgpu, BXT_PORT_PLL(phy, ch, 1)) & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; + clock.p1 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; + clock.p2 = (vgpu_vreg_t(vgpu, BXT_PORT_PLL_EBB_0(phy, ch)) & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; + clock.m = clock.m1 * clock.m2; + clock.p = clock.p1 * clock.p2; + + if (clock.n == 0 || clock.p == 0) { + gvt_dbg_dpy("vgpu-%d PORT_%c PLL has invalid divider\n", vgpu->id, port_name(port)); + goto out; + } + + clock.vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock.m), clock.n << 22); + clock.dot = DIV_ROUND_CLOSEST(clock.vco, clock.p); + + dp_br = clock.dot / 5; + +out: + return dp_br; +} + +static u32 skl_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) +{ + u32 dp_br = 0; + enum intel_dpll_id dpll_id = DPLL_ID_SKL_DPLL0; + + /* Find the enabled DPLL for the DDI/PORT */ + if (!(vgpu_vreg_t(vgpu, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_OFF(port)) && + (vgpu_vreg_t(vgpu, DPLL_CTRL2) & DPLL_CTRL2_DDI_SEL_OVERRIDE(port))) { + dpll_id += (vgpu_vreg_t(vgpu, DPLL_CTRL2) & + DPLL_CTRL2_DDI_CLK_SEL_MASK(port)) >> + DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port); + } else { + gvt_dbg_dpy("vgpu-%d DPLL for PORT_%c isn't turned on\n", + vgpu->id, port_name(port)); + return dp_br; + } + + /* Find PLL output frequency from correct DPLL, and get bir rate */ + switch ((vgpu_vreg_t(vgpu, DPLL_CTRL1) & + DPLL_CTRL1_LINK_RATE_MASK(dpll_id)) >> + DPLL_CTRL1_LINK_RATE_SHIFT(dpll_id)) { + case DPLL_CTRL1_LINK_RATE_810: + dp_br = 81000 * 2; + break; + case DPLL_CTRL1_LINK_RATE_1080: + dp_br = 108000 * 2; + break; + case DPLL_CTRL1_LINK_RATE_1350: + dp_br = 135000 * 2; + break; + case DPLL_CTRL1_LINK_RATE_1620: + dp_br = 162000 * 2; + break; + case DPLL_CTRL1_LINK_RATE_2160: + dp_br = 216000 * 2; + break; + case DPLL_CTRL1_LINK_RATE_2700: + dp_br = 270000 * 2; + break; + default: + dp_br = 0; + gvt_dbg_dpy("vgpu-%d PORT_%c fail to get DPLL-%d freq\n", + vgpu->id, port_name(port), dpll_id); + } + + return dp_br; +} + +static void vgpu_update_refresh_rate(struct intel_vgpu *vgpu) +{ + struct drm_i915_private *dev_priv = vgpu->gvt->gt->i915; + enum port port; + u32 dp_br, link_m, link_n, htotal, vtotal; + + /* Find DDI/PORT assigned to TRANSCODER_A, expect B or D */ + port = (vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) & + TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT; + if (port != PORT_B && port != PORT_D) { + gvt_dbg_dpy("vgpu-%d unsupported PORT_%c\n", vgpu->id, port_name(port)); + return; + } + + /* Calculate DP bitrate from PLL */ + if (IS_BROADWELL(dev_priv)) + dp_br = bdw_vgpu_get_dp_bitrate(vgpu, port); + else if (IS_BROXTON(dev_priv)) + dp_br = bxt_vgpu_get_dp_bitrate(vgpu, port); + else + dp_br = skl_vgpu_get_dp_bitrate(vgpu, port); + + /* Get DP link symbol clock M/N */ + link_m = vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)); + link_n = vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)); + + /* Get H/V total from transcoder timing */ + htotal = (vgpu_vreg_t(vgpu, HTOTAL(TRANSCODER_A)) >> TRANS_HTOTAL_SHIFT) + 1; + vtotal = (vgpu_vreg_t(vgpu, VTOTAL(TRANSCODER_A)) >> TRANS_VTOTAL_SHIFT) + 1; + + if (dp_br && link_n && htotal && vtotal) { + u64 pixel_clk = 0; + u32 new_rate = 0; + u32 *old_rate = &(intel_vgpu_port(vgpu, vgpu->display.port_num)->vrefresh_k); + + /* Calcuate pixel clock by (ls_clk * M / N) */ + pixel_clk = div_u64(mul_u32_u32(link_m, dp_br), link_n); + pixel_clk *= MSEC_PER_SEC; + + /* Calcuate refresh rate by (pixel_clk / (h_total * v_total)) */ + new_rate = DIV64_U64_ROUND_CLOSEST(pixel_clk, div64_u64(mul_u32_u32(htotal, vtotal), MSEC_PER_SEC)); + + if (*old_rate != new_rate) + *old_rate = new_rate; + + gvt_dbg_dpy("vgpu-%d PIPE_%c refresh rate updated to %d\n", + vgpu->id, pipe_name(PIPE_A), new_rate); + } +} + static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { @@ -451,10 +700,13 @@ static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, write_vreg(vgpu, offset, p_data, bytes); data = vgpu_vreg(vgpu, offset); - if (data & PIPECONF_ENABLE) + if (data & PIPECONF_ENABLE) { vgpu_vreg(vgpu, offset) |= I965_PIPECONF_ACTIVE; - else + vgpu_update_refresh_rate(vgpu); + + } else { vgpu_vreg(vgpu, offset) &= ~I965_PIPECONF_ACTIVE; + } /* vgpu_lock already hold by emulate mmio r/w */ mutex_unlock(&vgpu->vgpu_lock); intel_gvt_check_vblank_emulation(vgpu->gvt); From b01739fb865a268aec617f6bb5d2ef498da72697 Mon Sep 17 00:00:00 2001 From: Colin Xu Date: Fri, 26 Feb 2021 12:46:30 +0800 Subject: [PATCH 107/142] drm/i915/gvt: Refactor GVT vblank emulator for vGPU virtual display Current vblank emulator uses single hrtimer at 16ms period for all vGPUs, which introduces three major issues: - 16ms matches the refresh rate at 62.5Hz (instead of 60Hz) which doesn't follow standard timing. This leads to some frame drop or glitch issue during video playback. SW expects a vsync interval of 16.667ms or higher precision for an accurate 60Hz refresh rate. However current vblank emulator only works at 16ms. - Doesn't respect the fact that with current virtual EDID timing set, not all resolutions are running at 60Hz. For example, current virtual EDID also supports refresh rate at 56Hz, 59.97Hz, 60Hz, 75Hz, etc. - Current vblank emulator use single hrtimer for all vGPUs. Regardsless the possibility that different guests could run in different resolutions, all vsync interrupts are injected at 16ms interval with same hrtimer. Based on previous patch which decode guest expected refresh rate from vreg, the vblank emulator refactor patch makes following changes: - Change the vblank emulator hrtimer from gvt global to per-vGPU. By doing this, each vGPU display can operates at different refresh rates. Currently only one dislay is supported for each vGPU so per-vGPU hrtimer is enough. If multiple displays are supported per-vGPU in future, we can expand to per-PIPE further. - Change the fixed hrtimer period from 16ms to dynamic based on vreg. GVT is expected to emulate the HW as close as possible. So reflacting the accurate vsync interrupt interval is more correct than fixed 16ms. - Change the vblank timer period and start the timer on PIPECONF change. The initial period is updated to 16666667 based on 60Hz refresh rate. According to PRM, PIPECONF controls the timing generator of the connected display on this pipe, so it's safe to stop hrtimer on PIPECONF disabling, and re-start hrtimer at new period on enabling. Other changes including: - Move vblank_timer_fn from irq.c into display.c. - Clean per-vGPU vblank timer at clean_display instead of clean_irq. To run quick test, launch a web browser and goto URL: www.displayhz.com The actual refresh rate from guest can now always match guest settings. V2: Rebase to 5.11. Remove unused intel_gvt_clean_irq(). Simplify enable logic in update_vblank_emulation(). (zhenyu) Loop all vGPU by idr when check all vblank timer. (zhenyu) Signed-off-by: Colin Xu Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20210226044630.284269-1-colin.xu@intel.com Reviewed-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/display.c | 105 +++++++++++++++------------ drivers/gpu/drm/i915/gvt/display.h | 11 ++- drivers/gpu/drm/i915/gvt/gvt.c | 25 +++++-- drivers/gpu/drm/i915/gvt/gvt.h | 12 ++- drivers/gpu/drm/i915/gvt/handlers.c | 7 +- drivers/gpu/drm/i915/gvt/interrupt.c | 37 ---------- drivers/gpu/drm/i915/gvt/interrupt.h | 7 -- drivers/gpu/drm/i915/gvt/vgpu.c | 2 - 8 files changed, 94 insertions(+), 112 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index b7dc2894c94b8..26bce91437fa1 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -501,11 +501,27 @@ static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num) port->dpcd = NULL; } +static enum hrtimer_restart vblank_timer_fn(struct hrtimer *data) +{ + struct intel_vgpu_vblank_timer *vblank_timer; + struct intel_vgpu *vgpu; + + vblank_timer = container_of(data, struct intel_vgpu_vblank_timer, timer); + vgpu = container_of(vblank_timer, struct intel_vgpu, vblank_timer); + + /* Set vblank emulation request per-vGPU bit */ + intel_gvt_request_service(vgpu->gvt, + INTEL_GVT_REQUEST_EMULATE_VBLANK + vgpu->id); + hrtimer_add_expires_ns(&vblank_timer->timer, vblank_timer->period); + return HRTIMER_RESTART; +} + static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num, int type, unsigned int resolution) { struct drm_i915_private *i915 = vgpu->gvt->gt->i915; struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num); + struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer; if (drm_WARN_ON(&i915->drm, resolution >= GVT_EDID_NUM)) return -EINVAL; @@ -532,47 +548,56 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num, port->vrefresh_k = GVT_DEFAULT_REFRESH_RATE * MSEC_PER_SEC; vgpu->display.port_num = port_num; + /* Init hrtimer based on default refresh rate */ + hrtimer_init(&vblank_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + vblank_timer->timer.function = vblank_timer_fn; + vblank_timer->vrefresh_k = port->vrefresh_k; + vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k); + emulate_monitor_status_change(vgpu); return 0; } /** - * intel_gvt_check_vblank_emulation - check if vblank emulation timer should - * be turned on/off when a virtual pipe is enabled/disabled. - * @gvt: a GVT device + * vgpu_update_vblank_emulation - Update per-vGPU vblank_timer + * @vgpu: vGPU operated + * @turnon: Turn ON/OFF vblank_timer * - * This function is used to turn on/off vblank timer according to currently - * enabled/disabled virtual pipes. + * This function is used to turn on/off or update the per-vGPU vblank_timer + * when PIPECONF is enabled or disabled. vblank_timer period is also updated + * if guest changed the refresh rate. * */ -void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt) +void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon) { - struct intel_gvt_irq *irq = &gvt->irq; - struct intel_vgpu *vgpu; - int pipe, id; - int found = false; - - mutex_lock(&gvt->lock); - for_each_active_vgpu(gvt, vgpu, id) { - for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) { - if (pipe_is_enabled(vgpu, pipe)) { - found = true; - break; - } + struct intel_vgpu_vblank_timer *vblank_timer = &vgpu->vblank_timer; + struct intel_vgpu_port *port = + intel_vgpu_port(vgpu, vgpu->display.port_num); + + if (turnon) { + /* + * Skip the re-enable if already active and vrefresh unchanged. + * Otherwise, stop timer if already active and restart with new + * period. + */ + if (vblank_timer->vrefresh_k != port->vrefresh_k || + !hrtimer_active(&vblank_timer->timer)) { + /* Stop timer before start with new period if active */ + if (hrtimer_active(&vblank_timer->timer)) + hrtimer_cancel(&vblank_timer->timer); + + /* Make sure new refresh rate updated to timer period */ + vblank_timer->vrefresh_k = port->vrefresh_k; + vblank_timer->period = DIV64_U64_ROUND_CLOSEST(NSEC_PER_SEC * MSEC_PER_SEC, vblank_timer->vrefresh_k); + hrtimer_start(&vblank_timer->timer, + ktime_add_ns(ktime_get(), vblank_timer->period), + HRTIMER_MODE_ABS); } - if (found) - break; + } else { + /* Caller request to stop vblank */ + hrtimer_cancel(&vblank_timer->timer); } - - /* all the pipes are disabled */ - if (!found) - hrtimer_cancel(&irq->vblank_timer.timer); - else - hrtimer_start(&irq->vblank_timer.timer, - ktime_add_ns(ktime_get(), irq->vblank_timer.period), - HRTIMER_MODE_ABS); - mutex_unlock(&gvt->lock); } static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe) @@ -604,7 +629,7 @@ static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe) } } -static void emulate_vblank(struct intel_vgpu *vgpu) +void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu) { int pipe; @@ -614,24 +639,6 @@ static void emulate_vblank(struct intel_vgpu *vgpu) mutex_unlock(&vgpu->vgpu_lock); } -/** - * intel_gvt_emulate_vblank - trigger vblank events for vGPUs on GVT device - * @gvt: a GVT device - * - * This function is used to trigger vblank interrupts for vGPUs on GVT device - * - */ -void intel_gvt_emulate_vblank(struct intel_gvt *gvt) -{ - struct intel_vgpu *vgpu; - int id; - - mutex_lock(&gvt->lock); - for_each_active_vgpu(gvt, vgpu, id) - emulate_vblank(vgpu); - mutex_unlock(&gvt->lock); -} - /** * intel_vgpu_emulate_hotplug - trigger hotplug event for vGPU * @vgpu: a vGPU @@ -722,6 +729,8 @@ void intel_vgpu_clean_display(struct intel_vgpu *vgpu) clean_virtual_dp_monitor(vgpu, PORT_D); else clean_virtual_dp_monitor(vgpu, PORT_B); + + vgpu_update_vblank_emulation(vgpu, false); } /** diff --git a/drivers/gpu/drm/i915/gvt/display.h b/drivers/gpu/drm/i915/gvt/display.h index 2481a2ae1f687..f5616f99ef2f8 100644 --- a/drivers/gpu/drm/i915/gvt/display.h +++ b/drivers/gpu/drm/i915/gvt/display.h @@ -36,6 +36,7 @@ #define _GVT_DISPLAY_H_ #include +#include struct intel_gvt; struct intel_vgpu; @@ -169,6 +170,12 @@ struct intel_vgpu_port { u32 vrefresh_k; }; +struct intel_vgpu_vblank_timer { + struct hrtimer timer; + u32 vrefresh_k; + u64 period; +}; + static inline char *vgpu_edid_str(enum intel_vgpu_edid id) { switch (id) { @@ -205,8 +212,8 @@ static inline unsigned int vgpu_edid_yres(enum intel_vgpu_edid id) } } -void intel_gvt_emulate_vblank(struct intel_gvt *gvt); -void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt); +void intel_vgpu_emulate_vblank(struct intel_vgpu *vgpu); +void vgpu_update_vblank_emulation(struct intel_vgpu *vgpu, bool turnon); int intel_vgpu_init_display(struct intel_vgpu *vgpu, u64 resolution); void intel_vgpu_reset_display(struct intel_vgpu *vgpu); diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index aa7fc0dd1db5d..2ecb8534930b0 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -203,6 +203,22 @@ static void init_device_info(struct intel_gvt *gvt) info->msi_cap_offset = pdev->msi_cap; } +static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt) +{ + struct intel_vgpu *vgpu; + int id; + + mutex_lock(&gvt->lock); + idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) { + if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id, + (void *)&gvt->service_request)) { + if (vgpu->active) + intel_vgpu_emulate_vblank(vgpu); + } + } + mutex_unlock(&gvt->lock); +} + static int gvt_service_thread(void *data) { struct intel_gvt *gvt = (struct intel_gvt *)data; @@ -220,9 +236,7 @@ static int gvt_service_thread(void *data) if (WARN_ONCE(ret, "service thread is waken up by signal.\n")) continue; - if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK, - (void *)&gvt->service_request)) - intel_gvt_emulate_vblank(gvt); + intel_gvt_test_and_emulate_vblank(gvt); if (test_bit(INTEL_GVT_REQUEST_SCHED, (void *)&gvt->service_request) || @@ -278,7 +292,6 @@ void intel_gvt_clean_device(struct drm_i915_private *i915) intel_gvt_clean_sched_policy(gvt); intel_gvt_clean_workload_scheduler(gvt); intel_gvt_clean_gtt(gvt); - intel_gvt_clean_irq(gvt); intel_gvt_free_firmware(gvt); intel_gvt_clean_mmio_info(gvt); idr_destroy(&gvt->vgpu_idr); @@ -337,7 +350,7 @@ int intel_gvt_init_device(struct drm_i915_private *i915) ret = intel_gvt_init_gtt(gvt); if (ret) - goto out_clean_irq; + goto out_free_firmware; ret = intel_gvt_init_workload_scheduler(gvt); if (ret) @@ -392,8 +405,6 @@ int intel_gvt_init_device(struct drm_i915_private *i915) intel_gvt_clean_workload_scheduler(gvt); out_clean_gtt: intel_gvt_clean_gtt(gvt); -out_clean_irq: - intel_gvt_clean_irq(gvt); out_free_firmware: intel_gvt_free_firmware(gvt); out_clean_mmio_info: diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index a0f54ff556953..62b6faeb7ec03 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -215,6 +215,7 @@ struct intel_vgpu { struct list_head dmabuf_obj_list_head; struct mutex dmabuf_lock; struct idr object_idr; + struct intel_vgpu_vblank_timer vblank_timer; u32 scan_nonprivbb; }; @@ -344,13 +345,16 @@ static inline struct intel_gvt *to_gvt(struct drm_i915_private *i915) } enum { - INTEL_GVT_REQUEST_EMULATE_VBLANK = 0, - /* Scheduling trigger by timer */ - INTEL_GVT_REQUEST_SCHED = 1, + INTEL_GVT_REQUEST_SCHED = 0, /* Scheduling trigger by event */ - INTEL_GVT_REQUEST_EVENT_SCHED = 2, + INTEL_GVT_REQUEST_EVENT_SCHED = 1, + + /* per-vGPU vblank emulation request */ + INTEL_GVT_REQUEST_EMULATE_VBLANK = 2, + INTEL_GVT_REQUEST_EMULATE_VBLANK_MAX = INTEL_GVT_REQUEST_EMULATE_VBLANK + + GVT_MAX_VGPU, }; static inline void intel_gvt_request_service(struct intel_gvt *gvt, diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index ebd3173b6c391..30ae4eca87484 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -703,14 +703,11 @@ static int pipeconf_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, if (data & PIPECONF_ENABLE) { vgpu_vreg(vgpu, offset) |= I965_PIPECONF_ACTIVE; vgpu_update_refresh_rate(vgpu); - + vgpu_update_vblank_emulation(vgpu, true); } else { vgpu_vreg(vgpu, offset) &= ~I965_PIPECONF_ACTIVE; + vgpu_update_vblank_emulation(vgpu, false); } - /* vgpu_lock already hold by emulate mmio r/w */ - mutex_unlock(&vgpu->vgpu_lock); - intel_gvt_check_vblank_emulation(vgpu->gvt); - mutex_lock(&vgpu->vgpu_lock); return 0; } diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index 7498878e6289c..497d28ce47df5 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -647,38 +647,6 @@ static void init_events( } } -static enum hrtimer_restart vblank_timer_fn(struct hrtimer *data) -{ - struct intel_gvt_vblank_timer *vblank_timer; - struct intel_gvt_irq *irq; - struct intel_gvt *gvt; - - vblank_timer = container_of(data, struct intel_gvt_vblank_timer, timer); - irq = container_of(vblank_timer, struct intel_gvt_irq, vblank_timer); - gvt = container_of(irq, struct intel_gvt, irq); - - intel_gvt_request_service(gvt, INTEL_GVT_REQUEST_EMULATE_VBLANK); - hrtimer_add_expires_ns(&vblank_timer->timer, vblank_timer->period); - return HRTIMER_RESTART; -} - -/** - * intel_gvt_clean_irq - clean up GVT-g IRQ emulation subsystem - * @gvt: a GVT device - * - * This function is called at driver unloading stage, to clean up GVT-g IRQ - * emulation subsystem. - * - */ -void intel_gvt_clean_irq(struct intel_gvt *gvt) -{ - struct intel_gvt_irq *irq = &gvt->irq; - - hrtimer_cancel(&irq->vblank_timer.timer); -} - -#define VBLANK_TIMER_PERIOD 16000000 - /** * intel_gvt_init_irq - initialize GVT-g IRQ emulation subsystem * @gvt: a GVT device @@ -692,7 +660,6 @@ void intel_gvt_clean_irq(struct intel_gvt *gvt) int intel_gvt_init_irq(struct intel_gvt *gvt) { struct intel_gvt_irq *irq = &gvt->irq; - struct intel_gvt_vblank_timer *vblank_timer = &irq->vblank_timer; gvt_dbg_core("init irq framework\n"); @@ -707,9 +674,5 @@ int intel_gvt_init_irq(struct intel_gvt *gvt) init_irq_map(irq); - hrtimer_init(&vblank_timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - vblank_timer->timer.function = vblank_timer_fn; - vblank_timer->period = VBLANK_TIMER_PERIOD; - return 0; } diff --git a/drivers/gpu/drm/i915/gvt/interrupt.h b/drivers/gpu/drm/i915/gvt/interrupt.h index 287cd142629ee..6c47d3e33161c 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.h +++ b/drivers/gpu/drm/i915/gvt/interrupt.h @@ -201,11 +201,6 @@ struct intel_gvt_irq_map { u32 down_irq_bitmask; }; -struct intel_gvt_vblank_timer { - struct hrtimer timer; - u64 period; -}; - /* structure containing device specific IRQ state */ struct intel_gvt_irq { struct intel_gvt_irq_ops *ops; @@ -214,11 +209,9 @@ struct intel_gvt_irq { struct intel_gvt_event_info events[INTEL_GVT_EVENT_MAX]; DECLARE_BITMAP(pending_events, INTEL_GVT_EVENT_MAX); struct intel_gvt_irq_map *irq_map; - struct intel_gvt_vblank_timer vblank_timer; }; int intel_gvt_init_irq(struct intel_gvt *gvt); -void intel_gvt_clean_irq(struct intel_gvt *gvt); void intel_vgpu_trigger_virtual_event(struct intel_vgpu *vgpu, enum intel_gvt_event_type event); diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index e49944fde3339..c6e3f2925c01d 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -300,8 +300,6 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) mutex_unlock(&vgpu->vgpu_lock); mutex_lock(&gvt->lock); - if (idr_is_empty(&gvt->vgpu_idr)) - intel_gvt_clean_irq(gvt); intel_gvt_update_vgpu_types(gvt); mutex_unlock(&gvt->lock); From 9317f356df83a5caeccae2e343d1a569929bcfc9 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Mon, 22 Feb 2021 13:48:38 +0530 Subject: [PATCH 108/142] drm/i915/gvt: Fixed couple of spellings in the file gtt.c s/negtive/negative/ s/possilbe/possible/ Signed-off-by: Bhaskar Chowdhury Acked-by: Randy Dunlap Signed-off-by: Zhenyu Wang Link: http://patchwork.freedesktop.org/patch/msgid/20210222081838.30328-1-unixbhaskar@gmail.com --- drivers/gpu/drm/i915/gvt/gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 6d12a5a401f6c..67a26923aa0e6 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1159,8 +1159,8 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, * @vgpu: target vgpu * @entry: target pfn's gtt entry * - * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition, - * negtive if found err. + * Return 1 if 2MB huge gtt shadowing is possible, 0 if miscondition, + * negative if found err. */ static int is_2MB_gtt_possible(struct intel_vgpu *vgpu, struct intel_gvt_gtt_entry *entry) From 59b7cb44cffde6ab5b8ace1aef9b79f50be1c3eb Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Wed, 17 Feb 2021 13:00:16 -0500 Subject: [PATCH 109/142] drm/i915/gen9bc: Handle TGP PCH during suspend/resume For Legacy S3 suspend/resume GEN9 BC needs to enable and setup TGP PCH. v2: * Move Wa_14010685332 into it's own function - vsyrjala * Add TODO comment about figuring out if we can move this workaround - imre v3: * Rename cnp_irq_post_reset() to cnp_display_clock_wa() * Add TODO item mentioning we need to clarify which platforms this workaround applies to * Just use ibx_irq_reset() in gen8_irq_reset(). This code should be functionally equivalent on gen9 bc to the code v2 added * Drop icp_hpd_irq_setup() call in spt_hpd_irq_setup(), this looks to be more or less identical to spt_hpd_irq_setup() minus additionally enabling one port. Will update i915 to use icp_hpd_irq_setup() for ICP in a separate patch. v4: * Revert Wa_14010685332 system list in comments to how it was before * Add back HAS_PCH_SPLIT() check before calling ibx_irq_reset() Cc: Matt Roper Signed-off-by: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20210217180016.1937401-1-lyude@redhat.com --- drivers/gpu/drm/i915/i915_irq.c | 49 +++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 013794004da4c..e0804049f42bf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3040,6 +3040,24 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } +static void cnp_display_clock_wa(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + + /* + * Wa_14010685332:cnp/cmp,tgp,adp + * TODO: Clarify which platforms this applies to + * TODO: Figure out if this workaround can be applied in the s0ix suspend/resume handlers as + * on earlier platforms and whether the workaround is also needed for runtime suspend/resume + */ + if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP || + (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP && INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) { + intel_uncore_rmw(uncore, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, + SBCLK_RUN_REFCLK_DIS); + intel_uncore_rmw(uncore, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0); + } +} + static void gen8_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -3063,6 +3081,8 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) if (HAS_PCH_SPLIT(dev_priv)) ibx_irq_reset(dev_priv); + + cnp_display_clock_wa(dev_priv); } static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) @@ -3104,15 +3124,7 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) GEN3_IRQ_RESET(uncore, SDE); - /* Wa_14010685332:cnp/cmp,tgp,adp */ - if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP || - (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP && - INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) { - intel_uncore_rmw(uncore, SOUTH_CHICKEN1, - SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS); - intel_uncore_rmw(uncore, SOUTH_CHICKEN1, - SBCLK_RUN_REFCLK_DIS, 0); - } + cnp_display_clock_wa(dev_priv); } static void gen11_irq_reset(struct drm_i915_private *dev_priv) @@ -3764,9 +3776,19 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) } } +static void icp_irq_postinstall(struct drm_i915_private *dev_priv) +{ + struct intel_uncore *uncore = &dev_priv->uncore; + u32 mask = SDE_GMBUS_ICP; + + GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); +} + static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) { - if (HAS_PCH_SPLIT(dev_priv)) + if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + icp_irq_postinstall(dev_priv); + else if (HAS_PCH_SPLIT(dev_priv)) ibx_irq_postinstall(dev_priv); gen8_gt_irq_postinstall(&dev_priv->gt); @@ -3775,13 +3797,6 @@ static void gen8_irq_postinstall(struct drm_i915_private *dev_priv) gen8_master_intr_enable(dev_priv->uncore.regs); } -static void icp_irq_postinstall(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - u32 mask = SDE_GMBUS_ICP; - - GEN3_IRQ_INIT(uncore, SDE, ~mask, 0xffffffff); -} static void gen11_irq_postinstall(struct drm_i915_private *dev_priv) { From cec3295b246b5555f6de7570d25a13a2754de245 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 16 Feb 2021 21:53:37 -0500 Subject: [PATCH 110/142] drm/i915/icp+: Use icp_hpd_irq_setup() instead of spt_hpd_irq_setup() While reviewing patches for handling workarounds related to gen9 bc, Imre from Intel discovered that we're using spt_hpd_irq_setup() on ICP+ PCHs despite it being almost the same as icp_hpd_irq_setup(). Since we need to be calling icp_hpd_irq_setup() to ensure that CML-S/TGP platforms function correctly anyway, let's move platforms using PCH_ICP which aren't handled by gen11_hpd_irq_setup() over to icp_hpd_irq_setup(). Cc: Tejas Upadhyay Signed-off-by: Lyude Paul Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20210217025337.1929015-2-lyude@redhat.com --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e0804049f42bf..5cfaec500a603 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -4319,6 +4319,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) dev_priv->display.hpd_irq_setup = gen11_hpd_irq_setup; else if (IS_GEN9_LP(dev_priv)) dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup; + else if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) + dev_priv->display.hpd_irq_setup = icp_hpd_irq_setup; else if (INTEL_PCH_TYPE(dev_priv) >= PCH_SPT) dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup; else From 899f9d7bbc01bacefe3b124d4655678ad299177d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 16 Feb 2021 18:00:35 +0200 Subject: [PATCH 111/142] drm/i915: Readout conn_state->max_bpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Populate conn_state->max_bpc with something sensible from the start. Otherwise it's possible that we get to compute_sink_pipe_bpp() with max_bpc==0. The specific scenario goes as follows: 1. Initial connector state allocated with max_bpc==0 2. Trigger a modeset on the crtc feeding the connector, without actually adding the connector to the commit 3. drm_atomic_connector_check() is skipped because the connector has not yet been added, hence conn_state->max_bpc retains its current value 4. drm_atomic_helper_check_modeset() -> drm_atomic_add_affected_connectors() -> the connector is now part of the commit 5. compute_baseline_pipe_bpp() -> MISSING_CASE(max_bpc==0) Note that pipe_bpp itself may not be populated on pre-g4x machines, in which case we just fall back to max_bpc==8 and let .compute_config() limit the resulting pipe_bpp further if necessary. Cc: Daniel Vetter Reported-by: Chris Wilson Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210216160035.4780-1-ville.syrjala@linux.intel.com Tested-by: Chris Wilson Reviewed-by: José Roberto de Souza --- drivers/gpu/drm/i915/display/intel_display.c | 24 +++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e1060076ac83f..d7151a934e4cf 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -7991,19 +7991,27 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) drm_connector_list_iter_begin(dev, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { - if (connector->base.state->crtc) + struct drm_connector_state *conn_state = connector->base.state; + struct intel_encoder *encoder = + to_intel_encoder(connector->base.encoder); + + if (conn_state->crtc) drm_connector_put(&connector->base); - if (connector->base.encoder) { - connector->base.state->best_encoder = - connector->base.encoder; - connector->base.state->crtc = - connector->base.encoder->crtc; + if (encoder) { + struct intel_crtc *crtc = + to_intel_crtc(encoder->base.crtc); + const struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + + conn_state->best_encoder = &encoder->base; + conn_state->crtc = &crtc->base; + conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3; drm_connector_get(&connector->base); } else { - connector->base.state->best_encoder = NULL; - connector->base.state->crtc = NULL; + conn_state->best_encoder = NULL; + conn_state->crtc = NULL; } } drm_connector_list_iter_end(&conn_iter); From 2871b2fde449c2567a2d46a3635356cbc97c9740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:31:58 +0200 Subject: [PATCH 112/142] drm/i915: Fix TGL+ plane SAGV watermark programming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we switch between SAGV on vs. off we need to reprogram all plane wateramrks accordingly. Currently skl_wm_add_affected_planes() totally ignores the SAGV watermark and just assumes we will use the normal WM0. Fix this by utilizing skl_plane_wm_level() which picks the correct watermark based on use_sagv_wm. Thus we will force an update on all the planes whose watermark registers need to be reprogrammed. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-2-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 60 ++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8cc67f9c4e586..2d0e3e7f11b87 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4748,11 +4748,10 @@ icl_get_total_relative_data_rate(struct intel_atomic_state *state, } static const struct skl_wm_level * -skl_plane_wm_level(const struct intel_crtc_state *crtc_state, +skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, enum plane_id plane_id, int level) { - const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; if (level == 0 && pipe_wm->use_sagv_wm) @@ -5572,21 +5571,17 @@ void skl_write_plane_wm(struct intel_plane *plane, int level, max_level = ilk_wm_max_level(dev_priv); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - const struct skl_plane_wm *wm = - &crtc_state->wm.skl.optimal.planes[plane_id]; + const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; + const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; const struct skl_ddb_entry *ddb_y = &crtc_state->wm.skl.plane_ddb_y[plane_id]; const struct skl_ddb_entry *ddb_uv = &crtc_state->wm.skl.plane_ddb_uv[plane_id]; - for (level = 0; level <= max_level; level++) { - const struct skl_wm_level *wm_level; - - wm_level = skl_plane_wm_level(crtc_state, plane_id, level); - + for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, PLANE_WM(pipe, plane_id, level), - wm_level); - } + skl_plane_wm_level(pipe_wm, plane_id, level)); + skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id), &wm->trans_wm); @@ -5612,19 +5607,15 @@ void skl_write_cursor_wm(struct intel_plane *plane, int level, max_level = ilk_wm_max_level(dev_priv); enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; - const struct skl_plane_wm *wm = - &crtc_state->wm.skl.optimal.planes[plane_id]; + const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; + const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; const struct skl_ddb_entry *ddb = &crtc_state->wm.skl.plane_ddb_y[plane_id]; - for (level = 0; level <= max_level; level++) { - const struct skl_wm_level *wm_level; - - wm_level = skl_plane_wm_level(crtc_state, plane_id, level); - + for (level = 0; level <= max_level; level++) skl_write_wm_level(dev_priv, CUR_WM(pipe, level), - wm_level); - } + skl_plane_wm_level(pipe_wm, plane_id, level)); + skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm); skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb); @@ -5964,6 +5955,29 @@ skl_print_wm_changes(struct intel_atomic_state *state) } } +static bool skl_plane_selected_wm_equals(struct intel_plane *plane, + const struct skl_pipe_wm *old_pipe_wm, + const struct skl_pipe_wm *new_pipe_wm) +{ + const struct skl_plane_wm *old_wm = &old_pipe_wm->planes[plane->id]; + const struct skl_plane_wm *new_wm = &new_pipe_wm->planes[plane->id]; + struct drm_i915_private *i915 = to_i915(plane->base.dev); + int level, max_level = ilk_wm_max_level(i915); + + for (level = 0; level <= max_level; level++) { + /* + * We don't check uv_wm as the hardware doesn't actually + * use it. It only gets used for calculating the required + * ddb allocation. + */ + if (!skl_wm_level_equals(skl_plane_wm_level(old_pipe_wm, level, plane->id), + skl_plane_wm_level(new_pipe_wm, level, plane->id))) + return false; + } + + return skl_wm_level_equals(&old_wm->trans_wm, &new_wm->trans_wm); +} + /* * To make sure the cursor watermark registers are always consistent * with our computed state the following scenario needs special @@ -6009,9 +6023,9 @@ static int skl_wm_add_affected_planes(struct intel_atomic_state *state, * with the software state. */ if (!drm_atomic_crtc_needs_modeset(&new_crtc_state->uapi) && - skl_plane_wm_equals(dev_priv, - &old_crtc_state->wm.skl.optimal.planes[plane_id], - &new_crtc_state->wm.skl.optimal.planes[plane_id])) + skl_plane_selected_wm_equals(plane, + &old_crtc_state->wm.skl.optimal, + &new_crtc_state->wm.skl.optimal)) continue; plane_state = intel_atomic_get_plane_state(state, plane); From df4a50a35e2cae77b51ca5e39a19a61272055117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:31:59 +0200 Subject: [PATCH 113/142] drm/i915: Zero out SAGV wm when we don't have enough DDB for it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's handle the SAGV WM0 more like the other wm levels and just totally zero it out when we don't have the DDB space to back it up. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2d0e3e7f11b87..c341fa957884c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3921,12 +3921,10 @@ static bool tgl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) return true; for_each_plane_id_on_crtc(crtc, plane_id) { - const struct skl_ddb_entry *plane_alloc = - &crtc_state->wm.skl.plane_ddb_y[plane_id]; const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (skl_ddb_entry_size(plane_alloc) < wm->sagv_wm0.min_ddb_alloc) + if (wm->wm[0].plane_en && !wm->sagv_wm0.plane_en) return false; } @@ -4957,8 +4955,8 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, } /* - * Go back and disable the transition watermark if it turns out we - * don't have enough DDB blocks for it. + * Go back and disable the transition and SAGV watermarks + * if it turns out we don't have enough DDB blocks for them. */ for_each_plane_id_on_crtc(crtc, plane_id) { struct skl_plane_wm *wm = @@ -4966,6 +4964,9 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, if (wm->trans_wm.plane_res_b >= total[plane_id]) memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); + + if (wm->sagv_wm0.plane_res_b >= total[plane_id]) + memset(&wm->sagv_wm0, 0, sizeof(wm->sagv_wm0)); } return 0; From f11449d28ce92859008f728e7a6b39f36cc7773c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:32:00 +0200 Subject: [PATCH 114/142] drm/i915: Print wm changes if sagv_wm0 changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's consider sagv_wm0 as well when deciding whether to dump out the watermark changes. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-4-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c341fa957884c..06c54adc609a7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5647,7 +5647,8 @@ static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv, return false; } - return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm); + return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm) && + skl_wm_level_equals(&wm1->sagv_wm0, &wm2->sagv_wm0); } static bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a, From a68aa48d4ed848bfc0f4edb5e3bb23eae50abcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:32:01 +0200 Subject: [PATCH 115/142] drm/i915: Stuff SAGV watermark into a sub-structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll want a SAGV transition watermark as well. Prepare for that by collecting SAGV wm0 into a sub-strcture. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-5-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 4 +-- .../drm/i915/display/intel_display_types.h | 4 ++- drivers/gpu/drm/i915/intel_pm.c | 30 +++++++++---------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index d7151a934e4cf..0b4e226806f6a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9400,7 +9400,7 @@ static void verify_wm_state(struct intel_crtc *crtc, if (skl_wm_level_equals(&hw_plane_wm->wm[level], &sw_plane_wm->wm[level]) || (level == 0 && skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->sagv_wm0))) + &sw_plane_wm->sagv.wm0))) continue; drm_err(&dev_priv->drm, @@ -9457,7 +9457,7 @@ static void verify_wm_state(struct intel_crtc *crtc, if (skl_wm_level_equals(&hw_plane_wm->wm[level], &sw_plane_wm->wm[level]) || (level == 0 && skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->sagv_wm0))) + &sw_plane_wm->sagv.wm0))) continue; drm_err(&dev_priv->drm, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 1a76e1d9de7ad..6321cd3df81eb 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -732,7 +732,9 @@ struct skl_plane_wm { struct skl_wm_level wm[8]; struct skl_wm_level uv_wm[8]; struct skl_wm_level trans_wm; - struct skl_wm_level sagv_wm0; + struct { + struct skl_wm_level wm0; + } sagv; bool is_planar; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 06c54adc609a7..a1591d9189a06 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3924,7 +3924,7 @@ static bool tgl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (wm->wm[0].plane_en && !wm->sagv_wm0.plane_en) + if (wm->wm[0].plane_en && !wm->sagv.wm0.plane_en) return false; } @@ -4753,7 +4753,7 @@ skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; if (level == 0 && pipe_wm->use_sagv_wm) - return &wm->sagv_wm0; + return &wm->sagv.wm0; return &wm->wm[level]; } @@ -4965,8 +4965,8 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, if (wm->trans_wm.plane_res_b >= total[plane_id]) memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); - if (wm->sagv_wm0.plane_res_b >= total[plane_id]) - memset(&wm->sagv_wm0, 0, sizeof(wm->sagv_wm0)); + if (wm->sagv.wm0.plane_res_b >= total[plane_id]) + memset(&wm->sagv.wm0, 0, sizeof(wm->sagv.wm0)); } return 0; @@ -5316,7 +5316,7 @@ static void tgl_compute_sagv_wm(const struct intel_crtc_state *crtc_state, struct skl_plane_wm *plane_wm) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - struct skl_wm_level *sagv_wm = &plane_wm->sagv_wm0; + struct skl_wm_level *sagv_wm = &plane_wm->sagv.wm0; struct skl_wm_level *levels = plane_wm->wm; unsigned int latency = dev_priv->wm.skl_latency[0] + dev_priv->sagv_block_time_us; @@ -5648,7 +5648,7 @@ static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv, } return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm) && - skl_wm_level_equals(&wm1->sagv_wm0, &wm2->sagv_wm0); + skl_wm_level_equals(&wm1->sagv.wm0, &wm2->sagv.wm0); } static bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a, @@ -5886,13 +5886,13 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(old_wm->wm[4].plane_en), enast(old_wm->wm[5].plane_en), enast(old_wm->wm[6].plane_en), enast(old_wm->wm[7].plane_en), enast(old_wm->trans_wm.plane_en), - enast(old_wm->sagv_wm0.plane_en), + enast(old_wm->sagv.wm0.plane_en), enast(new_wm->wm[0].plane_en), enast(new_wm->wm[1].plane_en), enast(new_wm->wm[2].plane_en), enast(new_wm->wm[3].plane_en), enast(new_wm->wm[4].plane_en), enast(new_wm->wm[5].plane_en), enast(new_wm->wm[6].plane_en), enast(new_wm->wm[7].plane_en), enast(new_wm->trans_wm.plane_en), - enast(new_wm->sagv_wm0.plane_en)); + enast(new_wm->sagv.wm0.plane_en)); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d" @@ -5907,7 +5907,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].plane_res_l, enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].plane_res_l, enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.plane_res_l, - enast(old_wm->sagv_wm0.ignore_lines), old_wm->sagv_wm0.plane_res_l, + enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.plane_res_l, enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].plane_res_l, enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].plane_res_l, @@ -5918,7 +5918,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].plane_res_l, enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].plane_res_l, enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.plane_res_l, - enast(new_wm->sagv_wm0.ignore_lines), new_wm->sagv_wm0.plane_res_l); + enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.plane_res_l); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d" @@ -5929,13 +5929,13 @@ skl_print_wm_changes(struct intel_atomic_state *state) old_wm->wm[4].plane_res_b, old_wm->wm[5].plane_res_b, old_wm->wm[6].plane_res_b, old_wm->wm[7].plane_res_b, old_wm->trans_wm.plane_res_b, - old_wm->sagv_wm0.plane_res_b, + old_wm->sagv.wm0.plane_res_b, new_wm->wm[0].plane_res_b, new_wm->wm[1].plane_res_b, new_wm->wm[2].plane_res_b, new_wm->wm[3].plane_res_b, new_wm->wm[4].plane_res_b, new_wm->wm[5].plane_res_b, new_wm->wm[6].plane_res_b, new_wm->wm[7].plane_res_b, new_wm->trans_wm.plane_res_b, - new_wm->sagv_wm0.plane_res_b); + new_wm->sagv.wm0.plane_res_b); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d" @@ -5946,13 +5946,13 @@ skl_print_wm_changes(struct intel_atomic_state *state) old_wm->wm[4].min_ddb_alloc, old_wm->wm[5].min_ddb_alloc, old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc, old_wm->trans_wm.min_ddb_alloc, - old_wm->sagv_wm0.min_ddb_alloc, + old_wm->sagv.wm0.min_ddb_alloc, new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc, new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc, new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc, new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc, new_wm->trans_wm.min_ddb_alloc, - new_wm->sagv_wm0.min_ddb_alloc); + new_wm->sagv.wm0.min_ddb_alloc); } } } @@ -6189,7 +6189,7 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, } if (INTEL_GEN(dev_priv) >= 12) - wm->sagv_wm0 = wm->wm[0]; + wm->sagv.wm0 = wm->wm[0]; if (plane_id != PLANE_CURSOR) val = intel_uncore_read(&dev_priv->uncore, PLANE_WM_TRANS(pipe, plane_id)); From 5f25e6a4afd8a5b9b5f4f4a3b31e7a3f55a4a1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:32:02 +0200 Subject: [PATCH 116/142] drm/i915: Introduce SAGV transtion watermark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seems to me that if we calculate WM0 using the bumped up SAGV latency we need to calculate the transition watermark accordingly. Track it alongside the other watermarks. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 4 +- .../drm/i915/display/intel_display_types.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 94 ++++++++++++------- 3 files changed, 65 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0b4e226806f6a..0bce9b1be86af 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9472,7 +9472,9 @@ static void verify_wm_state(struct intel_crtc *crtc, } if (!skl_wm_level_equals(&hw_plane_wm->trans_wm, - &sw_plane_wm->trans_wm)) { + &sw_plane_wm->trans_wm) && + !skl_wm_level_equals(&hw_plane_wm->trans_wm, + &sw_plane_wm->sagv.trans_wm)) { drm_err(&dev_priv->drm, "mismatch in trans WM pipe %c cursor (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", pipe_name(pipe), diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 6321cd3df81eb..e2365f2d07cc4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -734,6 +734,7 @@ struct skl_plane_wm { struct skl_wm_level trans_wm; struct { struct skl_wm_level wm0; + struct skl_wm_level trans_wm; } sagv; bool is_planar; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1591d9189a06..9d9ba63fc3950 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4758,6 +4758,18 @@ skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, return &wm->wm[level]; } +static const struct skl_wm_level * +skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, + enum plane_id plane_id) +{ + const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; + + if (pipe_wm->use_sagv_wm) + return &wm->sagv.trans_wm; + + return &wm->trans_wm; +} + static int skl_allocate_plane_ddb(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -4967,6 +4979,9 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, if (wm->sagv.wm0.plane_res_b >= total[plane_id]) memset(&wm->sagv.wm0, 0, sizeof(wm->sagv.wm0)); + + if (wm->sagv.trans_wm.plane_res_b >= total[plane_id]) + memset(&wm->sagv.trans_wm, 0, sizeof(wm->sagv.trans_wm)); } return 0; @@ -5325,12 +5340,11 @@ static void tgl_compute_sagv_wm(const struct intel_crtc_state *crtc_state, sagv_wm); } -static void skl_compute_transition_wm(const struct intel_crtc_state *crtc_state, - const struct skl_wm_params *wp, - struct skl_plane_wm *wm) +static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, + struct skl_wm_level *trans_wm, + const struct skl_wm_level *wm0, + const struct skl_wm_params *wp) { - struct drm_device *dev = crtc_state->uapi.crtc->dev; - const struct drm_i915_private *dev_priv = to_i915(dev); u16 trans_min, trans_amount, trans_y_tile_min; u16 wm0_sel_res_b, trans_offset_b, res_blocks; @@ -5368,7 +5382,7 @@ static void skl_compute_transition_wm(const struct intel_crtc_state *crtc_state, * Result Blocks is Result Blocks minus 1 and it should work for the * current platforms. */ - wm0_sel_res_b = wm->wm[0].plane_res_b - 1; + wm0_sel_res_b = wm0->plane_res_b - 1; if (wp->y_tiled) { trans_y_tile_min = @@ -5384,8 +5398,8 @@ static void skl_compute_transition_wm(const struct intel_crtc_state *crtc_state, * computing the DDB we'll come back and disable it if that * assumption turns out to be false. */ - wm->trans_wm.plane_res_b = res_blocks + 1; - wm->trans_wm.plane_en = true; + trans_wm->plane_res_b = res_blocks + 1; + trans_wm->plane_en = true; } static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, @@ -5405,10 +5419,15 @@ static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, skl_compute_wm_levels(crtc_state, &wm_params, wm->wm); - if (INTEL_GEN(dev_priv) >= 12) + skl_compute_transition_wm(dev_priv, &wm->trans_wm, + &wm->wm[0], &wm_params); + + if (INTEL_GEN(dev_priv) >= 12) { tgl_compute_sagv_wm(crtc_state, &wm_params, wm); - skl_compute_transition_wm(crtc_state, &wm_params, wm); + skl_compute_transition_wm(dev_priv, &wm->sagv.trans_wm, + &wm->sagv.wm0, &wm_params); + } return 0; } @@ -5584,7 +5603,7 @@ void skl_write_plane_wm(struct intel_plane *plane, skl_plane_wm_level(pipe_wm, plane_id, level)); skl_write_wm_level(dev_priv, PLANE_WM_TRANS(pipe, plane_id), - &wm->trans_wm); + skl_plane_trans_wm(pipe_wm, plane_id)); if (INTEL_GEN(dev_priv) >= 11) { skl_ddb_entry_write(dev_priv, @@ -5609,7 +5628,6 @@ void skl_write_cursor_wm(struct intel_plane *plane, enum plane_id plane_id = plane->id; enum pipe pipe = plane->pipe; const struct skl_pipe_wm *pipe_wm = &crtc_state->wm.skl.optimal; - const struct skl_plane_wm *wm = &pipe_wm->planes[plane_id]; const struct skl_ddb_entry *ddb = &crtc_state->wm.skl.plane_ddb_y[plane_id]; @@ -5617,7 +5635,8 @@ void skl_write_cursor_wm(struct intel_plane *plane, skl_write_wm_level(dev_priv, CUR_WM(pipe, level), skl_plane_wm_level(pipe_wm, plane_id, level)); - skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), &wm->trans_wm); + skl_write_wm_level(dev_priv, CUR_WM_TRANS(pipe), + skl_plane_trans_wm(pipe_wm, plane_id)); skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe), ddb); } @@ -5648,7 +5667,8 @@ static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv, } return skl_wm_level_equals(&wm1->trans_wm, &wm2->trans_wm) && - skl_wm_level_equals(&wm1->sagv.wm0, &wm2->sagv.wm0); + skl_wm_level_equals(&wm1->sagv.wm0, &wm2->sagv.wm0) && + skl_wm_level_equals(&wm1->sagv.trans_wm, &wm2->sagv.trans_wm); } static bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a, @@ -5878,8 +5898,8 @@ skl_print_wm_changes(struct intel_atomic_state *state) continue; drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm" - " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm\n", + "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" + " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n", plane->base.base.id, plane->base.name, enast(old_wm->wm[0].plane_en), enast(old_wm->wm[1].plane_en), enast(old_wm->wm[2].plane_en), enast(old_wm->wm[3].plane_en), @@ -5887,16 +5907,18 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(old_wm->wm[6].plane_en), enast(old_wm->wm[7].plane_en), enast(old_wm->trans_wm.plane_en), enast(old_wm->sagv.wm0.plane_en), + enast(old_wm->sagv.trans_wm.plane_en), enast(new_wm->wm[0].plane_en), enast(new_wm->wm[1].plane_en), enast(new_wm->wm[2].plane_en), enast(new_wm->wm[3].plane_en), enast(new_wm->wm[4].plane_en), enast(new_wm->wm[5].plane_en), enast(new_wm->wm[6].plane_en), enast(new_wm->wm[7].plane_en), enast(new_wm->trans_wm.plane_en), - enast(new_wm->sagv.wm0.plane_en)); + enast(new_wm->sagv.wm0.plane_en), + enast(new_wm->sagv.trans_wm.plane_en)); drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d" - " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d\n", + "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" + " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n", plane->base.base.id, plane->base.name, enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].plane_res_l, enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].plane_res_l, @@ -5908,7 +5930,7 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].plane_res_l, enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.plane_res_l, enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.plane_res_l, - + enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.plane_res_l, enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].plane_res_l, enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].plane_res_l, enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].plane_res_l, @@ -5918,11 +5940,12 @@ skl_print_wm_changes(struct intel_atomic_state *state) enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].plane_res_l, enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].plane_res_l, enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.plane_res_l, - enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.plane_res_l); + enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.plane_res_l, + enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.plane_res_l); drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d" - " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n", + "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", plane->base.base.id, plane->base.name, old_wm->wm[0].plane_res_b, old_wm->wm[1].plane_res_b, old_wm->wm[2].plane_res_b, old_wm->wm[3].plane_res_b, @@ -5930,16 +5953,18 @@ skl_print_wm_changes(struct intel_atomic_state *state) old_wm->wm[6].plane_res_b, old_wm->wm[7].plane_res_b, old_wm->trans_wm.plane_res_b, old_wm->sagv.wm0.plane_res_b, + old_wm->sagv.trans_wm.plane_res_b, new_wm->wm[0].plane_res_b, new_wm->wm[1].plane_res_b, new_wm->wm[2].plane_res_b, new_wm->wm[3].plane_res_b, new_wm->wm[4].plane_res_b, new_wm->wm[5].plane_res_b, new_wm->wm[6].plane_res_b, new_wm->wm[7].plane_res_b, new_wm->trans_wm.plane_res_b, - new_wm->sagv.wm0.plane_res_b); + new_wm->sagv.wm0.plane_res_b, + new_wm->sagv.trans_wm.plane_res_b); drm_dbg_kms(&dev_priv->drm, - "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d" - " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\n", + "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" + " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", plane->base.base.id, plane->base.name, old_wm->wm[0].min_ddb_alloc, old_wm->wm[1].min_ddb_alloc, old_wm->wm[2].min_ddb_alloc, old_wm->wm[3].min_ddb_alloc, @@ -5947,12 +5972,14 @@ skl_print_wm_changes(struct intel_atomic_state *state) old_wm->wm[6].min_ddb_alloc, old_wm->wm[7].min_ddb_alloc, old_wm->trans_wm.min_ddb_alloc, old_wm->sagv.wm0.min_ddb_alloc, + old_wm->sagv.trans_wm.min_ddb_alloc, new_wm->wm[0].min_ddb_alloc, new_wm->wm[1].min_ddb_alloc, new_wm->wm[2].min_ddb_alloc, new_wm->wm[3].min_ddb_alloc, new_wm->wm[4].min_ddb_alloc, new_wm->wm[5].min_ddb_alloc, new_wm->wm[6].min_ddb_alloc, new_wm->wm[7].min_ddb_alloc, new_wm->trans_wm.min_ddb_alloc, - new_wm->sagv.wm0.min_ddb_alloc); + new_wm->sagv.wm0.min_ddb_alloc, + new_wm->sagv.trans_wm.min_ddb_alloc); } } } @@ -5961,8 +5988,6 @@ static bool skl_plane_selected_wm_equals(struct intel_plane *plane, const struct skl_pipe_wm *old_pipe_wm, const struct skl_pipe_wm *new_pipe_wm) { - const struct skl_plane_wm *old_wm = &old_pipe_wm->planes[plane->id]; - const struct skl_plane_wm *new_wm = &new_pipe_wm->planes[plane->id]; struct drm_i915_private *i915 = to_i915(plane->base.dev); int level, max_level = ilk_wm_max_level(i915); @@ -5977,7 +6002,8 @@ static bool skl_plane_selected_wm_equals(struct intel_plane *plane, return false; } - return skl_wm_level_equals(&old_wm->trans_wm, &new_wm->trans_wm); + return skl_wm_level_equals(skl_plane_trans_wm(old_pipe_wm, plane->id), + skl_plane_trans_wm(new_pipe_wm, plane->id)); } /* @@ -6188,15 +6214,17 @@ void skl_pipe_wm_get_hw_state(struct intel_crtc *crtc, skl_wm_level_from_reg_val(val, &wm->wm[level]); } - if (INTEL_GEN(dev_priv) >= 12) - wm->sagv.wm0 = wm->wm[0]; - if (plane_id != PLANE_CURSOR) val = intel_uncore_read(&dev_priv->uncore, PLANE_WM_TRANS(pipe, plane_id)); else val = intel_uncore_read(&dev_priv->uncore, CUR_WM_TRANS(pipe)); skl_wm_level_from_reg_val(val, &wm->trans_wm); + + if (INTEL_GEN(dev_priv) >= 12) { + wm->sagv.wm0 = wm->wm[0]; + wm->sagv.trans_wm = wm->trans_wm; + } } } From 5516e89d18f3aeaaf6bdf2db8d767065e77b6a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:32:03 +0200 Subject: [PATCH 117/142] drm/i915: Check tgl+ SAGV watermarks properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We know which WM0 (normal vs. SAGV) we supposedly programmed into the hardware, so just check against that instead of accepting either watermark as valid. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-7-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 88 +++++++++----------- drivers/gpu/drm/i915/intel_pm.c | 4 +- drivers/gpu/drm/i915/intel_pm.h | 5 ++ 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0bce9b1be86af..bb702111adc5c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9390,41 +9390,40 @@ static void verify_wm_state(struct intel_crtc *crtc, /* planes */ for_each_universal_plane(dev_priv, pipe, plane) { - struct skl_plane_wm *hw_plane_wm, *sw_plane_wm; - - hw_plane_wm = &hw->wm.planes[plane]; - sw_plane_wm = &sw_wm->planes[plane]; + const struct skl_wm_level *hw_wm_level, *sw_wm_level; /* Watermarks */ for (level = 0; level <= max_level; level++) { - if (skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->wm[level]) || - (level == 0 && skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->sagv.wm0))) + hw_wm_level = &hw->wm.planes[plane].wm[level]; + sw_wm_level = skl_plane_wm_level(sw_wm, plane, level); + + if (skl_wm_level_equals(hw_wm_level, sw_wm_level)) continue; drm_err(&dev_priv->drm, "mismatch in WM pipe %c plane %d level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", pipe_name(pipe), plane + 1, level, - sw_plane_wm->wm[level].plane_en, - sw_plane_wm->wm[level].plane_res_b, - sw_plane_wm->wm[level].plane_res_l, - hw_plane_wm->wm[level].plane_en, - hw_plane_wm->wm[level].plane_res_b, - hw_plane_wm->wm[level].plane_res_l); + sw_wm_level->plane_en, + sw_wm_level->plane_res_b, + sw_wm_level->plane_res_l, + hw_wm_level->plane_en, + hw_wm_level->plane_res_b, + hw_wm_level->plane_res_l); } - if (!skl_wm_level_equals(&hw_plane_wm->trans_wm, - &sw_plane_wm->trans_wm)) { + hw_wm_level = &hw->wm.planes[plane].trans_wm; + sw_wm_level = skl_plane_trans_wm(sw_wm, plane); + + if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { drm_err(&dev_priv->drm, "mismatch in trans WM pipe %c plane %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", pipe_name(pipe), plane + 1, - sw_plane_wm->trans_wm.plane_en, - sw_plane_wm->trans_wm.plane_res_b, - sw_plane_wm->trans_wm.plane_res_l, - hw_plane_wm->trans_wm.plane_en, - hw_plane_wm->trans_wm.plane_res_b, - hw_plane_wm->trans_wm.plane_res_l); + sw_wm_level->plane_en, + sw_wm_level->plane_res_b, + sw_wm_level->plane_res_l, + hw_wm_level->plane_en, + hw_wm_level->plane_res_b, + hw_wm_level->plane_res_l); } /* DDB */ @@ -9447,43 +9446,36 @@ static void verify_wm_state(struct intel_crtc *crtc, * once the plane becomes visible, we can skip this check */ if (1) { - struct skl_plane_wm *hw_plane_wm, *sw_plane_wm; - - hw_plane_wm = &hw->wm.planes[PLANE_CURSOR]; - sw_plane_wm = &sw_wm->planes[PLANE_CURSOR]; + const struct skl_wm_level *hw_wm_level, *sw_wm_level; /* Watermarks */ for (level = 0; level <= max_level; level++) { - if (skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->wm[level]) || - (level == 0 && skl_wm_level_equals(&hw_plane_wm->wm[level], - &sw_plane_wm->sagv.wm0))) - continue; - + hw_wm_level = &hw->wm.planes[PLANE_CURSOR].wm[level]; + sw_wm_level = skl_plane_wm_level(sw_wm, PLANE_CURSOR, level); drm_err(&dev_priv->drm, "mismatch in WM pipe %c cursor level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", pipe_name(pipe), level, - sw_plane_wm->wm[level].plane_en, - sw_plane_wm->wm[level].plane_res_b, - sw_plane_wm->wm[level].plane_res_l, - hw_plane_wm->wm[level].plane_en, - hw_plane_wm->wm[level].plane_res_b, - hw_plane_wm->wm[level].plane_res_l); + sw_wm_level->plane_en, + sw_wm_level->plane_res_b, + sw_wm_level->plane_res_l, + hw_wm_level->plane_en, + hw_wm_level->plane_res_b, + hw_wm_level->plane_res_l); } - if (!skl_wm_level_equals(&hw_plane_wm->trans_wm, - &sw_plane_wm->trans_wm) && - !skl_wm_level_equals(&hw_plane_wm->trans_wm, - &sw_plane_wm->sagv.trans_wm)) { + hw_wm_level = &hw->wm.planes[PLANE_CURSOR].trans_wm; + sw_wm_level = skl_plane_trans_wm(sw_wm, PLANE_CURSOR); + + if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { drm_err(&dev_priv->drm, "mismatch in trans WM pipe %c cursor (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", pipe_name(pipe), - sw_plane_wm->trans_wm.plane_en, - sw_plane_wm->trans_wm.plane_res_b, - sw_plane_wm->trans_wm.plane_res_l, - hw_plane_wm->trans_wm.plane_en, - hw_plane_wm->trans_wm.plane_res_b, - hw_plane_wm->trans_wm.plane_res_l); + sw_wm_level->plane_en, + sw_wm_level->plane_res_b, + sw_wm_level->plane_res_l, + hw_wm_level->plane_en, + hw_wm_level->plane_res_b, + hw_wm_level->plane_res_l); } /* DDB */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9d9ba63fc3950..854ffecd98d9c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4745,7 +4745,7 @@ icl_get_total_relative_data_rate(struct intel_atomic_state *state, return total_data_rate; } -static const struct skl_wm_level * +const struct skl_wm_level * skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, enum plane_id plane_id, int level) @@ -4758,7 +4758,7 @@ skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, return &wm->wm[level]; } -static const struct skl_wm_level * +const struct skl_wm_level * skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, enum plane_id plane_id) { diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index 97550cf0b6df0..669c8d5056778 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -52,6 +52,11 @@ bool intel_can_enable_sagv(struct drm_i915_private *dev_priv, const struct intel_bw_state *bw_state); void intel_sagv_pre_plane_update(struct intel_atomic_state *state); void intel_sagv_post_plane_update(struct intel_atomic_state *state); +const struct skl_wm_level *skl_plane_wm_level(const struct skl_pipe_wm *pipe_wm, + enum plane_id plane_id, + int level); +const struct skl_wm_level *skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, + enum plane_id plane_id); bool skl_wm_level_equals(const struct skl_wm_level *l1, const struct skl_wm_level *l2); bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry *ddb, From a49388bd2b75fc7529481b291925a431ecaef65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 26 Feb 2021 17:32:04 +0200 Subject: [PATCH 118/142] drm/i915: Clean up verify_wm_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the nonsense cursor special case in verify_wm_state() by just iterating through all the planes. And let's use the canonical [PLANE:..] style in the debug prints while at it. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210226153204.1270-8-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 88 ++++---------------- drivers/gpu/drm/i915/display/intel_display.h | 5 -- 2 files changed, 17 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index bb702111adc5c..e405fe0336dca 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9361,11 +9361,10 @@ static void verify_wm_state(struct intel_crtc *crtc, struct skl_ddb_entry ddb_uv[I915_MAX_PLANES]; struct skl_pipe_wm wm; } *hw; - struct skl_pipe_wm *sw_wm; - struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry; + const struct skl_pipe_wm *sw_wm = &new_crtc_state->wm.skl.optimal; + int level, max_level = ilk_wm_max_level(dev_priv); + struct intel_plane *plane; u8 hw_enabled_slices; - const enum pipe pipe = crtc->pipe; - int plane, level, max_level = ilk_wm_max_level(dev_priv); if (INTEL_GEN(dev_priv) < 9 || !new_crtc_state->hw.active) return; @@ -9375,7 +9374,6 @@ static void verify_wm_state(struct intel_crtc *crtc, return; skl_pipe_wm_get_hw_state(crtc, &hw->wm); - sw_wm = &new_crtc_state->wm.skl.optimal; skl_pipe_ddb_get_hw_state(crtc, hw->ddb_y, hw->ddb_uv); @@ -9388,73 +9386,21 @@ static void verify_wm_state(struct intel_crtc *crtc, dev_priv->dbuf.enabled_slices, hw_enabled_slices); - /* planes */ - for_each_universal_plane(dev_priv, pipe, plane) { + for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { + const struct skl_ddb_entry *hw_ddb_entry, *sw_ddb_entry; const struct skl_wm_level *hw_wm_level, *sw_wm_level; /* Watermarks */ for (level = 0; level <= max_level; level++) { - hw_wm_level = &hw->wm.planes[plane].wm[level]; - sw_wm_level = skl_plane_wm_level(sw_wm, plane, level); + hw_wm_level = &hw->wm.planes[plane->id].wm[level]; + sw_wm_level = skl_plane_wm_level(sw_wm, plane->id, level); if (skl_wm_level_equals(hw_wm_level, sw_wm_level)) continue; drm_err(&dev_priv->drm, - "mismatch in WM pipe %c plane %d level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", - pipe_name(pipe), plane + 1, level, - sw_wm_level->plane_en, - sw_wm_level->plane_res_b, - sw_wm_level->plane_res_l, - hw_wm_level->plane_en, - hw_wm_level->plane_res_b, - hw_wm_level->plane_res_l); - } - - hw_wm_level = &hw->wm.planes[plane].trans_wm; - sw_wm_level = skl_plane_trans_wm(sw_wm, plane); - - if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { - drm_err(&dev_priv->drm, - "mismatch in trans WM pipe %c plane %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", - pipe_name(pipe), plane + 1, - sw_wm_level->plane_en, - sw_wm_level->plane_res_b, - sw_wm_level->plane_res_l, - hw_wm_level->plane_en, - hw_wm_level->plane_res_b, - hw_wm_level->plane_res_l); - } - - /* DDB */ - hw_ddb_entry = &hw->ddb_y[plane]; - sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[plane]; - - if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { - drm_err(&dev_priv->drm, - "mismatch in DDB state pipe %c plane %d (expected (%u,%u), found (%u,%u))\n", - pipe_name(pipe), plane + 1, - sw_ddb_entry->start, sw_ddb_entry->end, - hw_ddb_entry->start, hw_ddb_entry->end); - } - } - - /* - * cursor - * If the cursor plane isn't active, we may not have updated it's ddb - * allocation. In that case since the ddb allocation will be updated - * once the plane becomes visible, we can skip this check - */ - if (1) { - const struct skl_wm_level *hw_wm_level, *sw_wm_level; - - /* Watermarks */ - for (level = 0; level <= max_level; level++) { - hw_wm_level = &hw->wm.planes[PLANE_CURSOR].wm[level]; - sw_wm_level = skl_plane_wm_level(sw_wm, PLANE_CURSOR, level); - drm_err(&dev_priv->drm, - "mismatch in WM pipe %c cursor level %d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", - pipe_name(pipe), level, + "[PLANE:%d:%s] mismatch in WM%d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", + plane->base.base.id, plane->base.name, level, sw_wm_level->plane_en, sw_wm_level->plane_res_b, sw_wm_level->plane_res_l, @@ -9463,13 +9409,13 @@ static void verify_wm_state(struct intel_crtc *crtc, hw_wm_level->plane_res_l); } - hw_wm_level = &hw->wm.planes[PLANE_CURSOR].trans_wm; - sw_wm_level = skl_plane_trans_wm(sw_wm, PLANE_CURSOR); + hw_wm_level = &hw->wm.planes[plane->id].trans_wm; + sw_wm_level = skl_plane_trans_wm(sw_wm, plane->id); if (!skl_wm_level_equals(hw_wm_level, sw_wm_level)) { drm_err(&dev_priv->drm, - "mismatch in trans WM pipe %c cursor (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", - pipe_name(pipe), + "[PLANE:%d:%s] mismatch in trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", + plane->base.base.id, plane->base.name, sw_wm_level->plane_en, sw_wm_level->plane_res_b, sw_wm_level->plane_res_l, @@ -9479,13 +9425,13 @@ static void verify_wm_state(struct intel_crtc *crtc, } /* DDB */ - hw_ddb_entry = &hw->ddb_y[PLANE_CURSOR]; - sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[PLANE_CURSOR]; + hw_ddb_entry = &hw->ddb_y[plane->id]; + sw_ddb_entry = &new_crtc_state->wm.skl.plane_ddb_y[plane->id]; if (!skl_ddb_entry_equal(hw_ddb_entry, sw_ddb_entry)) { drm_err(&dev_priv->drm, - "mismatch in DDB state pipe %c cursor (expected (%u,%u), found (%u,%u))\n", - pipe_name(pipe), + "[PLANE:%d:%s] mismatch in DDB (expected (%u,%u), found (%u,%u))\n", + plane->base.base.id, plane->base.name, sw_ddb_entry->start, sw_ddb_entry->end, hw_ddb_entry->start, hw_ddb_entry->end); } diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 0e4c1481fa009..431770eeadb47 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -353,11 +353,6 @@ enum phy_fia { for_each_cpu_transcoder(__dev_priv, __t) \ for_each_if ((__mask) & BIT(__t)) -#define for_each_universal_plane(__dev_priv, __pipe, __p) \ - for ((__p) = 0; \ - (__p) < RUNTIME_INFO(__dev_priv)->num_sprites[(__pipe)] + 1; \ - (__p)++) - #define for_each_sprite(__dev_priv, __p, __s) \ for ((__s) = 0; \ (__s) < RUNTIME_INFO(__dev_priv)->num_sprites[(__p)]; \ From 5b616a2958da0c75a6083e82859ca33be7662562 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 2 Mar 2021 13:02:59 +0200 Subject: [PATCH 119/142] drm/i915/mso: add splitter state readout for platforms that support it Add splitter configuration to crtc state, and read it where supported. Also add splitter state dumping. The stream splitter will be required for eDP MSO. v4: - Catch invalid splitter configuration (Uma) v3: - Convert segment timings to full panel timings. - Refer to splitter instead of mso in crtc state. - Dump splitter state. v2: Add warning for mso being enabled on pipes other than A. Cc: Nischal Varide Cc: Uma Shankar Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/95cbe1c9d45edf3e3ec252e49fb49055def98155.1614682842.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 41 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_display.c | 31 +++++++++++++- .../drm/i915/display/intel_display_types.h | 7 ++++ drivers/gpu/drm/i915/i915_drv.h | 2 + 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index eeae78097a20b..d4cfe7e85538f 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2136,6 +2136,45 @@ static void intel_ddi_power_up_lanes(struct intel_encoder *encoder, } } +static void intel_ddi_mso_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) +{ + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + u32 dss1; + + if (!HAS_MSO(i915)) + return; + + dss1 = intel_de_read(i915, ICL_PIPE_DSS_CTL1(pipe)); + + pipe_config->splitter.enable = dss1 & SPLITTER_ENABLE; + if (!pipe_config->splitter.enable) + return; + + /* Splitter enable is supported for pipe A only. */ + if (drm_WARN_ON(&i915->drm, pipe != PIPE_A)) { + pipe_config->splitter.enable = false; + return; + } + + switch (dss1 & SPLITTER_CONFIGURATION_MASK) { + default: + drm_WARN(&i915->drm, true, + "Invalid splitter configuration, dss1=0x%08x\n", dss1); + fallthrough; + case SPLITTER_CONFIGURATION_2_SEGMENT: + pipe_config->splitter.link_count = 2; + break; + case SPLITTER_CONFIGURATION_4_SEGMENT: + pipe_config->splitter.link_count = 4; + break; + } + + pipe_config->splitter.pixel_overlap = REG_FIELD_GET(OVERLAP_PIXELS_MASK, dss1); +} + static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, @@ -3316,6 +3355,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder, intel_ddi_read_func_ctl(encoder, pipe_config); } + intel_ddi_mso_get_config(encoder, pipe_config); + pipe_config->has_audio = intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index e405fe0336dca..c605d481ec02a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4862,8 +4862,30 @@ static void intel_crtc_readout_derived_state(struct intel_crtc_state *crtc_state pipe_mode->crtc_clock /= 2; } - intel_mode_from_crtc_timings(pipe_mode, pipe_mode); - intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode); + if (crtc_state->splitter.enable) { + int n = crtc_state->splitter.link_count; + int overlap = crtc_state->splitter.pixel_overlap; + + /* + * eDP MSO uses segment timings from EDID for transcoder + * timings, but full mode for everything else. + * + * h_full = (h_segment - pixel_overlap) * link_count + */ + pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n; + pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n; + pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n; + pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n; + pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n; + pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n; + pipe_mode->crtc_clock *= n; + + intel_mode_from_crtc_timings(pipe_mode, pipe_mode); + intel_mode_from_crtc_timings(adjusted_mode, pipe_mode); + } else { + intel_mode_from_crtc_timings(pipe_mode, pipe_mode); + intel_mode_from_crtc_timings(adjusted_mode, adjusted_mode); + } intel_crtc_compute_pixel_rate(crtc_state); @@ -8272,6 +8294,11 @@ static void intel_dump_pipe_config(const struct intel_crtc_state *pipe_config, pipe_config->bigjoiner_slave ? "slave" : pipe_config->bigjoiner ? "master" : "no"); + drm_dbg_kms(&dev_priv->drm, "splitter: %s, link count %d, overlap %d\n", + enableddisabled(pipe_config->splitter.enable), + pipe_config->splitter.link_count, + pipe_config->splitter.pixel_overlap); + if (pipe_config->has_pch_encoder) intel_dump_m_n_config(pipe_config, "fdi", pipe_config->fdi_lanes, diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index e2365f2d07cc4..8d9113fa82c71 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1169,6 +1169,13 @@ struct intel_crtc_state { u8 pipeline_full; u16 flipline, vmin, vmax; } vrr; + + /* Stream Splitter for eDP MSO */ + struct { + bool enable; + u8 link_count; + u8 pixel_overlap; + } splitter; }; enum intel_pipe_crc_source { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0816c39e51ddb..ea9f1d9d530d6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1705,6 +1705,8 @@ tgl_stepping_get(struct drm_i915_private *dev_priv) #define HAS_CSR(dev_priv) (INTEL_INFO(dev_priv)->display.has_csr) +#define HAS_MSO(i915) (INTEL_GEN(i915) >= 12) + #define HAS_RUNTIME_PM(dev_priv) (INTEL_INFO(dev_priv)->has_runtime_pm) #define HAS_64BIT_RELOC(dev_priv) (INTEL_INFO(dev_priv)->has_64bit_reloc) From 5bc4fab7e79206926718c3d39cb70cbee22ef4ac Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 2 Mar 2021 13:03:00 +0200 Subject: [PATCH 120/142] drm/i915/mso: add splitter state check For starters, we expect the state to be zero, as we don't enable MSO anywhere. v2: Refer to splitter. Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/459a332f3cdce941c57312150872559db68f88c1.1614682842.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c605d481ec02a..7a243a96d6efc 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9339,6 +9339,10 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(dsc.dsc_split); PIPE_CONF_CHECK_I(dsc.compressed_bpp); + PIPE_CONF_CHECK_BOOL(splitter.enable); + PIPE_CONF_CHECK_I(splitter.link_count); + PIPE_CONF_CHECK_I(splitter.pixel_overlap); + PIPE_CONF_CHECK_I(mst_master_transcoder); PIPE_CONF_CHECK_BOOL(vrr.enable); From 512005d949287c2a38f4d65f285b7fb9f8244ed0 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 2 Mar 2021 13:03:01 +0200 Subject: [PATCH 121/142] drm/i915/edp: modify fixed and downclock modes for MSO In the case of MSO (Multi-SST Operation), the EDID contains the timings for a single panel segment. We'll want to hide the fact from userspace, and expose modes that span the entire display. Don't modify the EDID, as the userspace should not use that for modesetting, only modify the actual modes. v3: Use pixel overlap if available. v2: Rename intel_dp_mso_mode_fixup -> intel_edp_mso_mode_fixup Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/2862284eb033bb0ffc96134b7d5b11bf29e4587f.1614682842.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_dp.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2ec82a5c9f24b..2d0001e7c26a2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3516,6 +3516,31 @@ static void intel_dp_get_dsc_sink_cap(struct intel_dp *intel_dp) } } +static void intel_edp_mso_mode_fixup(struct intel_connector *connector, + struct drm_display_mode *mode) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + int n = intel_dp->mso_link_count; + int overlap = intel_dp->mso_pixel_overlap; + + if (!mode || !n) + return; + + mode->hdisplay = (mode->hdisplay - overlap) * n; + mode->hsync_start = (mode->hsync_start - overlap) * n; + mode->hsync_end = (mode->hsync_end - overlap) * n; + mode->htotal = (mode->htotal - overlap) * n; + mode->clock *= n; + + drm_mode_set_name(mode); + + drm_dbg_kms(&i915->drm, + "[CONNECTOR:%d:%s] using generated MSO mode: ", + connector->base.base.id, connector->base.name); + drm_mode_debug_printmodeline(mode); +} + static void intel_edp_mso_init(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); @@ -6493,6 +6518,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (fixed_mode) downclock_mode = intel_dp_drrs_init(intel_connector, fixed_mode); + /* multiply the mode clock and horizontal timings for MSO */ + intel_edp_mso_mode_fixup(intel_connector, fixed_mode); + intel_edp_mso_mode_fixup(intel_connector, downclock_mode); + /* fallback to VBT if available for eDP */ if (!fixed_mode) fixed_mode = intel_panel_vbt_fixed_mode(intel_connector); From bc71194e889741eb54a3dcc35fc79215fa9449d2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 2 Mar 2021 13:03:02 +0200 Subject: [PATCH 122/142] drm/i915/edp: enable eDP MSO during link training If the source and sink support MSO, enable it during link training. v4: Divide DRRS pixel clock by link count before M/N calculation v3: Adjust timings, refer to splitter v2: Limit MSO to pipe A using ->pipe_mask Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/2711 Cc: Nischal Varide Reviewed-by: Uma Shankar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/66da48b4b3c5ccffaac7989097cd96d6c6af8243.1614682842.git.jani.nikula@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 37 +++++++++++++++++ drivers/gpu/drm/i915/display/intel_display.c | 13 ++++++ drivers/gpu/drm/i915/display/intel_dp.c | 43 ++++++++++++++++++-- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index d4cfe7e85538f..549e4399a0c21 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2175,6 +2175,34 @@ static void intel_ddi_mso_get_config(struct intel_encoder *encoder, pipe_config->splitter.pixel_overlap = REG_FIELD_GET(OVERLAP_PIXELS_MASK, dss1); } +static void intel_ddi_mso_configure(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); + enum pipe pipe = crtc->pipe; + u32 dss1 = 0; + + if (!HAS_MSO(i915)) + return; + + if (crtc_state->splitter.enable) { + /* Splitter enable is supported for pipe A only. */ + if (drm_WARN_ON(&i915->drm, pipe != PIPE_A)) + return; + + dss1 |= SPLITTER_ENABLE; + dss1 |= OVERLAP_PIXELS(crtc_state->splitter.pixel_overlap); + if (crtc_state->splitter.link_count == 2) + dss1 |= SPLITTER_CONFIGURATION_2_SEGMENT; + else + dss1 |= SPLITTER_CONFIGURATION_4_SEGMENT; + } + + intel_de_rmw(i915, ICL_PIPE_DSS_CTL1(pipe), + SPLITTER_ENABLE | SPLITTER_CONFIGURATION_MASK | + OVERLAP_PIXELS_MASK, dss1); +} + static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, @@ -2268,6 +2296,11 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, */ intel_ddi_power_up_lanes(encoder, crtc_state); + /* + * 7.g Program CoG/MSO configuration bits in DSS_CTL1 if selected. + */ + intel_ddi_mso_configure(crtc_state); + /* * 7.g Configure and enable DDI_BUF_CTL * 7.h Wait for DDI_BUF_CTL DDI Idle Status = 0b (Not Idle), timeout @@ -4200,6 +4233,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) goto err; dig_port->hpd_pulse = intel_dp_hpd_pulse; + + /* Splitter enable for eDP MSO is supported for pipe A only. */ + if (dig_port->dp.mso_link_count) + encoder->pipe_mask = BIT(PIPE_A); } /* In theory we don't need the encoder->type check, but leave it just in diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 7a243a96d6efc..39e8ab1408b67 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4923,6 +4923,19 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, pipe_config->pipe_src_w /= 2; } + if (pipe_config->splitter.enable) { + int n = pipe_config->splitter.link_count; + int overlap = pipe_config->splitter.pixel_overlap; + + pipe_mode->crtc_hdisplay = (pipe_mode->crtc_hdisplay - overlap) * n; + pipe_mode->crtc_hblank_start = (pipe_mode->crtc_hblank_start - overlap) * n; + pipe_mode->crtc_hblank_end = (pipe_mode->crtc_hblank_end - overlap) * n; + pipe_mode->crtc_hsync_start = (pipe_mode->crtc_hsync_start - overlap) * n; + pipe_mode->crtc_hsync_end = (pipe_mode->crtc_hsync_end - overlap) * n; + pipe_mode->crtc_htotal = (pipe_mode->crtc_htotal - overlap) * n; + pipe_mode->crtc_clock *= n; + } + intel_mode_from_crtc_timings(pipe_mode, pipe_mode); if (INTEL_GEN(dev_priv) < 4) { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2d0001e7c26a2..b6b5776f5a668 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1723,6 +1723,7 @@ intel_dp_drrs_compute_config(struct intel_dp *intel_dp, { struct intel_connector *intel_connector = intel_dp->attached_connector; struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + int pixel_clock; if (pipe_config->vrr.enable) return; @@ -1741,10 +1742,18 @@ intel_dp_drrs_compute_config(struct intel_dp *intel_dp, return; pipe_config->has_drrs = true; - intel_link_compute_m_n(output_bpp, pipe_config->lane_count, - intel_connector->panel.downclock_mode->clock, + + pixel_clock = intel_connector->panel.downclock_mode->clock; + if (pipe_config->splitter.enable) + pixel_clock /= pipe_config->splitter.link_count; + + intel_link_compute_m_n(output_bpp, pipe_config->lane_count, pixel_clock, pipe_config->port_clock, &pipe_config->dp_m2_n2, constant_n, pipe_config->fec_enable); + + /* FIXME: abstract this better */ + if (pipe_config->splitter.enable) + pipe_config->dp_m2_n2.gmch_m *= pipe_config->splitter.link_count; } int @@ -1819,6 +1828,26 @@ intel_dp_compute_config(struct intel_encoder *encoder, output_bpp = intel_dp_output_bpp(pipe_config->output_format, pipe_config->pipe_bpp); + if (intel_dp->mso_link_count) { + int n = intel_dp->mso_link_count; + int overlap = intel_dp->mso_pixel_overlap; + + pipe_config->splitter.enable = true; + pipe_config->splitter.link_count = n; + pipe_config->splitter.pixel_overlap = overlap; + + drm_dbg_kms(&dev_priv->drm, "MSO link count %d, pixel overlap %d\n", + n, overlap); + + adjusted_mode->crtc_hdisplay = adjusted_mode->crtc_hdisplay / n + overlap; + adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hblank_start / n + overlap; + adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_end / n + overlap; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hsync_start / n + overlap; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_end / n + overlap; + adjusted_mode->crtc_htotal = adjusted_mode->crtc_htotal / n + overlap; + adjusted_mode->crtc_clock /= n; + } + intel_link_compute_m_n(output_bpp, pipe_config->lane_count, adjusted_mode->crtc_clock, @@ -1826,6 +1855,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, &pipe_config->dp_m_n, constant_n, pipe_config->fec_enable); + /* FIXME: abstract this better */ + if (pipe_config->splitter.enable) + pipe_config->dp_m_n.gmch_m *= pipe_config->splitter.link_count; + if (!HAS_DDI(dev_priv)) intel_dp_set_clock(encoder, pipe_config); @@ -3564,8 +3597,10 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp) if (mso) { drm_dbg_kms(&i915->drm, "Sink MSO %ux%u configuration\n", mso, drm_dp_max_lane_count(intel_dp->dpcd) / mso); - drm_err(&i915->drm, "No source MSO support, disabling\n"); - mso = 0; + if (!HAS_MSO(i915)) { + drm_err(&i915->drm, "No source MSO support, disabling\n"); + mso = 0; + } } intel_dp->mso_link_count = mso; From e43539f87a6d7bd18c2df82130bbdeda5b399516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Mar 2021 19:04:18 +0200 Subject: [PATCH 123/142] drm/i915: Move pipe enable/disable tracepoints to intel_crtc_vblank_{on,off}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms/outputs without a working frame counter we rely on the vblank code to cook up the frame counter from the timestamps. That requires that vblank support is enabled. Thus we need to move the pipe enable/disable tracepoints to the other side of the drm_vblank_{on,off}() calls. There shouldn't really be much happening between these old and new call sites so the tracepoints should still provide reasonable data. The alternative would be to give up on having the frame counter values in the trace which would render the tracepoints more or less pointless. v2: Missed one case in intel_ddi_post_disable() Drop the now useless i915_trace.h includes Reported-by: Steven Rostedt (VMware) Tested-by: Steven Rostedt (VMware) Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210304170421.10901-2-ville.syrjala@linux.intel.com Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/display/intel_crtc.c | 14 ++++++++++++++ drivers/gpu/drm/i915/display/intel_ddi.c | 2 -- drivers/gpu/drm/i915/display/intel_display.c | 9 +-------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 88b44ac50aae1..e54f9cff518e9 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -84,12 +84,26 @@ void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state) drm_crtc_set_max_vblank_count(&crtc->base, intel_crtc_max_vblank_count(crtc_state)); drm_crtc_vblank_on(&crtc->base); + + /* + * Should really happen exactly when we enable the pipe + * but we want the frame counters in the trace, and that + * requires vblank support on some platforms/outputs. + */ + trace_intel_pipe_enable(crtc); } void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + /* + * Should really happen exactly when we disable the pipe + * but we want the frame counters in the trace, and that + * requires vblank support on some platforms/outputs. + */ + trace_intel_pipe_disable(crtc); + drm_crtc_vblank_off(&crtc->base); assert_vblank_disabled(&crtc->base); } diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 549e4399a0c21..c0ace39bbfdff 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -28,7 +28,6 @@ #include #include "i915_drv.h" -#include "i915_trace.h" #include "intel_audio.h" #include "intel_combo_phy.h" #include "intel_connector.h" @@ -2656,7 +2655,6 @@ static void intel_ddi_post_disable(struct intel_atomic_state *state, intel_atomic_get_old_crtc_state(state, slave); intel_crtc_vblank_off(old_slave_crtc_state); - trace_intel_pipe_disable(slave); intel_dsc_disable(old_slave_crtc_state); skl_scaler_disable(old_slave_crtc_state); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 39e8ab1408b67..35bd7798beffd 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -67,7 +67,6 @@ #include "gt/intel_rps.h" #include "i915_drv.h" -#include "i915_trace.h" #include "intel_acpi.h" #include "intel_atomic.h" #include "intel_atomic_plane.h" @@ -794,8 +793,6 @@ void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state) /* FIXME: assert CPU port conditions for SNB+ */ } - trace_intel_pipe_enable(crtc); - reg = PIPECONF(cpu_transcoder); val = intel_de_read(dev_priv, reg); if (val & PIPECONF_ENABLE) { @@ -835,8 +832,6 @@ void intel_disable_pipe(const struct intel_crtc_state *old_crtc_state) */ assert_planes_disabled(crtc); - trace_intel_pipe_disable(crtc); - reg = PIPECONF(cpu_transcoder); val = intel_de_read(dev_priv, reg); if ((val & PIPECONF_ENABLE) == 0) @@ -4026,10 +4021,8 @@ static void hsw_crtc_enable(struct intel_atomic_state *state, if (INTEL_GEN(dev_priv) >= 11) icl_pipe_mbus_enable(crtc); - if (new_crtc_state->bigjoiner_slave) { - trace_intel_pipe_enable(crtc); + if (new_crtc_state->bigjoiner_slave) intel_crtc_vblank_on(new_crtc_state); - } intel_encoders_enable(state, crtc); From 9bb475cd31fa6e724225841689495a9c86fac037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Mar 2021 19:04:19 +0200 Subject: [PATCH 124/142] drm/i915: Don't try to query the frame counter for disabled pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For platforms/outputs without hardware frame counters we can't call drm_crtc_accurate_vblank_count() when the vblank support is disabled or we just get a WARN due to the crtc timings (vblank->hwmode) being considered invalid. Note that until the pipe in question has been enabled and drm_crtc_set_max_vblank_count() has been called on it we would also take this path on platforms which have a working frame counter. So getting the WARN is rather likely on any platform unless you always boot with lots of displays plugged in. Also even on hardware with a working frame counter we may not be able to read the actual frame counter register on disabled pipes due the relevant power well being disabled. Ie. would just result in the unclaimed reg spew. So let's just avoid all this an directly report zero in case the pipe is disabled. Reported-by: Steven Rostedt (VMware) Tested-by: Steven Rostedt (VMware) Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210304170421.10901-3-ville.syrjala@linux.intel.com Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/display/intel_crtc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index e54f9cff518e9..c7a3e09fb425a 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -39,6 +39,9 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)]; + if (!crtc->active) + return 0; + if (!vblank->max_vblank_count) return (u32)drm_crtc_accurate_vblank_count(&crtc->base); From 2c6afc3675bc0d4e38b8b47425d8150810482874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Mar 2021 19:04:20 +0200 Subject: [PATCH 125/142] drm/i915: Return zero as the scanline counter for disabled pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We print the scanline counters as unsigned integers so the -1 here just makes the debugs/traces look a bit messy. Zero seems equally valid for this usecase. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210304170421.10901-4-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5cfaec500a603..67c6d71f26753 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -794,7 +794,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) int position, vtotal; if (!crtc->active) - return -1; + return 0; vblank = &crtc->base.dev->vblank[drm_crtc_index(&crtc->base)]; mode = &vblank->hwmode; From 603a945e55bddc9265bb40d27fd1de3ab3d0316b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Mar 2021 19:04:21 +0200 Subject: [PATCH 126/142] drm/i915: Fix DSI TE max_vblank_count handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 33267703df15 ("drm/i915/dsi: Enable software vblank counter") claims to get the mode_flags from the crtc_state, but in fact does not. Fix it to do it right. Cc: Vandita Kulkarni Cc: Jani Nikula Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210304170421.10901-5-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- drivers/gpu/drm/i915/display/intel_crtc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index c7a3e09fb425a..3248f49999bb7 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -51,8 +51,6 @@ u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc) u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - u32 mode_flags = crtc->mode_flags; /* * From Gen 11, In case of dsi cmd mode, frame counter wouldnt @@ -60,7 +58,8 @@ u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state) * the hw counter, then we would find it updated in only * the next TE, hence switching to sw counter. */ - if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1)) + if (crtc_state->mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | + I915_MODE_FLAG_DSI_USE_TE1)) return 0; /* From 356ce0ea7eb46f29fbb3061a9cccff5ab81d0378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Feb 2021 16:42:09 +0200 Subject: [PATCH 127/142] drm/i915: Call primary encoder's .get_config() from MST .get_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop assuming intel_ddi_get_config() is all we need from the primary encoder, and instead call it via the .get_config() vfunc. This will allow customized .get_config() for the primary, which I plan to use to handle the differences in the clock readout between various platforms. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210224144214.24803-2-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_dp_mst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 8e316146b6d16..906860ad8eb8a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -591,7 +591,7 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder, struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); struct intel_digital_port *dig_port = intel_mst->primary; - intel_ddi_get_config(&dig_port->base, pipe_config); + dig_port->base.get_config(&dig_port->base, pipe_config); } static bool intel_dp_mst_initial_fastset_check(struct intel_encoder *encoder, From 7d3d8f853cbe981ffe98c71328d67d3b3d16a79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 25 Feb 2021 18:12:25 +0200 Subject: [PATCH 128/142] drm/i915: Do intel_dpll_readout_hw_state() after encoder readout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clock readout for DDI encoders needs to moved into the encoders. To that end intel_dpll_readout_hw_state() needs to happen after the encoder readout as otherwise it can't correctly populate the PLL crtc_mask/active_mask bitmasks. v2: Populate DPLL ref clocks before the encoder->get_config() Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210225161225.30746-1-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_display.c | 5 +++-- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 9 ++++++--- drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 35bd7798beffd..ef5ce92819848 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -12909,6 +12909,7 @@ int intel_modeset_init_nogem(struct drm_i915_private *i915) intel_update_czclk(i915); intel_modeset_init_hw(i915); + intel_dpll_update_ref_clks(i915); intel_hdcp_component_init(i915); @@ -13445,8 +13446,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) readout_plane_state(dev_priv); - intel_dpll_readout_hw_state(dev_priv); - for_each_intel_encoder(dev, encoder) { pipe = 0; @@ -13481,6 +13480,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) pipe_name(pipe)); } + intel_dpll_readout_hw_state(dev_priv); + drm_connector_list_iter_begin(dev, &conn_iter); for_each_intel_connector_iter(connector, &conn_iter) { if (connector->get_hw_state(connector)) { diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 529b1d569af21..ac6460962e298 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -4612,12 +4612,15 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915, pll->info->name, pll->state.crtc_mask, pll->on); } -void intel_dpll_readout_hw_state(struct drm_i915_private *i915) +void intel_dpll_update_ref_clks(struct drm_i915_private *i915) { - int i; - if (i915->dpll.mgr && i915->dpll.mgr->update_ref_clks) i915->dpll.mgr->update_ref_clks(i915); +} + +void intel_dpll_readout_hw_state(struct drm_i915_private *i915) +{ + int i; for (i = 0; i < i915->dpll.num_shared_dpll; i++) readout_dpll_hw_state(i915, &i915->dpll.shared_dplls[i]); diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 2eb7618ef9571..81e67639dadb4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -410,6 +410,7 @@ void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state); void intel_shared_dpll_swap_state(struct intel_atomic_state *state); void intel_shared_dpll_init(struct drm_device *dev); +void intel_dpll_update_ref_clks(struct drm_i915_private *dev_priv); void intel_dpll_readout_hw_state(struct drm_i915_private *dev_priv); void intel_dpll_sanitize_state(struct drm_i915_private *dev_priv); From d0f1bfc615a893187bf7ba27ccde852dc83320bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Feb 2021 16:42:11 +0200 Subject: [PATCH 129/142] drm/i915: Use pipes instead crtc indices in PLL state tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the other places we have use pipes instead of crtc indices when tracking resource usage. Life is easier when we do it the same way always, so switch the dpll mgr to using pipes as well. Looks like it was actually mixing these up in some cases so it would not even have worked correctly except when the device has a contiguous set of pipes starting from pipe A. Granted, that is the typical case but supposedly it may not always hold on modern hw. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210224144214.24803-4-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_display.c | 40 ++++++++-------- .../drm/i915/display/intel_display_debugfs.c | 4 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 48 ++++++++++--------- drivers/gpu/drm/i915/display/intel_dpll_mgr.h | 8 ++-- 4 files changed, 51 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index ef5ce92819848..78817d0c82e2c 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9643,7 +9643,7 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, struct intel_crtc_state *new_crtc_state) { struct intel_dpll_hw_state dpll_hw_state; - unsigned int crtc_mask; + u8 pipe_mask; bool active; memset(&dpll_hw_state, 0, sizeof(dpll_hw_state)); @@ -9656,34 +9656,34 @@ verify_single_dpll_state(struct drm_i915_private *dev_priv, I915_STATE_WARN(!pll->on && pll->active_mask, "pll in active use but not on in sw tracking\n"); I915_STATE_WARN(pll->on && !pll->active_mask, - "pll is on but not used by any active crtc\n"); + "pll is on but not used by any active pipe\n"); I915_STATE_WARN(pll->on != active, "pll on state mismatch (expected %i, found %i)\n", pll->on, active); } if (!crtc) { - I915_STATE_WARN(pll->active_mask & ~pll->state.crtc_mask, - "more active pll users than references: %x vs %x\n", - pll->active_mask, pll->state.crtc_mask); + I915_STATE_WARN(pll->active_mask & ~pll->state.pipe_mask, + "more active pll users than references: 0x%x vs 0x%x\n", + pll->active_mask, pll->state.pipe_mask); return; } - crtc_mask = drm_crtc_mask(&crtc->base); + pipe_mask = BIT(crtc->pipe); if (new_crtc_state->hw.active) - I915_STATE_WARN(!(pll->active_mask & crtc_mask), - "pll active mismatch (expected pipe %c in active mask 0x%02x)\n", + I915_STATE_WARN(!(pll->active_mask & pipe_mask), + "pll active mismatch (expected pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); else - I915_STATE_WARN(pll->active_mask & crtc_mask, - "pll active mismatch (didn't expect pipe %c in active mask 0x%02x)\n", + I915_STATE_WARN(pll->active_mask & pipe_mask, + "pll active mismatch (didn't expect pipe %c in active mask 0x%x)\n", pipe_name(crtc->pipe), pll->active_mask); - I915_STATE_WARN(!(pll->state.crtc_mask & crtc_mask), - "pll enabled crtcs mismatch (expected 0x%x in 0x%02x)\n", - crtc_mask, pll->state.crtc_mask); + I915_STATE_WARN(!(pll->state.pipe_mask & pipe_mask), + "pll enabled crtcs mismatch (expected 0x%x in 0x%x)\n", + pipe_mask, pll->state.pipe_mask); I915_STATE_WARN(pll->on && memcmp(&pll->state.hw_state, &dpll_hw_state, @@ -9703,15 +9703,15 @@ verify_shared_dpll_state(struct intel_crtc *crtc, if (old_crtc_state->shared_dpll && old_crtc_state->shared_dpll != new_crtc_state->shared_dpll) { - unsigned int crtc_mask = drm_crtc_mask(&crtc->base); + u8 pipe_mask = BIT(crtc->pipe); struct intel_shared_dpll *pll = old_crtc_state->shared_dpll; - I915_STATE_WARN(pll->active_mask & crtc_mask, - "pll active mismatch (didn't expect pipe %c in active mask)\n", - pipe_name(crtc->pipe)); - I915_STATE_WARN(pll->state.crtc_mask & crtc_mask, - "pll enabled crtcs mismatch (found %x in enabled mask)\n", - pipe_name(crtc->pipe)); + I915_STATE_WARN(pll->active_mask & pipe_mask, + "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", + pipe_name(crtc->pipe), pll->active_mask); + I915_STATE_WARN(pll->state.pipe_mask & pipe_mask, + "pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n", + pipe_name(crtc->pipe), pll->state.pipe_mask); } } diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 449470ef9f659..0c5b7600d8477 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -1098,8 +1098,8 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused) seq_printf(m, "DPLL%i: %s, id: %i\n", i, pll->info->name, pll->info->id); - seq_printf(m, " crtc_mask: 0x%08x, active: 0x%x, on: %s\n", - pll->state.crtc_mask, pll->active_mask, yesno(pll->on)); + seq_printf(m, " pipe_mask: 0x%x, active: 0x%x, on: %s\n", + pll->state.pipe_mask, pll->active_mask, yesno(pll->on)); seq_printf(m, " tracked hardware state:\n"); seq_printf(m, " dpll: 0x%08x\n", pll->state.hw_state.dpll); seq_printf(m, " dpll_md: 0x%08x\n", diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index ac6460962e298..22ee8e13b518c 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -176,7 +176,7 @@ void intel_prepare_shared_dpll(const struct intel_crtc_state *crtc_state) return; mutex_lock(&dev_priv->dpll.lock); - drm_WARN_ON(&dev_priv->drm, !pll->state.crtc_mask); + drm_WARN_ON(&dev_priv->drm, !pll->state.pipe_mask); if (!pll->active_mask) { drm_dbg(&dev_priv->drm, "setting up %s\n", pll->info->name); drm_WARN_ON(&dev_priv->drm, pll->on); @@ -198,7 +198,7 @@ void intel_enable_shared_dpll(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_shared_dpll *pll = crtc_state->shared_dpll; - unsigned int crtc_mask = drm_crtc_mask(&crtc->base); + unsigned int pipe_mask = BIT(crtc->pipe); unsigned int old_mask; if (drm_WARN_ON(&dev_priv->drm, pll == NULL)) @@ -207,16 +207,16 @@ void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state) mutex_lock(&dev_priv->dpll.lock); old_mask = pll->active_mask; - if (drm_WARN_ON(&dev_priv->drm, !(pll->state.crtc_mask & crtc_mask)) || - drm_WARN_ON(&dev_priv->drm, pll->active_mask & crtc_mask)) + if (drm_WARN_ON(&dev_priv->drm, !(pll->state.pipe_mask & pipe_mask)) || + drm_WARN_ON(&dev_priv->drm, pll->active_mask & pipe_mask)) goto out; - pll->active_mask |= crtc_mask; + pll->active_mask |= pipe_mask; drm_dbg_kms(&dev_priv->drm, - "enable %s (active %x, on? %d) for crtc %d\n", + "enable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, - crtc->base.base.id); + crtc->base.base.id, crtc->base.name); if (old_mask) { drm_WARN_ON(&dev_priv->drm, !pll->on); @@ -244,7 +244,7 @@ void intel_disable_shared_dpll(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_shared_dpll *pll = crtc_state->shared_dpll; - unsigned int crtc_mask = drm_crtc_mask(&crtc->base); + unsigned int pipe_mask = BIT(crtc->pipe); /* PCH only available on ILK+ */ if (INTEL_GEN(dev_priv) < 5) @@ -254,18 +254,20 @@ void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state) return; mutex_lock(&dev_priv->dpll.lock); - if (drm_WARN_ON(&dev_priv->drm, !(pll->active_mask & crtc_mask))) + if (drm_WARN(&dev_priv->drm, !(pll->active_mask & pipe_mask), + "%s not used by [CRTC:%d:%s]\n", pll->info->name, + crtc->base.base.id, crtc->base.name)) goto out; drm_dbg_kms(&dev_priv->drm, - "disable %s (active %x, on? %d) for crtc %d\n", + "disable %s (active 0x%x, on? %d) for [CRTC:%d:%s]\n", pll->info->name, pll->active_mask, pll->on, - crtc->base.base.id); + crtc->base.base.id, crtc->base.name); assert_shared_dpll_enabled(dev_priv, pll); drm_WARN_ON(&dev_priv->drm, !pll->on); - pll->active_mask &= ~crtc_mask; + pll->active_mask &= ~pipe_mask; if (pll->active_mask) goto out; @@ -296,7 +298,7 @@ intel_find_shared_dpll(struct intel_atomic_state *state, pll = &dev_priv->dpll.shared_dplls[i]; /* Only want to check enabled timings first */ - if (shared_dpll[i].crtc_mask == 0) { + if (shared_dpll[i].pipe_mask == 0) { if (!unused_pll) unused_pll = pll; continue; @@ -306,10 +308,10 @@ intel_find_shared_dpll(struct intel_atomic_state *state, &shared_dpll[i].hw_state, sizeof(*pll_state)) == 0) { drm_dbg_kms(&dev_priv->drm, - "[CRTC:%d:%s] sharing existing %s (crtc mask 0x%08x, active %x)\n", + "[CRTC:%d:%s] sharing existing %s (pipe mask 0x%x, active 0x%x)\n", crtc->base.base.id, crtc->base.name, pll->info->name, - shared_dpll[i].crtc_mask, + shared_dpll[i].pipe_mask, pll->active_mask); return pll; } @@ -338,13 +340,13 @@ intel_reference_shared_dpll(struct intel_atomic_state *state, shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - if (shared_dpll[id].crtc_mask == 0) + if (shared_dpll[id].pipe_mask == 0) shared_dpll[id].hw_state = *pll_state; drm_dbg(&i915->drm, "using %s for pipe %c\n", pll->info->name, pipe_name(crtc->pipe)); - shared_dpll[id].crtc_mask |= 1 << crtc->pipe; + shared_dpll[id].pipe_mask |= BIT(crtc->pipe); } static void intel_unreference_shared_dpll(struct intel_atomic_state *state, @@ -354,7 +356,7 @@ static void intel_unreference_shared_dpll(struct intel_atomic_state *state, struct intel_shared_dpll_state *shared_dpll; shared_dpll = intel_atomic_get_shared_dpll_state(&state->base); - shared_dpll[pll->info->id].crtc_mask &= ~(1 << crtc->pipe); + shared_dpll[pll->info->id].pipe_mask &= ~BIT(crtc->pipe); } static void intel_put_dpll(struct intel_atomic_state *state, @@ -4597,19 +4599,19 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915, POWER_DOMAIN_DPLL_DC_OFF); } - pll->state.crtc_mask = 0; + pll->state.pipe_mask = 0; for_each_intel_crtc(&i915->drm, crtc) { struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); if (crtc_state->hw.active && crtc_state->shared_dpll == pll) - pll->state.crtc_mask |= 1 << crtc->pipe; + pll->state.pipe_mask |= BIT(crtc->pipe); } - pll->active_mask = pll->state.crtc_mask; + pll->active_mask = pll->state.pipe_mask; drm_dbg_kms(&i915->drm, - "%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->info->name, pll->state.crtc_mask, pll->on); + "%s hw state readout: pipe_mask 0x%x, on %i\n", + pll->info->name, pll->state.pipe_mask, pll->on); } void intel_dpll_update_ref_clks(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index 81e67639dadb4..7fd031a70cfd3 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -241,9 +241,9 @@ struct intel_dpll_hw_state { */ struct intel_shared_dpll_state { /** - * @crtc_mask: mask of CRTC using this DPLL, active or not + * @pipe_mask: mask of pipes using this DPLL, active or not */ - unsigned crtc_mask; + u8 pipe_mask; /** * @hw_state: hardware configuration for the DPLL stored in @@ -351,9 +351,9 @@ struct intel_shared_dpll { struct intel_shared_dpll_state state; /** - * @active_mask: mask of active CRTCs (i.e. DPMS on) using this DPLL + * @active_mask: mask of active pipes (i.e. DPMS on) using this DPLL */ - unsigned active_mask; + u8 active_mask; /** * @on: is the PLL actually active? Disabled during modeset From 351221ffc5e5a183031bb424ab8b434e3a074b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Feb 2021 16:42:12 +0200 Subject: [PATCH 130/142] drm/i915: Move DDI clock readout to encoder->get_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the *_get_ddi_pll() stuff into the encodet->get_config() hook. There it neatly sits next to the matching .{enable,disable}_clock() functions. In order to avoid excessive boilerplate I changed the behaviour such that all platforms now do the readout via crtc_state->port_dpll[]. ICL+ TC is still a bit special due to TBTPLL not having a functional .get_freq(). Should probably change that by adopting the LCPLL approach, but that would require a fairly substantial rework of the DPLL ID handling. So leave it for later. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210224144214.24803-5-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/icl_dsi.c | 6 +- drivers/gpu/drm/i915/display/intel_crt.c | 2 +- drivers/gpu/drm/i915/display/intel_ddi.c | 321 +++++++++++++++++-- drivers/gpu/drm/i915/display/intel_ddi.h | 8 +- drivers/gpu/drm/i915/display/intel_display.c | 219 ------------- 5 files changed, 306 insertions(+), 250 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 05d5709ae5378..29fe4919392ad 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1490,14 +1490,10 @@ static void gen11_dsi_get_cmd_mode_config(struct intel_dsi *intel_dsi, static void gen11_dsi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); - /* FIXME: adapt icl_ddi_clock_get() for DSI and use that? */ - pipe_config->port_clock = intel_dpll_get_freq(i915, - pipe_config->shared_dpll, - &pipe_config->dpll_hw_state); + intel_ddi_get_clock(encoder, pipe_config, icl_ddi_combo_get_pll(encoder)); pipe_config->hw.adjusted_mode.crtc_clock = intel_dsi->pclk; if (intel_dsi->dual_link) diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 91a8a42b4aa26..b03f74076f647 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -142,7 +142,7 @@ static void hsw_crt_get_config(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - intel_ddi_get_config(encoder, pipe_config); + hsw_ddi_get_config(encoder, pipe_config); pipe_config->hw.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC | diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c0ace39bbfdff..e88e3bb0c39d9 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -303,25 +303,6 @@ static void ddi_dotclock_get(struct intel_crtc_state *pipe_config) pipe_config->hw.adjusted_mode.crtc_clock = dotclock; } -static void intel_ddi_clock_get(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(dev_priv, encoder->port); - - if (intel_phy_is_tc(dev_priv, phy) && - intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll) == - DPLL_ID_ICL_TBTPLL) - pipe_config->port_clock = icl_calc_tbt_pll_link(dev_priv, - encoder->port); - else - pipe_config->port_clock = - intel_dpll_get_freq(dev_priv, pipe_config->shared_dpll, - &pipe_config->dpll_hw_state); - - ddi_dotclock_get(pipe_config); -} - void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { @@ -1607,6 +1588,17 @@ static void _cnl_ddi_disable_clock(struct drm_i915_private *i915, i915_reg_t reg mutex_unlock(&i915->dpll.lock); } +static struct intel_shared_dpll * +_cnl_ddi_get_pll(struct drm_i915_private *i915, i915_reg_t reg, + u32 clk_sel_mask, u32 clk_sel_shift) +{ + enum intel_dpll_id id; + + id = (intel_de_read(i915, reg) & clk_sel_mask) >> clk_sel_shift; + + return intel_get_shared_dpll_by_id(i915, id); +} + static void adls_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1632,6 +1624,16 @@ static void adls_ddi_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static struct intel_shared_dpll *adls_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_get_pll(i915, ADLS_DPCLKA_CFGCR(phy), + ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy), + ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy)); +} + static void rkl_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1657,6 +1659,16 @@ static void rkl_ddi_disable_clock(struct intel_encoder *encoder) RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static struct intel_shared_dpll *rkl_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_get_pll(i915, ICL_DPCLKA_CFGCR0, + RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)); +} + static void dg1_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1691,6 +1703,16 @@ static void dg1_ddi_disable_clock(struct intel_encoder *encoder) DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static struct intel_shared_dpll *dg1_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_get_pll(i915, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)); +} + static void icl_ddi_combo_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1716,6 +1738,16 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +struct intel_shared_dpll *icl_ddi_combo_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_get_pll(i915, ICL_DPCLKA_CFGCR0, + ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy)); +} + static void jsl_ddi_tc_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1783,6 +1815,36 @@ static void icl_ddi_tc_disable_clock(struct intel_encoder *encoder) intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); } +static struct intel_shared_dpll *icl_ddi_tc_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, encoder->port); + enum port port = encoder->port; + enum intel_dpll_id id; + u32 tmp; + + tmp = intel_de_read(i915, DDI_CLK_SEL(port)); + + switch (tmp & DDI_CLK_SEL_MASK) { + case DDI_CLK_SEL_TBT_162: + case DDI_CLK_SEL_TBT_270: + case DDI_CLK_SEL_TBT_540: + case DDI_CLK_SEL_TBT_810: + id = DPLL_ID_ICL_TBTPLL; + break; + case DDI_CLK_SEL_MG: + id = icl_tc_port_to_pll_id(tc_port); + break; + default: + MISSING_CASE(tmp); + fallthrough; + case DDI_CLK_SEL_NONE: + return NULL; + } + + return intel_get_shared_dpll_by_id(i915, id); +} + static void cnl_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1808,6 +1870,39 @@ static void cnl_ddi_disable_clock(struct intel_encoder *encoder) DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } +static struct intel_shared_dpll *cnl_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + return _cnl_ddi_get_pll(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port), + DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)); +} + +static struct intel_shared_dpll *bxt_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum intel_dpll_id id; + + switch (encoder->port) { + case PORT_A: + id = DPLL_ID_SKL_DPLL0; + break; + case PORT_B: + id = DPLL_ID_SKL_DPLL1; + break; + case PORT_C: + id = DPLL_ID_SKL_DPLL2; + break; + default: + MISSING_CASE(encoder->port); + return NULL; + } + + return intel_get_shared_dpll_by_id(i915, id); +} + static void skl_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1842,6 +1937,28 @@ static void skl_ddi_disable_clock(struct intel_encoder *encoder) mutex_unlock(&i915->dpll.lock); } +static struct intel_shared_dpll *skl_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + enum intel_dpll_id id; + u32 tmp; + + tmp = intel_de_read(i915, DPLL_CTRL2); + + /* + * FIXME Not sure if the override affects both + * the PLL selection and the CLK_OFF bit. + */ + if ((tmp & DPLL_CTRL2_DDI_SEL_OVERRIDE(port)) == 0) + return NULL; + + id = (tmp & DPLL_CTRL2_DDI_CLK_SEL_MASK(port)) >> + DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port); + + return intel_get_shared_dpll_by_id(i915, id); +} + void hsw_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1863,6 +1980,44 @@ void hsw_ddi_disable_clock(struct intel_encoder *encoder) intel_de_write(i915, PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); } +static struct intel_shared_dpll *hsw_ddi_get_pll(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + enum intel_dpll_id id; + u32 tmp; + + tmp = intel_de_read(i915, PORT_CLK_SEL(port)); + + switch (tmp & PORT_CLK_SEL_MASK) { + case PORT_CLK_SEL_WRPLL1: + id = DPLL_ID_WRPLL1; + break; + case PORT_CLK_SEL_WRPLL2: + id = DPLL_ID_WRPLL2; + break; + case PORT_CLK_SEL_SPLL: + id = DPLL_ID_SPLL; + break; + case PORT_CLK_SEL_LCPLL_810: + id = DPLL_ID_LCPLL_810; + break; + case PORT_CLK_SEL_LCPLL_1350: + id = DPLL_ID_LCPLL_1350; + break; + case PORT_CLK_SEL_LCPLL_2700: + id = DPLL_ID_LCPLL_2700; + break; + default: + MISSING_CASE(tmp); + fallthrough; + case PORT_CLK_SEL_NONE: + return NULL; + } + + return intel_get_shared_dpll_by_id(i915, id); +} + void intel_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -3363,8 +3518,8 @@ static void intel_ddi_read_func_ctl(struct intel_encoder *encoder, } } -void intel_ddi_get_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config) +static void intel_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *pipe_config) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; @@ -3413,7 +3568,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder, } if (!pipe_config->bigjoiner_slave) - intel_ddi_clock_get(encoder, pipe_config); + ddi_dotclock_get(pipe_config); if (IS_GEN9_LP(dev_priv)) pipe_config->lane_lat_optim_mask = @@ -3443,6 +3598,114 @@ void intel_ddi_get_config(struct intel_encoder *encoder, intel_read_dp_sdp(encoder, pipe_config, DP_SDP_VSC); } +void intel_ddi_get_clock(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, + struct intel_shared_dpll *pll) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT; + struct icl_port_dpll *port_dpll = &crtc_state->icl_port_dplls[port_dpll_id]; + bool pll_active; + + port_dpll->pll = pll; + pll_active = intel_dpll_get_hw_state(i915, pll, &port_dpll->hw_state); + drm_WARN_ON(&i915->drm, !pll_active); + + icl_set_active_port_dpll(crtc_state, port_dpll_id); + + crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll, + &crtc_state->dpll_hw_state); +} + +static void adls_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, adls_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void rkl_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, rkl_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void dg1_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, dg1_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void icl_ddi_combo_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, icl_ddi_combo_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void icl_ddi_tc_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum icl_port_dpll_id port_dpll_id; + struct icl_port_dpll *port_dpll; + struct intel_shared_dpll *pll; + bool pll_active; + + pll = icl_ddi_tc_get_pll(encoder); + + if (intel_get_shared_dpll_id(i915, pll) == DPLL_ID_ICL_TBTPLL) + port_dpll_id = ICL_PORT_DPLL_DEFAULT; + else + port_dpll_id = ICL_PORT_DPLL_MG_PHY; + + port_dpll = &crtc_state->icl_port_dplls[port_dpll_id]; + + port_dpll->pll = pll; + pll_active = intel_dpll_get_hw_state(i915, pll, &port_dpll->hw_state); + drm_WARN_ON(&i915->drm, !pll_active); + + icl_set_active_port_dpll(crtc_state, port_dpll_id); + + if (intel_get_shared_dpll_id(i915, crtc_state->shared_dpll) == DPLL_ID_ICL_TBTPLL) + crtc_state->port_clock = icl_calc_tbt_pll_link(i915, encoder->port); + else + crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll, + &crtc_state->dpll_hw_state); + + intel_ddi_get_config(encoder, crtc_state); +} + +static void cnl_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, cnl_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void bxt_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, bxt_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +static void skl_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, skl_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + +void hsw_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + intel_ddi_get_clock(encoder, crtc_state, hsw_ddi_get_pll(encoder)); + intel_ddi_get_config(encoder, crtc_state); +} + static void intel_ddi_sync_state(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -4129,7 +4392,6 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) encoder->post_disable = intel_ddi_post_disable; encoder->update_pipe = intel_ddi_update_pipe; encoder->get_hw_state = intel_ddi_get_hw_state; - encoder->get_config = intel_ddi_get_config; encoder->sync_state = intel_ddi_sync_state; encoder->initial_fastset_check = intel_ddi_initial_fastset_check; encoder->suspend = intel_dp_encoder_suspend; @@ -4145,37 +4407,50 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) if (IS_ALDERLAKE_S(dev_priv)) { encoder->enable_clock = adls_ddi_enable_clock; encoder->disable_clock = adls_ddi_disable_clock; + encoder->get_config = adls_ddi_get_config; } else if (IS_ROCKETLAKE(dev_priv)) { encoder->enable_clock = rkl_ddi_enable_clock; encoder->disable_clock = rkl_ddi_disable_clock; + encoder->get_config = rkl_ddi_get_config; } else if (IS_DG1(dev_priv)) { encoder->enable_clock = dg1_ddi_enable_clock; encoder->disable_clock = dg1_ddi_disable_clock; + encoder->get_config = dg1_ddi_get_config; } else if (IS_JSL_EHL(dev_priv)) { if (intel_ddi_is_tc(dev_priv, port)) { encoder->enable_clock = jsl_ddi_tc_enable_clock; encoder->disable_clock = jsl_ddi_tc_disable_clock; + encoder->get_config = icl_ddi_combo_get_config; } else { encoder->enable_clock = icl_ddi_combo_enable_clock; encoder->disable_clock = icl_ddi_combo_disable_clock; + encoder->get_config = icl_ddi_combo_get_config; } } else if (INTEL_GEN(dev_priv) >= 11) { if (intel_ddi_is_tc(dev_priv, port)) { encoder->enable_clock = icl_ddi_tc_enable_clock; encoder->disable_clock = icl_ddi_tc_disable_clock; + encoder->get_config = icl_ddi_tc_get_config; } else { encoder->enable_clock = icl_ddi_combo_enable_clock; encoder->disable_clock = icl_ddi_combo_disable_clock; + encoder->get_config = icl_ddi_combo_get_config; } } else if (IS_CANNONLAKE(dev_priv)) { encoder->enable_clock = cnl_ddi_enable_clock; encoder->disable_clock = cnl_ddi_disable_clock; + encoder->get_config = cnl_ddi_get_config; + } else if (IS_GEN9_LP(dev_priv)) { + /* BXT/GLK have fixed PLL->port mapping */ + encoder->get_config = bxt_ddi_get_config; } else if (IS_GEN9_BC(dev_priv)) { encoder->enable_clock = skl_ddi_enable_clock; encoder->disable_clock = skl_ddi_disable_clock; + encoder->get_config = skl_ddi_get_config; } else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { encoder->enable_clock = hsw_ddi_enable_clock; encoder->disable_clock = hsw_ddi_disable_clock; + encoder->get_config = hsw_ddi_get_config; } if (IS_DG1(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 4a0c1d5c85e7a..0780c47efe0f9 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -30,9 +30,15 @@ void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, const struct drm_connector_state *old_conn_state); void intel_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); +void intel_ddi_get_clock(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, + struct intel_shared_dpll *pll); void hsw_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void hsw_ddi_disable_clock(struct intel_encoder *encoder); +void hsw_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state); +struct intel_shared_dpll *icl_ddi_combo_get_pll(struct intel_encoder *encoder); void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, @@ -48,8 +54,6 @@ void intel_ddi_disable_pipe_clock(const struct intel_crtc_state *crtc_state); void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); -void intel_ddi_get_config(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config); void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state, bool state); void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 78817d0c82e2c..18d7f7afc8ee7 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -6554,212 +6554,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc, return ret; } -static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - enum icl_port_dpll_id port_dpll_id = ICL_PORT_DPLL_DEFAULT; - enum phy phy = intel_port_to_phy(dev_priv, port); - struct icl_port_dpll *port_dpll; - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 clk_sel; - - clk_sel = intel_de_read(dev_priv, DG1_DPCLKA_CFGCR0(phy)) & DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - id = DG1_DPCLKA_CFGCR0_DDI_CLK_SEL_DPLL_MAP(clk_sel, phy); - - if (WARN_ON(id > DPLL_ID_DG1_DPLL3)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; - - port_dpll->pll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &port_dpll->hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); - - icl_set_active_port_dpll(pipe_config, port_dpll_id); -} - -static void icl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - enum phy phy = intel_port_to_phy(dev_priv, port); - enum icl_port_dpll_id port_dpll_id; - struct icl_port_dpll *port_dpll; - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - i915_reg_t reg; - u32 temp; - - if (intel_phy_is_combo(dev_priv, phy)) { - u32 mask, shift; - - if (IS_ALDERLAKE_S(dev_priv)) { - reg = ADLS_DPCLKA_CFGCR(phy); - mask = ADLS_DPCLKA_CFGCR_DDI_CLK_SEL_MASK(phy); - shift = ADLS_DPCLKA_CFGCR_DDI_SHIFT(phy); - } else if (IS_ROCKETLAKE(dev_priv)) { - reg = ICL_DPCLKA_CFGCR0; - mask = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - shift = RKL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); - } else { - reg = ICL_DPCLKA_CFGCR0; - mask = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(phy); - shift = ICL_DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(phy); - } - - temp = intel_de_read(dev_priv, reg) & mask; - id = temp >> shift; - port_dpll_id = ICL_PORT_DPLL_DEFAULT; - } else if (intel_phy_is_tc(dev_priv, phy)) { - u32 clk_sel = intel_de_read(dev_priv, DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK; - - if (clk_sel == DDI_CLK_SEL_MG) { - id = icl_tc_port_to_pll_id(intel_port_to_tc(dev_priv, - port)); - port_dpll_id = ICL_PORT_DPLL_MG_PHY; - } else { - drm_WARN_ON(&dev_priv->drm, - clk_sel < DDI_CLK_SEL_TBT_162); - id = DPLL_ID_ICL_TBTPLL; - port_dpll_id = ICL_PORT_DPLL_DEFAULT; - } - } else { - drm_WARN(&dev_priv->drm, 1, "Invalid port %x\n", port); - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - port_dpll = &pipe_config->icl_port_dplls[port_dpll_id]; - - port_dpll->pll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &port_dpll->hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); - - icl_set_active_port_dpll(pipe_config, port_dpll_id); -} - -static void cnl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 temp; - - temp = intel_de_read(dev_priv, DPCLKA_CFGCR0) & DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); - id = temp >> DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port); - - if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL2)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv, - enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - - switch (port) { - case PORT_A: - id = DPLL_ID_SKL_DPLL0; - break; - case PORT_B: - id = DPLL_ID_SKL_DPLL1; - break; - case PORT_C: - id = DPLL_ID_SKL_DPLL2; - break; - default: - drm_err(&dev_priv->drm, "Incorrect port type\n"); - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void skl_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - bool pll_active; - u32 temp; - - temp = intel_de_read(dev_priv, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port); - id = temp >> (port * 3 + 1); - - if (drm_WARN_ON(&dev_priv->drm, id < SKL_DPLL0 || id > SKL_DPLL3)) - return; - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - -static void hsw_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port, - struct intel_crtc_state *pipe_config) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id id; - u32 ddi_pll_sel = intel_de_read(dev_priv, PORT_CLK_SEL(port)); - bool pll_active; - - switch (ddi_pll_sel) { - case PORT_CLK_SEL_WRPLL1: - id = DPLL_ID_WRPLL1; - break; - case PORT_CLK_SEL_WRPLL2: - id = DPLL_ID_WRPLL2; - break; - case PORT_CLK_SEL_SPLL: - id = DPLL_ID_SPLL; - break; - case PORT_CLK_SEL_LCPLL_810: - id = DPLL_ID_LCPLL_810; - break; - case PORT_CLK_SEL_LCPLL_1350: - id = DPLL_ID_LCPLL_1350; - break; - case PORT_CLK_SEL_LCPLL_2700: - id = DPLL_ID_LCPLL_2700; - break; - default: - MISSING_CASE(ddi_pll_sel); - fallthrough; - case PORT_CLK_SEL_NONE: - return; - } - - pll = intel_get_shared_dpll_by_id(dev_priv, id); - - pipe_config->shared_dpll = pll; - pll_active = intel_dpll_get_hw_state(dev_priv, pll, - &pipe_config->dpll_hw_state); - drm_WARN_ON(&dev_priv->drm, !pll_active); -} - static bool hsw_get_transcoder_state(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config, struct intel_display_power_domain_set *power_domain_set) @@ -6916,19 +6710,6 @@ static void hsw_get_ddi_port_state(struct intel_crtc *crtc, port = TRANS_DDI_FUNC_CTL_VAL_TO_PORT(tmp); } - if (IS_DG1(dev_priv)) - dg1_get_ddi_pll(dev_priv, port, pipe_config); - else if (INTEL_GEN(dev_priv) >= 11) - icl_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_CANNONLAKE(dev_priv)) - cnl_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_GEN9_LP(dev_priv)) - bxt_get_ddi_pll(dev_priv, port, pipe_config); - else if (IS_GEN9_BC(dev_priv)) - skl_get_ddi_pll(dev_priv, port, pipe_config); - else - hsw_get_ddi_pll(dev_priv, port, pipe_config); - /* * Haswell has only FDI/PCH transcoder A. It is which is connected to * DDI E. So just check whether this pipe is wired to DDI E and whether From 0fbd869427749347a1cc927df16a16e18c0814b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Feb 2021 16:42:13 +0200 Subject: [PATCH 131/142] drm/i915: Add encoder->is_clock_enabled() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support reading out the current state of the DDI clock. Not sure we really want this. Seems a bit excessive just to restore the debug print to icl_sanitize_encoder_pll_mapping()? But maybe there's more use for it? Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210224144214.24803-6-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/icl_dsi.c | 19 +++ drivers/gpu/drm/i915/display/intel_crt.c | 1 + drivers/gpu/drm/i915/display/intel_ddi.c | 123 +++++++++++++++++- drivers/gpu/drm/i915/display/intel_ddi.h | 1 + .../drm/i915/display/intel_display_types.h | 4 + 5 files changed, 146 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 29fe4919392ad..7f2abc088a665 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -655,6 +655,24 @@ static void gen11_dsi_ungate_clocks(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpll.lock); } +static bool gen11_dsi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); + bool clock_enabled = false; + enum phy phy; + u32 tmp; + + tmp = intel_de_read(dev_priv, ICL_DPCLKA_CFGCR0); + + for_each_dsi_phy(phy, intel_dsi->phys) { + if (!(tmp & ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy))) + clock_enabled = true; + } + + return clock_enabled; +} + static void gen11_dsi_map_pll(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1939,6 +1957,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) encoder->power_domain = POWER_DOMAIN_PORT_DSI; encoder->get_power_domains = gen11_dsi_get_power_domains; encoder->disable_clock = gen11_dsi_gate_clocks; + encoder->is_clock_enabled = gen11_dsi_is_clock_enabled; /* register DSI connector with DRM subsystem */ drm_connector_init(dev, connector, &gen11_dsi_connector_funcs, diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index b03f74076f647..7f3d11c5ce3e2 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -1078,6 +1078,7 @@ void intel_crt_init(struct drm_i915_private *dev_priv) crt->base.post_disable = hsw_post_disable_crt; crt->base.enable_clock = hsw_ddi_enable_clock; crt->base.disable_clock = hsw_ddi_disable_clock; + crt->base.is_clock_enabled = hsw_ddi_is_clock_enabled; } else { if (HAS_PCH_SPLIT(dev_priv)) { crt->base.compute_config = pch_crt_compute_config; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e88e3bb0c39d9..59f105c842426 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -1588,6 +1588,12 @@ static void _cnl_ddi_disable_clock(struct drm_i915_private *i915, i915_reg_t reg mutex_unlock(&i915->dpll.lock); } +static bool _cnl_ddi_is_clock_enabled(struct drm_i915_private *i915, i915_reg_t reg, + u32 clk_off) +{ + return !(intel_de_read(i915, reg) & clk_off); +} + static struct intel_shared_dpll * _cnl_ddi_get_pll(struct drm_i915_private *i915, i915_reg_t reg, u32 clk_sel_mask, u32 clk_sel_shift) @@ -1624,6 +1630,15 @@ static void adls_ddi_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static bool adls_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_is_clock_enabled(i915, ADLS_DPCLKA_CFGCR(phy), + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + static struct intel_shared_dpll *adls_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1659,6 +1674,15 @@ static void rkl_ddi_disable_clock(struct intel_encoder *encoder) RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static bool rkl_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_is_clock_enabled(i915, ICL_DPCLKA_CFGCR0, + RKL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + static struct intel_shared_dpll *rkl_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1703,6 +1727,15 @@ static void dg1_ddi_disable_clock(struct intel_encoder *encoder) DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static bool dg1_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_is_clock_enabled(i915, DG1_DPCLKA_CFGCR0(phy), + DG1_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + static struct intel_shared_dpll *dg1_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1738,6 +1771,15 @@ static void icl_ddi_combo_disable_clock(struct intel_encoder *encoder) ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); } +static bool icl_ddi_combo_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + return _cnl_ddi_is_clock_enabled(i915, ICL_DPCLKA_CFGCR0, + ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(phy)); +} + struct intel_shared_dpll *icl_ddi_combo_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1777,6 +1819,20 @@ static void jsl_ddi_tc_disable_clock(struct intel_encoder *encoder) intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); } +static bool jsl_ddi_tc_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + u32 tmp; + + tmp = intel_de_read(i915, DDI_CLK_SEL(port)); + + if ((tmp & DDI_CLK_SEL_MASK) == DDI_CLK_SEL_NONE) + return false; + + return icl_ddi_combo_is_clock_enabled(encoder); +} + static void icl_ddi_tc_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { @@ -1815,6 +1871,23 @@ static void icl_ddi_tc_disable_clock(struct intel_encoder *encoder) intel_de_write(i915, DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); } +static bool icl_ddi_tc_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum tc_port tc_port = intel_port_to_tc(i915, encoder->port); + enum port port = encoder->port; + u32 tmp; + + tmp = intel_de_read(i915, DDI_CLK_SEL(port)); + + if ((tmp & DDI_CLK_SEL_MASK) == DDI_CLK_SEL_NONE) + return false; + + tmp = intel_de_read(i915, ICL_DPCLKA_CFGCR0); + + return !(tmp & ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port)); +} + static struct intel_shared_dpll *icl_ddi_tc_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1870,6 +1943,15 @@ static void cnl_ddi_disable_clock(struct intel_encoder *encoder) DPCLKA_CFGCR0_DDI_CLK_OFF(port)); } +static bool cnl_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + return _cnl_ddi_is_clock_enabled(i915, DPCLKA_CFGCR0, + DPCLKA_CFGCR0_DDI_CLK_OFF(port)); +} + static struct intel_shared_dpll *cnl_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1937,6 +2019,18 @@ static void skl_ddi_disable_clock(struct intel_encoder *encoder) mutex_unlock(&i915->dpll.lock); } +static bool skl_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + /* + * FIXME Not sure if the override affects both + * the PLL selection and the CLK_OFF bit. + */ + return !(intel_de_read(i915, DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_OFF(port)); +} + static struct intel_shared_dpll *skl_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -1980,6 +2074,14 @@ void hsw_ddi_disable_clock(struct intel_encoder *encoder) intel_de_write(i915, PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); } +bool hsw_ddi_is_clock_enabled(struct intel_encoder *encoder) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum port port = encoder->port; + + return intel_de_read(i915, PORT_CLK_SEL(port)) != PORT_CLK_SEL_NONE; +} + static struct intel_shared_dpll *hsw_ddi_get_pll(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); @@ -2083,8 +2185,15 @@ void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) ddi_clk_needed = false; } - if (!ddi_clk_needed && encoder->disable_clock) - encoder->disable_clock(encoder); + if (ddi_clk_needed || !encoder->disable_clock || + !encoder->is_clock_enabled(encoder)) + return; + + drm_notice(&i915->drm, + "[ENCODER:%d:%s] is disabled/in DSI mode with an ungated DDI clock, gate it\n", + encoder->base.base.id, encoder->base.name); + + encoder->disable_clock(encoder); } static void @@ -4407,38 +4516,46 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) if (IS_ALDERLAKE_S(dev_priv)) { encoder->enable_clock = adls_ddi_enable_clock; encoder->disable_clock = adls_ddi_disable_clock; + encoder->is_clock_enabled = adls_ddi_is_clock_enabled; encoder->get_config = adls_ddi_get_config; } else if (IS_ROCKETLAKE(dev_priv)) { encoder->enable_clock = rkl_ddi_enable_clock; encoder->disable_clock = rkl_ddi_disable_clock; + encoder->is_clock_enabled = rkl_ddi_is_clock_enabled; encoder->get_config = rkl_ddi_get_config; } else if (IS_DG1(dev_priv)) { encoder->enable_clock = dg1_ddi_enable_clock; encoder->disable_clock = dg1_ddi_disable_clock; + encoder->is_clock_enabled = dg1_ddi_is_clock_enabled; encoder->get_config = dg1_ddi_get_config; } else if (IS_JSL_EHL(dev_priv)) { if (intel_ddi_is_tc(dev_priv, port)) { encoder->enable_clock = jsl_ddi_tc_enable_clock; encoder->disable_clock = jsl_ddi_tc_disable_clock; + encoder->is_clock_enabled = jsl_ddi_tc_is_clock_enabled; encoder->get_config = icl_ddi_combo_get_config; } else { encoder->enable_clock = icl_ddi_combo_enable_clock; encoder->disable_clock = icl_ddi_combo_disable_clock; + encoder->is_clock_enabled = icl_ddi_combo_is_clock_enabled; encoder->get_config = icl_ddi_combo_get_config; } } else if (INTEL_GEN(dev_priv) >= 11) { if (intel_ddi_is_tc(dev_priv, port)) { encoder->enable_clock = icl_ddi_tc_enable_clock; encoder->disable_clock = icl_ddi_tc_disable_clock; + encoder->is_clock_enabled = icl_ddi_tc_is_clock_enabled; encoder->get_config = icl_ddi_tc_get_config; } else { encoder->enable_clock = icl_ddi_combo_enable_clock; encoder->disable_clock = icl_ddi_combo_disable_clock; + encoder->is_clock_enabled = icl_ddi_combo_is_clock_enabled; encoder->get_config = icl_ddi_combo_get_config; } } else if (IS_CANNONLAKE(dev_priv)) { encoder->enable_clock = cnl_ddi_enable_clock; encoder->disable_clock = cnl_ddi_disable_clock; + encoder->is_clock_enabled = cnl_ddi_is_clock_enabled; encoder->get_config = cnl_ddi_get_config; } else if (IS_GEN9_LP(dev_priv)) { /* BXT/GLK have fixed PLL->port mapping */ @@ -4446,10 +4563,12 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) } else if (IS_GEN9_BC(dev_priv)) { encoder->enable_clock = skl_ddi_enable_clock; encoder->disable_clock = skl_ddi_disable_clock; + encoder->is_clock_enabled = skl_ddi_is_clock_enabled; encoder->get_config = skl_ddi_get_config; } else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) { encoder->enable_clock = hsw_ddi_enable_clock; encoder->disable_clock = hsw_ddi_disable_clock; + encoder->is_clock_enabled = hsw_ddi_is_clock_enabled; encoder->get_config = hsw_ddi_get_config; } diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 0780c47efe0f9..99cebbe6b5869 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -36,6 +36,7 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, void hsw_ddi_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void hsw_ddi_disable_clock(struct intel_encoder *encoder); +bool hsw_ddi_is_clock_enabled(struct intel_encoder *encoder); void hsw_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state); struct intel_shared_dpll *icl_ddi_combo_get_pll(struct intel_encoder *encoder); diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 8d9113fa82c71..f159dce0f7448 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -226,6 +226,10 @@ struct intel_encoder { void (*enable_clock)(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void (*disable_clock)(struct intel_encoder *encoder); + /* + * Returns whether the port clock is enabled or not. + */ + bool (*is_clock_enabled)(struct intel_encoder *encoder); enum hpd_pin hpd_pin; enum intel_display_power_domain power_domain; /* for communication with audio component; protected by av_mutex */ From aaca50ef45ed247d98a66c0a754d1be93ff35dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Feb 2021 16:42:14 +0200 Subject: [PATCH 132/142] drm/i915: Extend icl_sanitize_encoder_pll_mapping() to all DDI platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all the encoder clock stuff is uniformly abstracted for all hsw+ platforms, let's extend icl_sanitize_encoder_pll_mapping() to cover all of them. Not sure there is a particular benefit in doing so, but less special cases always makes me happy. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210224144214.24803-7-ville.syrjala@linux.intel.com Reviewed-by: Mika Kahola --- drivers/gpu/drm/i915/display/intel_ddi.c | 2 +- drivers/gpu/drm/i915/display/intel_ddi.h | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 59f105c842426..ba83682e1d3e8 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2133,7 +2133,7 @@ static void intel_ddi_disable_clock(struct intel_encoder *encoder) encoder->disable_clock(encoder); } -void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) +void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 port_mask; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 99cebbe6b5869..59c6b01d4199e 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -66,6 +66,6 @@ u32 ddi_signal_levels(struct intel_dp *intel_dp, int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder, enum transcoder cpu_transcoder, bool enable, u32 hdcp_mask); -void icl_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); +void intel_ddi_sanitize_encoder_pll_mapping(struct intel_encoder *encoder); #endif /* __INTEL_DDI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 18d7f7afc8ee7..f4bf81f27f319 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -13146,8 +13146,8 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) /* notify opregion of the sanitized encoder state */ intel_opregion_notify_encoder(encoder, connector && has_active_crtc); - if (INTEL_GEN(dev_priv) >= 11) - icl_sanitize_encoder_pll_mapping(encoder); + if (HAS_DDI(dev_priv)) + intel_ddi_sanitize_encoder_pll_mapping(encoder); } /* FIXME read out full plane state for all planes */ From 086877a12f36f7fffaaeb3b7842cf409093e13b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 10 Mar 2021 21:43:51 +0200 Subject: [PATCH 133/142] drm/i915: Tolerate bogus DPLL selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's check that we actually found the PLL before doing the port_clock readout, just in case the hardware was severly misprogrammed by the previous guy. Not sure the hw would even survive such misprogramming without hanging but no real harm in checking anyway. Cc: Karthik B S Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210310194351.6233-1-ville.syrjala@linux.intel.com Reviewed-by: Karthik B S --- drivers/gpu/drm/i915/display/intel_ddi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index ba83682e1d3e8..64a952db85284 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3716,6 +3716,9 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, struct icl_port_dpll *port_dpll = &crtc_state->icl_port_dplls[port_dpll_id]; bool pll_active; + if (drm_WARN_ON(&i915->drm, !pll)) + return; + port_dpll->pll = pll; pll_active = intel_dpll_get_hw_state(i915, pll, &port_dpll->hw_state); drm_WARN_ON(&i915->drm, !pll_active); @@ -3754,16 +3757,17 @@ static void icl_ddi_combo_get_config(struct intel_encoder *encoder, intel_ddi_get_config(encoder, crtc_state); } -static void icl_ddi_tc_get_config(struct intel_encoder *encoder, - struct intel_crtc_state *crtc_state) +static void icl_ddi_tc_get_clock(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state, + struct intel_shared_dpll *pll) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); enum icl_port_dpll_id port_dpll_id; struct icl_port_dpll *port_dpll; - struct intel_shared_dpll *pll; bool pll_active; - pll = icl_ddi_tc_get_pll(encoder); + if (drm_WARN_ON(&i915->drm, !pll)) + return; if (intel_get_shared_dpll_id(i915, pll) == DPLL_ID_ICL_TBTPLL) port_dpll_id = ICL_PORT_DPLL_DEFAULT; @@ -3783,7 +3787,12 @@ static void icl_ddi_tc_get_config(struct intel_encoder *encoder, else crtc_state->port_clock = intel_dpll_get_freq(i915, crtc_state->shared_dpll, &crtc_state->dpll_hw_state); +} +static void icl_ddi_tc_get_config(struct intel_encoder *encoder, + struct intel_crtc_state *crtc_state) +{ + icl_ddi_tc_get_clock(encoder, crtc_state, icl_ddi_tc_get_pll(encoder)); intel_ddi_get_config(encoder, crtc_state); } From b7a7053ab2ec558b8ae4e55f62ea8f1f58e14f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Sat, 20 Feb 2021 12:33:03 +0200 Subject: [PATCH 134/142] drm/i915: Workaround async flip + VT-d corruption on HSW/BDW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On HSW/BDW with VT-d active the first tile row scanned out after the first async flip of the frame often ends up corrupted. Whether the corruption happens or not depends on the scanline on which the async flip happens, but the behaviour seems very consistent. Ie. the same set of scanlines (which are most scanlines) always show the corruption. And another set of scanlines (far less of them) never shows the corruption. I discovered that disabling the fetch-stride stretching feature cures the corruption. This is some kind of TLB related prefetch thing AFAIK. We already disable it on SNB primary planes due to a documented workaround. The hardware folks indicated that disabling this should be fine, so let's go with that. And while we're here, let's document the relevant bits on all pre-skl platforms. Fixes: 2a636e240c77 ("drm/i915: Implement async flip for ivb/hsw") Fixes: cda195f13abd ("drm/i915: Implement async flips for bdw") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210220103303.3448-1-ville.syrjala@linux.intel.com Reviewed-by: Karthik B S --- drivers/gpu/drm/i915/i915_reg.h | 23 ++++++++++++++++++++++- drivers/gpu/drm/i915/intel_pm.c | 16 +++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 174dc15a0cf83..765ba64442aba 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3319,7 +3319,18 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define ILK_DISPLAY_CHICKEN1 _MMIO(0x42000) #define ILK_FBCQ_DIS (1 << 22) -#define ILK_PABSTRETCH_DIS (1 << 21) +#define ILK_PABSTRETCH_DIS REG_BIT(21) +#define ILK_SABSTRETCH_DIS REG_BIT(20) +#define IVB_PRI_STRETCH_MAX_MASK REG_GENMASK(21, 20) +#define IVB_PRI_STRETCH_MAX_X8 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 0) +#define IVB_PRI_STRETCH_MAX_X4 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 1) +#define IVB_PRI_STRETCH_MAX_X2 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 2) +#define IVB_PRI_STRETCH_MAX_X1 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 3) +#define IVB_SPR_STRETCH_MAX_MASK REG_GENMASK(19, 18) +#define IVB_SPR_STRETCH_MAX_X8 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 0) +#define IVB_SPR_STRETCH_MAX_X4 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 1) +#define IVB_SPR_STRETCH_MAX_X2 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 2) +#define IVB_SPR_STRETCH_MAX_X1 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 3) /* @@ -8042,6 +8053,16 @@ enum { #define _CHICKEN_PIPESL_1_A 0x420b0 #define _CHICKEN_PIPESL_1_B 0x420b4 +#define HSW_PRI_STRETCH_MAX_MASK REG_GENMASK(28, 27) +#define HSW_PRI_STRETCH_MAX_X8 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 0) +#define HSW_PRI_STRETCH_MAX_X4 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 1) +#define HSW_PRI_STRETCH_MAX_X2 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 2) +#define HSW_PRI_STRETCH_MAX_X1 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 3) +#define HSW_SPR_STRETCH_MAX_MASK REG_GENMASK(26, 25) +#define HSW_SPR_STRETCH_MAX_X8 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 0) +#define HSW_SPR_STRETCH_MAX_X4 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 1) +#define HSW_SPR_STRETCH_MAX_X2 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 2) +#define HSW_SPR_STRETCH_MAX_X1 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 3) #define HSW_FBCQ_DIS (1 << 22) #define BDW_DPRS_MASK_VBLANK_SRD (1 << 0) #define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 854ffecd98d9c..00f1ab5a8aeb7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7287,11 +7287,16 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1, intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); - /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ for_each_pipe(dev_priv, pipe) { + /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) | BDW_DPRS_MASK_VBLANK_SRD); + + /* Undocumented but fixes async flip + VT-d corruption */ + if (intel_vtd_active()) + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), + HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1); } /* WaVSRefCountFullforceMissDisable:bdw */ @@ -7327,11 +7332,20 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv) static void hsw_init_clock_gating(struct drm_i915_private *dev_priv) { + enum pipe pipe; + /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A), intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) | HSW_FBCQ_DIS); + for_each_pipe(dev_priv, pipe) { + /* Undocumented but fixes async flip + VT-d corruption */ + if (intel_vtd_active()) + intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe), + HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1); + } + /* This is required by WaCatErrorRejectionIssue:hsw */ intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | From cdf64625e8d090db6abd13d1b3d71c8d77844801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Mar 2021 17:36:06 +0200 Subject: [PATCH 135/142] drm/i915: Tighten SAGV constraint for pre-tgl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Say we have two planes enabled with watermarks configured as follows: plane A: wm0=enabled/can_sagv=false, wm1=enabled/can_sagv=true plane B: wm0=enabled/can_sagv=true, wm1=disabled This is possible since the latency we use to calculate can_sagv may not be the same for both planes due to skl_needs_memory_bw_wa(). In this case skl_crtc_can_enable_sagv() will see that both planes have enabled at least one watermark level with can_sagv==true, and thus proceeds to allow SAGV. However, since plane B does not have wm1 enabled plane A can't actually use it either. Thus we are now running with SAGV enabled, but plane A can't actually tolerate the extra latency it imposes. To remedy this only allow SAGV on if the highest common enabled watermark level for all active planes can tolerate the extra SAGV latency. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210305153610.12177-3-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 00f1ab5a8aeb7..bf33f73ed2adb 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3876,6 +3876,7 @@ static bool skl_crtc_can_enable_sagv(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); enum plane_id plane_id; + int max_level = INT_MAX; if (!intel_has_sagv(dev_priv)) return false; @@ -3900,12 +3901,23 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) !wm->wm[level].plane_en; --level) { } + /* Highest common enabled wm level for all planes */ + max_level = min(level, max_level); + } + + /* No enabled planes? */ + if (max_level == INT_MAX) + return true; + + for_each_plane_id_on_crtc(crtc, plane_id) { + const struct skl_plane_wm *wm = + &crtc_state->wm.skl.optimal.planes[plane_id]; + /* - * If any of the planes on this pipe don't enable wm levels that - * incur memory latencies higher than sagv_block_time_us we - * can't enable SAGV. + * All enabled planes must have enabled a common wm level that + * can tolerate memory latencies higher than sagv_block_time_us */ - if (!wm->wm[level].can_sagv) + if (wm->wm[0].plane_en && !wm->wm[max_level].can_sagv) return false; } From f0dfaa982b7936dfd751502bf89fbd8c07e02943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Mar 2021 17:36:07 +0200 Subject: [PATCH 136/142] drm/i915: Check SAGV wm min_ddb_alloc rather than plane_res_b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For non-transition watermarks we are supposed to check min_ddb_alloc rather than plane_res_b when determining if we have enough DDB space for it. A bit too much copy pasta made me check the wrong thing. Cc: Stanislav Lisovskiy Fixes: df4a50a35e2c ("drm/i915: Zero out SAGV wm when we don't have enough DDB for it") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210305153610.12177-4-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index bf33f73ed2adb..986ef5eff3744 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4989,7 +4989,7 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, if (wm->trans_wm.plane_res_b >= total[plane_id]) memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); - if (wm->sagv.wm0.plane_res_b >= total[plane_id]) + if (wm->sagv.wm0.min_ddb_alloc > total[plane_id]) memset(&wm->sagv.wm0, 0, sizeof(wm->sagv.wm0)); if (wm->sagv.trans_wm.plane_res_b >= total[plane_id]) From 18ffd6de8c50fdbb925e421f70ea0d1a60f81528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Mar 2021 17:36:08 +0200 Subject: [PATCH 137/142] drm/i915: Calculate min_ddb_alloc for trans_wm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's make all the "do we have enough DDB for this WM level?" checks use min_ddb_alloc. To achieve that we need to populate this for the transition watermarks as well. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210305153610.12177-5-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 986ef5eff3744..ee11447f50aa8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4986,13 +4986,13 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (wm->trans_wm.plane_res_b >= total[plane_id]) + if (wm->trans_wm.min_ddb_alloc > total[plane_id]) memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); if (wm->sagv.wm0.min_ddb_alloc > total[plane_id]) memset(&wm->sagv.wm0, 0, sizeof(wm->sagv.wm0)); - if (wm->sagv.trans_wm.plane_res_b >= total[plane_id]) + if (wm->sagv.trans_wm.min_ddb_alloc > total[plane_id]) memset(&wm->sagv.trans_wm, 0, sizeof(wm->sagv.trans_wm)); } @@ -5404,13 +5404,15 @@ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, } else { res_blocks = wm0_sel_res_b + trans_offset_b; } + res_blocks++; /* * Just assume we can enable the transition watermark. After * computing the DDB we'll come back and disable it if that * assumption turns out to be false. */ - trans_wm->plane_res_b = res_blocks + 1; + trans_wm->plane_res_b = res_blocks; + trans_wm->min_ddb_alloc = max_t(u16, wm0->min_ddb_alloc, res_blocks + 1); trans_wm->plane_en = true; } From a5941b475028676165525b1bdf259a9088ea2e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Mar 2021 17:36:09 +0200 Subject: [PATCH 138/142] drm/i915: Extract skl_check_wm_level() and skl_check_nv12_wm_level() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the code more typo proof by extracting small helpers that do the "do we have enough DDB for the WM level?" checks in a consistent manner. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210305153610.12177-6-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/intel_pm.c | 58 ++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ee11447f50aa8..069ae650187bd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4782,6 +4782,36 @@ skl_plane_trans_wm(const struct skl_pipe_wm *pipe_wm, return &wm->trans_wm; } +/* + * We only disable the watermarks for each plane if + * they exceed the ddb allocation of said plane. This + * is done so that we don't end up touching cursor + * watermarks needlessly when some other plane reduces + * our max possible watermark level. + * + * Bspec has this to say about the PLANE_WM enable bit: + * "All the watermarks at this level for all enabled + * planes must be enabled before the level will be used." + * So this is actually safe to do. + */ +static void +skl_check_wm_level(struct skl_wm_level *wm, u64 total) +{ + if (wm->min_ddb_alloc > total) + memset(wm, 0, sizeof(*wm)); +} + +static void +skl_check_nv12_wm_level(struct skl_wm_level *wm, struct skl_wm_level *uv_wm, + u64 total, u64 uv_total) +{ + if (wm->min_ddb_alloc > total || + uv_wm->min_ddb_alloc > uv_total) { + memset(wm, 0, sizeof(*wm)); + memset(uv_wm, 0, sizeof(*uv_wm)); + } +} + static int skl_allocate_plane_ddb(struct intel_atomic_state *state, struct intel_crtc *crtc) @@ -4949,21 +4979,8 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - /* - * We only disable the watermarks for each plane if - * they exceed the ddb allocation of said plane. This - * is done so that we don't end up touching cursor - * watermarks needlessly when some other plane reduces - * our max possible watermark level. - * - * Bspec has this to say about the PLANE_WM enable bit: - * "All the watermarks at this level for all enabled - * planes must be enabled before the level will be used." - * So this is actually safe to do. - */ - if (wm->wm[level].min_ddb_alloc > total[plane_id] || - wm->uv_wm[level].min_ddb_alloc > uv_total[plane_id]) - memset(&wm->wm[level], 0, sizeof(wm->wm[level])); + skl_check_nv12_wm_level(&wm->wm[level], &wm->uv_wm[level], + total[plane_id], uv_total[plane_id]); /* * Wa_1408961008:icl, ehl @@ -4986,14 +5003,9 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (wm->trans_wm.min_ddb_alloc > total[plane_id]) - memset(&wm->trans_wm, 0, sizeof(wm->trans_wm)); - - if (wm->sagv.wm0.min_ddb_alloc > total[plane_id]) - memset(&wm->sagv.wm0, 0, sizeof(wm->sagv.wm0)); - - if (wm->sagv.trans_wm.min_ddb_alloc > total[plane_id]) - memset(&wm->sagv.trans_wm, 0, sizeof(wm->sagv.trans_wm)); + skl_check_wm_level(&wm->trans_wm, total[plane_id]); + skl_check_wm_level(&wm->sagv.wm0, total[plane_id]); + skl_check_wm_level(&wm->sagv.trans_wm, total[plane_id]); } return 0; From 5dac808aceb62bb7481908efb9ce402f5127157d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 5 Mar 2021 17:36:10 +0200 Subject: [PATCH 139/142] drm/i915: s/plane_res_b/blocks/ etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename a bunch of the skl+ watermark struct members to have sensible names. Avoids me having to think what plane_res_b/etc. means. Cc: Stanislav Lisovskiy Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20210305153610.12177-7-ville.syrjala@linux.intel.com Reviewed-by: Stanislav Lisovskiy --- drivers/gpu/drm/i915/display/intel_display.c | 24 +-- .../drm/i915/display/intel_display_types.h | 6 +- drivers/gpu/drm/i915/intel_pm.c | 198 +++++++++--------- 3 files changed, 112 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 1a4e255dc43c4..3957f7497461f 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -9216,12 +9216,12 @@ static void verify_wm_state(struct intel_crtc *crtc, drm_err(&dev_priv->drm, "[PLANE:%d:%s] mismatch in WM%d (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", plane->base.base.id, plane->base.name, level, - sw_wm_level->plane_en, - sw_wm_level->plane_res_b, - sw_wm_level->plane_res_l, - hw_wm_level->plane_en, - hw_wm_level->plane_res_b, - hw_wm_level->plane_res_l); + sw_wm_level->enable, + sw_wm_level->blocks, + sw_wm_level->lines, + hw_wm_level->enable, + hw_wm_level->blocks, + hw_wm_level->lines); } hw_wm_level = &hw->wm.planes[plane->id].trans_wm; @@ -9231,12 +9231,12 @@ static void verify_wm_state(struct intel_crtc *crtc, drm_err(&dev_priv->drm, "[PLANE:%d:%s] mismatch in trans WM (expected e=%d b=%u l=%u, got e=%d b=%u l=%u)\n", plane->base.base.id, plane->base.name, - sw_wm_level->plane_en, - sw_wm_level->plane_res_b, - sw_wm_level->plane_res_l, - hw_wm_level->plane_en, - hw_wm_level->plane_res_b, - hw_wm_level->plane_res_l); + sw_wm_level->enable, + sw_wm_level->blocks, + sw_wm_level->lines, + hw_wm_level->enable, + hw_wm_level->blocks, + hw_wm_level->lines); } /* DDB */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index f159dce0f7448..eaebba5889d2b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -725,9 +725,9 @@ struct intel_pipe_wm { struct skl_wm_level { u16 min_ddb_alloc; - u16 plane_res_b; - u8 plane_res_l; - bool plane_en; + u16 blocks; + u8 lines; + bool enable; bool ignore_lines; bool can_sagv; }; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 069ae650187bd..4c07745a6fdb0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3893,12 +3893,12 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) int level; /* Skip this plane if it's not enabled */ - if (!wm->wm[0].plane_en) + if (!wm->wm[0].enable) continue; /* Find the highest enabled wm level for this plane */ for (level = ilk_wm_max_level(dev_priv); - !wm->wm[level].plane_en; --level) + !wm->wm[level].enable; --level) { } /* Highest common enabled wm level for all planes */ @@ -3917,7 +3917,7 @@ static bool skl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) * All enabled planes must have enabled a common wm level that * can tolerate memory latencies higher than sagv_block_time_us */ - if (wm->wm[0].plane_en && !wm->wm[max_level].can_sagv) + if (wm->wm[0].enable && !wm->wm[max_level].can_sagv) return false; } @@ -3936,7 +3936,7 @@ static bool tgl_crtc_can_enable_sagv(const struct intel_crtc_state *crtc_state) const struct skl_plane_wm *wm = &crtc_state->wm.skl.optimal.planes[plane_id]; - if (wm->wm[0].plane_en && !wm->sagv.wm0.plane_en) + if (wm->wm[0].enable && !wm->sagv.wm0.enable) return false; } @@ -4987,9 +4987,9 @@ skl_allocate_plane_ddb(struct intel_atomic_state *state, * Underruns with WM1+ disabled */ if (IS_GEN(dev_priv, 11) && - level == 1 && wm->wm[0].plane_en) { - wm->wm[level].plane_res_b = wm->wm[0].plane_res_b; - wm->wm[level].plane_res_l = wm->wm[0].plane_res_l; + level == 1 && wm->wm[0].enable) { + wm->wm[level].blocks = wm->wm[0].blocks; + wm->wm[level].lines = wm->wm[0].lines; wm->wm[level].ignore_lines = wm->wm[0].ignore_lines; } } @@ -5210,7 +5210,7 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); uint_fixed_16_16_t method1, method2; uint_fixed_16_16_t selected_result; - u32 res_blocks, res_lines, min_ddb_alloc = 0; + u32 blocks, lines, min_ddb_alloc = 0; if (latency == 0) { /* reject it */ @@ -5256,24 +5256,22 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, } } - res_blocks = fixed16_to_u32_round_up(selected_result) + 1; - res_lines = div_round_up_fixed16(selected_result, - wp->plane_blocks_per_line); + blocks = fixed16_to_u32_round_up(selected_result) + 1; + lines = div_round_up_fixed16(selected_result, + wp->plane_blocks_per_line); if (IS_GEN9_BC(dev_priv) || IS_BROXTON(dev_priv)) { /* Display WA #1125: skl,bxt,kbl */ if (level == 0 && wp->rc_surface) - res_blocks += - fixed16_to_u32_round_up(wp->y_tile_minimum); + blocks += fixed16_to_u32_round_up(wp->y_tile_minimum); /* Display WA #1126: skl,bxt,kbl */ if (level >= 1 && level <= 7) { if (wp->y_tiled) { - res_blocks += - fixed16_to_u32_round_up(wp->y_tile_minimum); - res_lines += wp->y_min_scanlines; + blocks += fixed16_to_u32_round_up(wp->y_tile_minimum); + lines += wp->y_min_scanlines; } else { - res_blocks++; + blocks++; } /* @@ -5282,8 +5280,8 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, * Assumption in DDB algorithm optimization for special * cases. Also covers Display WA #1125 for RC. */ - if (result_prev->plane_res_b > res_blocks) - res_blocks = result_prev->plane_res_b; + if (result_prev->blocks > blocks) + blocks = result_prev->blocks; } } @@ -5291,40 +5289,39 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, if (wp->y_tiled) { int extra_lines; - if (res_lines % wp->y_min_scanlines == 0) + if (lines % wp->y_min_scanlines == 0) extra_lines = wp->y_min_scanlines; else extra_lines = wp->y_min_scanlines * 2 - - res_lines % wp->y_min_scanlines; + lines % wp->y_min_scanlines; - min_ddb_alloc = mul_round_up_u32_fixed16(res_lines + extra_lines, + min_ddb_alloc = mul_round_up_u32_fixed16(lines + extra_lines, wp->plane_blocks_per_line); } else { - min_ddb_alloc = res_blocks + - DIV_ROUND_UP(res_blocks, 10); + min_ddb_alloc = blocks + DIV_ROUND_UP(blocks, 10); } } if (!skl_wm_has_lines(dev_priv, level)) - res_lines = 0; + lines = 0; - if (res_lines > 31) { + if (lines > 31) { /* reject it */ result->min_ddb_alloc = U16_MAX; return; } /* - * If res_lines is valid, assume we can use this watermark level + * If lines is valid, assume we can use this watermark level * for now. We'll come back and disable it after we calculate the * DDB allocation if it turns out we don't actually have enough * blocks to satisfy it. */ - result->plane_res_b = res_blocks; - result->plane_res_l = res_lines; + result->blocks = blocks; + result->lines = lines; /* Bspec says: value >= plane ddb allocation -> invalid, hence the +1 here */ - result->min_ddb_alloc = max(min_ddb_alloc, res_blocks) + 1; - result->plane_en = true; + result->min_ddb_alloc = max(min_ddb_alloc, blocks) + 1; + result->enable = true; if (INTEL_GEN(dev_priv) < 12) result->can_sagv = latency >= dev_priv->sagv_block_time_us; @@ -5370,7 +5367,7 @@ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, const struct skl_wm_params *wp) { u16 trans_min, trans_amount, trans_y_tile_min; - u16 wm0_sel_res_b, trans_offset_b, res_blocks; + u16 wm0_blocks, trans_offset, blocks; /* Transition WM don't make any sense if ipc is disabled */ if (!dev_priv->ipc_enabled) @@ -5394,38 +5391,37 @@ static void skl_compute_transition_wm(struct drm_i915_private *dev_priv, else trans_amount = 10; /* This is configurable amount */ - trans_offset_b = trans_min + trans_amount; + trans_offset = trans_min + trans_amount; /* * The spec asks for Selected Result Blocks for wm0 (the real value), * not Result Blocks (the integer value). Pay attention to the capital - * letters. The value wm_l0->plane_res_b is actually Result Blocks, but + * letters. The value wm_l0->blocks is actually Result Blocks, but * since Result Blocks is the ceiling of Selected Result Blocks plus 1, * and since we later will have to get the ceiling of the sum in the * transition watermarks calculation, we can just pretend Selected * Result Blocks is Result Blocks minus 1 and it should work for the * current platforms. */ - wm0_sel_res_b = wm0->plane_res_b - 1; + wm0_blocks = wm0->blocks - 1; if (wp->y_tiled) { trans_y_tile_min = (u16)mul_round_up_u32_fixed16(2, wp->y_tile_minimum); - res_blocks = max(wm0_sel_res_b, trans_y_tile_min) + - trans_offset_b; + blocks = max(wm0_blocks, trans_y_tile_min) + trans_offset; } else { - res_blocks = wm0_sel_res_b + trans_offset_b; + blocks = wm0_blocks + trans_offset; } - res_blocks++; + blocks++; /* * Just assume we can enable the transition watermark. After * computing the DDB we'll come back and disable it if that * assumption turns out to be false. */ - trans_wm->plane_res_b = res_blocks; - trans_wm->min_ddb_alloc = max_t(u16, wm0->min_ddb_alloc, res_blocks + 1); - trans_wm->plane_en = true; + trans_wm->blocks = blocks; + trans_wm->min_ddb_alloc = max_t(u16, wm0->min_ddb_alloc, blocks + 1); + trans_wm->enable = true; } static int skl_build_plane_wm_single(struct intel_crtc_state *crtc_state, @@ -5600,12 +5596,12 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv, { u32 val = 0; - if (level->plane_en) + if (level->enable) val |= PLANE_WM_EN; if (level->ignore_lines) val |= PLANE_WM_IGNORE_LINES; - val |= level->plane_res_b; - val |= level->plane_res_l << PLANE_WM_LINES_SHIFT; + val |= level->blocks; + val |= level->lines << PLANE_WM_LINES_SHIFT; intel_de_write_fw(dev_priv, reg, val); } @@ -5670,10 +5666,10 @@ void skl_write_cursor_wm(struct intel_plane *plane, bool skl_wm_level_equals(const struct skl_wm_level *l1, const struct skl_wm_level *l2) { - return l1->plane_en == l2->plane_en && + return l1->enable == l2->enable && l1->ignore_lines == l2->ignore_lines && - l1->plane_res_l == l2->plane_res_l && - l1->plane_res_b == l2->plane_res_b; + l1->lines == l2->lines && + l1->blocks == l2->blocks; } static bool skl_plane_wm_equals(struct drm_i915_private *dev_priv, @@ -5927,66 +5923,66 @@ skl_print_wm_changes(struct intel_atomic_state *state) "[PLANE:%d:%s] level %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm" " -> %cwm0,%cwm1,%cwm2,%cwm3,%cwm4,%cwm5,%cwm6,%cwm7,%ctwm,%cswm,%cstwm\n", plane->base.base.id, plane->base.name, - enast(old_wm->wm[0].plane_en), enast(old_wm->wm[1].plane_en), - enast(old_wm->wm[2].plane_en), enast(old_wm->wm[3].plane_en), - enast(old_wm->wm[4].plane_en), enast(old_wm->wm[5].plane_en), - enast(old_wm->wm[6].plane_en), enast(old_wm->wm[7].plane_en), - enast(old_wm->trans_wm.plane_en), - enast(old_wm->sagv.wm0.plane_en), - enast(old_wm->sagv.trans_wm.plane_en), - enast(new_wm->wm[0].plane_en), enast(new_wm->wm[1].plane_en), - enast(new_wm->wm[2].plane_en), enast(new_wm->wm[3].plane_en), - enast(new_wm->wm[4].plane_en), enast(new_wm->wm[5].plane_en), - enast(new_wm->wm[6].plane_en), enast(new_wm->wm[7].plane_en), - enast(new_wm->trans_wm.plane_en), - enast(new_wm->sagv.wm0.plane_en), - enast(new_wm->sagv.trans_wm.plane_en)); + enast(old_wm->wm[0].enable), enast(old_wm->wm[1].enable), + enast(old_wm->wm[2].enable), enast(old_wm->wm[3].enable), + enast(old_wm->wm[4].enable), enast(old_wm->wm[5].enable), + enast(old_wm->wm[6].enable), enast(old_wm->wm[7].enable), + enast(old_wm->trans_wm.enable), + enast(old_wm->sagv.wm0.enable), + enast(old_wm->sagv.trans_wm.enable), + enast(new_wm->wm[0].enable), enast(new_wm->wm[1].enable), + enast(new_wm->wm[2].enable), enast(new_wm->wm[3].enable), + enast(new_wm->wm[4].enable), enast(new_wm->wm[5].enable), + enast(new_wm->wm[6].enable), enast(new_wm->wm[7].enable), + enast(new_wm->trans_wm.enable), + enast(new_wm->sagv.wm0.enable), + enast(new_wm->sagv.trans_wm.enable)); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] lines %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d" " -> %c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%3d,%c%4d\n", plane->base.base.id, plane->base.name, - enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].plane_res_l, - enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].plane_res_l, - enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].plane_res_l, - enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].plane_res_l, - enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].plane_res_l, - enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].plane_res_l, - enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].plane_res_l, - enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].plane_res_l, - enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.plane_res_l, - enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.plane_res_l, - enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.plane_res_l, - enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].plane_res_l, - enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].plane_res_l, - enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].plane_res_l, - enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].plane_res_l, - enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].plane_res_l, - enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].plane_res_l, - enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].plane_res_l, - enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].plane_res_l, - enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.plane_res_l, - enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.plane_res_l, - enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.plane_res_l); + enast(old_wm->wm[0].ignore_lines), old_wm->wm[0].lines, + enast(old_wm->wm[1].ignore_lines), old_wm->wm[1].lines, + enast(old_wm->wm[2].ignore_lines), old_wm->wm[2].lines, + enast(old_wm->wm[3].ignore_lines), old_wm->wm[3].lines, + enast(old_wm->wm[4].ignore_lines), old_wm->wm[4].lines, + enast(old_wm->wm[5].ignore_lines), old_wm->wm[5].lines, + enast(old_wm->wm[6].ignore_lines), old_wm->wm[6].lines, + enast(old_wm->wm[7].ignore_lines), old_wm->wm[7].lines, + enast(old_wm->trans_wm.ignore_lines), old_wm->trans_wm.lines, + enast(old_wm->sagv.wm0.ignore_lines), old_wm->sagv.wm0.lines, + enast(old_wm->sagv.trans_wm.ignore_lines), old_wm->sagv.trans_wm.lines, + enast(new_wm->wm[0].ignore_lines), new_wm->wm[0].lines, + enast(new_wm->wm[1].ignore_lines), new_wm->wm[1].lines, + enast(new_wm->wm[2].ignore_lines), new_wm->wm[2].lines, + enast(new_wm->wm[3].ignore_lines), new_wm->wm[3].lines, + enast(new_wm->wm[4].ignore_lines), new_wm->wm[4].lines, + enast(new_wm->wm[5].ignore_lines), new_wm->wm[5].lines, + enast(new_wm->wm[6].ignore_lines), new_wm->wm[6].lines, + enast(new_wm->wm[7].ignore_lines), new_wm->wm[7].lines, + enast(new_wm->trans_wm.ignore_lines), new_wm->trans_wm.lines, + enast(new_wm->sagv.wm0.ignore_lines), new_wm->sagv.wm0.lines, + enast(new_wm->sagv.trans_wm.ignore_lines), new_wm->sagv.trans_wm.lines); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] blocks %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" " -> %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d\n", plane->base.base.id, plane->base.name, - old_wm->wm[0].plane_res_b, old_wm->wm[1].plane_res_b, - old_wm->wm[2].plane_res_b, old_wm->wm[3].plane_res_b, - old_wm->wm[4].plane_res_b, old_wm->wm[5].plane_res_b, - old_wm->wm[6].plane_res_b, old_wm->wm[7].plane_res_b, - old_wm->trans_wm.plane_res_b, - old_wm->sagv.wm0.plane_res_b, - old_wm->sagv.trans_wm.plane_res_b, - new_wm->wm[0].plane_res_b, new_wm->wm[1].plane_res_b, - new_wm->wm[2].plane_res_b, new_wm->wm[3].plane_res_b, - new_wm->wm[4].plane_res_b, new_wm->wm[5].plane_res_b, - new_wm->wm[6].plane_res_b, new_wm->wm[7].plane_res_b, - new_wm->trans_wm.plane_res_b, - new_wm->sagv.wm0.plane_res_b, - new_wm->sagv.trans_wm.plane_res_b); + old_wm->wm[0].blocks, old_wm->wm[1].blocks, + old_wm->wm[2].blocks, old_wm->wm[3].blocks, + old_wm->wm[4].blocks, old_wm->wm[5].blocks, + old_wm->wm[6].blocks, old_wm->wm[7].blocks, + old_wm->trans_wm.blocks, + old_wm->sagv.wm0.blocks, + old_wm->sagv.trans_wm.blocks, + new_wm->wm[0].blocks, new_wm->wm[1].blocks, + new_wm->wm[2].blocks, new_wm->wm[3].blocks, + new_wm->wm[4].blocks, new_wm->wm[5].blocks, + new_wm->wm[6].blocks, new_wm->wm[7].blocks, + new_wm->trans_wm.blocks, + new_wm->sagv.wm0.blocks, + new_wm->sagv.trans_wm.blocks); drm_dbg_kms(&dev_priv->drm, "[PLANE:%d:%s] min_ddb %4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%4d,%5d" @@ -6210,10 +6206,10 @@ static void ilk_optimize_watermarks(struct intel_atomic_state *state, static void skl_wm_level_from_reg_val(u32 val, struct skl_wm_level *level) { - level->plane_en = val & PLANE_WM_EN; + level->enable = val & PLANE_WM_EN; level->ignore_lines = val & PLANE_WM_IGNORE_LINES; - level->plane_res_b = val & PLANE_WM_BLOCKS_MASK; - level->plane_res_l = (val >> PLANE_WM_LINES_SHIFT) & + level->blocks = val & PLANE_WM_BLOCKS_MASK; + level->lines = (val >> PLANE_WM_LINES_SHIFT) & PLANE_WM_LINES_MASK; } From be0bdd67fda9468156c733976688f6487d0c42f7 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Fri, 5 Mar 2021 13:09:47 -0800 Subject: [PATCH 140/142] i915/perf: Start hrtimer only if sampling the OA buffer SAMPLE_OA parameter enables sampling of OA buffer and results in a call to init the OA buffer which initializes the OA unit head/tail pointers. The OA_EXPONENT parameter controls the periodicity of the OA reports in the OA buffer and results in starting a hrtimer. Before gen12, all use cases required the use of the OA buffer and i915 enforced this setting when vetting out the parameters passed. In these platforms the hrtimer was enabled if OA_EXPONENT was passed. This worked fine since it was implied that SAMPLE_OA is always passed. With gen12, this changed. Users can use perf without enabling the OA buffer as in OAR use cases. While an OAR use case should ideally not start the hrtimer, we see that passing an OA_EXPONENT parameter will start the hrtimer even though SAMPLE_OA is not specified. This results in an uninitialized OA buffer, so the head/tail pointers used to track the buffer are zero. This itself does not fail, but if we ran a use-case that SAMPLED the OA buffer previously, then the OA_TAIL register is still pointing to an old value. When the timer callback runs, it ends up calculating a wrong/large number of available reports. Since we do a spinlock_irq_save and start processing a large number of reports, NMI watchdog fires and causes a crash. Start the timer only if SAMPLE_OA is specified. v2: - Drop SAMPLE OA check when appending samples (Ashutosh) - Prevent read if OA buffer is not being sampled Fixes: 00a7f0d7155c ("drm/i915/tgl: Add perf support on TGL") Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Signed-off-by: Lionel Landwerlin Link: https://patchwork.freedesktop.org/patch/msgid/20210305210947.58751-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/i915/i915_perf.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 736c09891e245..41ad5a66657ed 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -595,7 +595,6 @@ static int append_oa_sample(struct i915_perf_stream *stream, { int report_size = stream->oa_buffer.format_size; struct drm_i915_perf_record_header header; - u32 sample_flags = stream->sample_flags; header.type = DRM_I915_PERF_RECORD_SAMPLE; header.pad = 0; @@ -609,10 +608,8 @@ static int append_oa_sample(struct i915_perf_stream *stream, return -EFAULT; buf += sizeof(header); - if (sample_flags & SAMPLE_OA_REPORT) { - if (copy_to_user(buf, report, report_size)) - return -EFAULT; - } + if (copy_to_user(buf, report, report_size)) + return -EFAULT; (*offset) += header.size; @@ -2669,7 +2666,7 @@ static void i915_oa_stream_enable(struct i915_perf_stream *stream) stream->perf->ops.oa_enable(stream); - if (stream->periodic) + if (stream->sample_flags & SAMPLE_OA_REPORT) hrtimer_start(&stream->poll_check_timer, ns_to_ktime(stream->poll_oa_period), HRTIMER_MODE_REL_PINNED); @@ -2732,7 +2729,7 @@ static void i915_oa_stream_disable(struct i915_perf_stream *stream) { stream->perf->ops.oa_disable(stream); - if (stream->periodic) + if (stream->sample_flags & SAMPLE_OA_REPORT) hrtimer_cancel(&stream->poll_check_timer); } @@ -3015,7 +3012,7 @@ static ssize_t i915_perf_read(struct file *file, * disabled stream as an error. In particular it might otherwise lead * to a deadlock for blocking file descriptors... */ - if (!stream->enabled) + if (!stream->enabled || !(stream->sample_flags & SAMPLE_OA_REPORT)) return -EIO; if (!(file->f_flags & O_NONBLOCK)) { From 65e3fe107ed7fa1b2726e63e83070e089d12c419 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Wed, 10 Mar 2021 16:47:56 -0500 Subject: [PATCH 141/142] drm/i915/dp_link_training: Add newlines to debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds some newlines which are missing from debug messages. This will prevent logs from being stacked up in dmesg. Signed-off-by: Sean Paul Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210310214845.29021-1-sean@poorly.run --- drivers/gpu/drm/i915/display/intel_dp_link_training.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 892d7db7d94f6..ad02d493ec165 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -29,7 +29,7 @@ static void intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE]) { - DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x", + DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n", link_status[0], link_status[1], link_status[2], link_status[3], link_status[4], link_status[5]); } @@ -731,7 +731,7 @@ intel_dp_link_train_phy(struct intel_dp *intel_dp, out: drm_dbg_kms(&dp_to_i915(intel_dp)->drm, - "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s", + "[CONNECTOR:%d:%s] Link Training %s at link rate = %d, lane count = %d, at %s\n", intel_connector->base.base.id, intel_connector->base.name, ret ? "passed" : "failed", From 41ed4005aa0a9d1d9d1ab8e056b0c5f6a4b12407 Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Wed, 10 Mar 2021 16:47:57 -0500 Subject: [PATCH 142/142] drm/i915/dp_link_training: Convert DRM_DEBUG_KMS to drm_dbg_kms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One instance of DRM_DEBUG_KMS was leftover in dp_link_training, convert it to the new shiny. Signed-off-by: Sean Paul Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20210310214845.29021-2-sean@poorly.run --- .../gpu/drm/i915/display/intel_dp_link_training.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index ad02d493ec165..19ba7c7cbaab9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -26,12 +26,13 @@ #include "intel_dp_link_training.h" static void -intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE]) +intel_dp_dump_link_status(struct drm_device *drm, + const u8 link_status[DP_LINK_STATUS_SIZE]) { - - DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n", - link_status[0], link_status[1], link_status[2], - link_status[3], link_status[4], link_status[5]); + drm_dbg_kms(drm, + "ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x\n", + link_status[0], link_status[1], link_status[2], + link_status[3], link_status[4], link_status[5]); } static void intel_dp_reset_lttpr_count(struct intel_dp *intel_dp) @@ -642,7 +643,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, /* Make sure clock is still ok */ if (!drm_dp_clock_recovery_ok(link_status, crtc_state->lane_count)) { - intel_dp_dump_link_status(link_status); + intel_dp_dump_link_status(&i915->drm, link_status); drm_dbg_kms(&i915->drm, "Clock recovery check failed, cannot " "continue channel equalization\n"); @@ -669,7 +670,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp, /* Try 5 times, else fail and try at lower BW */ if (tries == 5) { - intel_dp_dump_link_status(link_status); + intel_dp_dump_link_status(&i915->drm, link_status); drm_dbg_kms(&i915->drm, "Channel equalization failed 5 times\n"); }