diff options
42 files changed, 842 insertions, 369 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 84ec79b64960..49c86a0d44f9 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -156,6 +156,7 @@ gem-y += \ gem/i915_gem_lmem.o \ gem/i915_gem_mman.o \ gem/i915_gem_object.o \ + gem/i915_gem_object_frontbuffer.o \ gem/i915_gem_pages.o \ gem/i915_gem_phys.o \ gem/i915_gem_pm.o \ diff --git a/drivers/gpu/drm/i915/display/intel_bo.c b/drivers/gpu/drm/i915/display/intel_bo.c index 6ae1374d5c2b..f3687eb63467 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.c +++ b/drivers/gpu/drm/i915/display/intel_bo.c @@ -29,11 +29,6 @@ bool intel_bo_is_protected(struct drm_gem_object *obj) return i915_gem_object_is_protected(to_intel_bo(obj)); } -void intel_bo_flush_if_display(struct drm_gem_object *obj) -{ - i915_gem_object_flush_if_display(to_intel_bo(obj)); -} - int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { return i915_gem_fb_mmap(to_intel_bo(obj), vma); @@ -44,15 +39,40 @@ int intel_bo_read_from_page(struct drm_gem_object *obj, u64 offset, void *dst, i return i915_gem_object_read_from_page(to_intel_bo(obj), offset, dst, size); } -struct intel_frontbuffer *intel_bo_get_frontbuffer(struct drm_gem_object *obj) +struct intel_frontbuffer *intel_bo_frontbuffer_get(struct drm_gem_object *_obj) +{ + struct drm_i915_gem_object *obj = to_intel_bo(_obj); + struct i915_frontbuffer *front; + + front = i915_gem_object_frontbuffer_get(obj); + if (!front) + return NULL; + + return &front->base; +} + +void intel_bo_frontbuffer_ref(struct intel_frontbuffer *_front) { - return i915_gem_object_get_frontbuffer(to_intel_bo(obj)); + struct i915_frontbuffer *front = + container_of(_front, typeof(*front), base); + + i915_gem_object_frontbuffer_ref(front); } -struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj, - struct intel_frontbuffer *front) +void intel_bo_frontbuffer_put(struct intel_frontbuffer *_front) { - return i915_gem_object_set_frontbuffer(to_intel_bo(obj), front); + struct i915_frontbuffer *front = + container_of(_front, typeof(*front), base); + + return i915_gem_object_frontbuffer_put(front); +} + +void intel_bo_frontbuffer_flush_for_display(struct intel_frontbuffer *_front) +{ + struct i915_frontbuffer *front = + container_of(_front, typeof(*front), base); + + i915_gem_object_flush_if_display(front->obj); } void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/i915/display/intel_bo.h b/drivers/gpu/drm/i915/display/intel_bo.h index 48d87019e48a..fc05f680dc76 100644 --- a/drivers/gpu/drm/i915/display/intel_bo.h +++ b/drivers/gpu/drm/i915/display/intel_bo.h @@ -16,13 +16,13 @@ bool intel_bo_is_tiled(struct drm_gem_object *obj); bool intel_bo_is_userptr(struct drm_gem_object *obj); bool intel_bo_is_shmem(struct drm_gem_object *obj); bool intel_bo_is_protected(struct drm_gem_object *obj); -void intel_bo_flush_if_display(struct drm_gem_object *obj); int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); int intel_bo_read_from_page(struct drm_gem_object *obj, u64 offset, void *dst, int size); -struct intel_frontbuffer *intel_bo_get_frontbuffer(struct drm_gem_object *obj); -struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj, - struct intel_frontbuffer *front); +struct intel_frontbuffer *intel_bo_frontbuffer_get(struct drm_gem_object *obj); +void intel_bo_frontbuffer_ref(struct intel_frontbuffer *front); +void intel_bo_frontbuffer_put(struct intel_frontbuffer *front); +void intel_bo_frontbuffer_flush_for_display(struct intel_frontbuffer *front); void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index f97ccc1a96a7..1f6461be50ef 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -805,29 +805,40 @@ void intel_bw_init_hw(struct intel_display *display) if (!HAS_DISPLAY(display)) return; - if (DISPLAY_VERx100(display) >= 3002) - tgl_get_bw_info(display, dram_info, &xe3lpd_3002_sa_info); - else if (DISPLAY_VER(display) >= 30) - tgl_get_bw_info(display, dram_info, &xe3lpd_sa_info); - else if (DISPLAY_VERx100(display) >= 1401 && display->platform.dgfx && - dram_info->type == INTEL_DRAM_GDDR_ECC) - xe2_hpd_get_bw_info(display, dram_info, &xe2_hpd_ecc_sa_info); - else if (DISPLAY_VERx100(display) >= 1401 && display->platform.dgfx) - xe2_hpd_get_bw_info(display, dram_info, &xe2_hpd_sa_info); - else if (DISPLAY_VER(display) >= 14) + /* + * Starting with Xe3p_LPD, the hardware tells us whether memory has ECC + * enabled that would impact display bandwidth. However, so far there + * are no instructions in Bspec on how to handle that case. Let's + * complain if we ever find such a scenario. + */ + if (DISPLAY_VER(display) >= 35) + drm_WARN_ON(display->drm, dram_info->ecc_impacting_de_bw); + + if (DISPLAY_VER(display) >= 30) { + if (DISPLAY_VERx100(display) == 3002) + tgl_get_bw_info(display, dram_info, &xe3lpd_3002_sa_info); + else + tgl_get_bw_info(display, dram_info, &xe3lpd_sa_info); + } else if (DISPLAY_VERx100(display) >= 1401 && display->platform.dgfx) { + if (dram_info->type == INTEL_DRAM_GDDR_ECC) + xe2_hpd_get_bw_info(display, dram_info, &xe2_hpd_ecc_sa_info); + else + xe2_hpd_get_bw_info(display, dram_info, &xe2_hpd_sa_info); + } else if (DISPLAY_VER(display) >= 14) { tgl_get_bw_info(display, dram_info, &mtl_sa_info); - else if (display->platform.dg2) + } else if (display->platform.dg2) { dg2_get_bw_info(display); - else if (display->platform.alderlake_p) + } else if (display->platform.alderlake_p) { tgl_get_bw_info(display, dram_info, &adlp_sa_info); - else if (display->platform.alderlake_s) + } else if (display->platform.alderlake_s) { tgl_get_bw_info(display, dram_info, &adls_sa_info); - else if (display->platform.rocketlake) + } else if (display->platform.rocketlake) { tgl_get_bw_info(display, dram_info, &rkl_sa_info); - else if (DISPLAY_VER(display) == 12) + } else if (DISPLAY_VER(display) == 12) { tgl_get_bw_info(display, dram_info, &tgl_sa_info); - else if (DISPLAY_VER(display) == 11) + } else if (DISPLAY_VER(display) == 11) { icl_get_bw_info(display, dram_info, &icl_sa_info); + } } static unsigned int intel_bw_num_active_planes(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index bdb42fcc4cb2..4d03cfefc72c 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1535,6 +1535,41 @@ static const struct intel_cdclk_vals xe3lpd_cdclk_table[] = { {} }; +static const struct intel_cdclk_vals xe3p_lpd_cdclk_table[] = { + { .refclk = 38400, .cdclk = 151200, .ratio = 21, .waveform = 0xa4a4 }, + { .refclk = 38400, .cdclk = 176400, .ratio = 21, .waveform = 0xaa54 }, + { .refclk = 38400, .cdclk = 201600, .ratio = 21, .waveform = 0xaaaa }, + { .refclk = 38400, .cdclk = 226800, .ratio = 21, .waveform = 0xad5a }, + { .refclk = 38400, .cdclk = 252000, .ratio = 21, .waveform = 0xb6b6 }, + { .refclk = 38400, .cdclk = 277200, .ratio = 21, .waveform = 0xdbb6 }, + { .refclk = 38400, .cdclk = 302400, .ratio = 21, .waveform = 0xeeee }, + { .refclk = 38400, .cdclk = 327600, .ratio = 21, .waveform = 0xf7de }, + { .refclk = 38400, .cdclk = 352800, .ratio = 21, .waveform = 0xfefe }, + { .refclk = 38400, .cdclk = 378000, .ratio = 21, .waveform = 0xfffe }, + { .refclk = 38400, .cdclk = 403200, .ratio = 21, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 422400, .ratio = 22, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 441600, .ratio = 23, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 460800, .ratio = 24, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 480000, .ratio = 25, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 499200, .ratio = 26, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 518400, .ratio = 27, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 537600, .ratio = 28, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 556800, .ratio = 29, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 576000, .ratio = 30, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 595200, .ratio = 31, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 614400, .ratio = 32, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 633600, .ratio = 33, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 652800, .ratio = 34, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 672000, .ratio = 35, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 691200, .ratio = 36, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 710400, .ratio = 37, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 729600, .ratio = 38, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 748800, .ratio = 39, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 768000, .ratio = 40, .waveform = 0xffff }, + { .refclk = 38400, .cdclk = 787200, .ratio = 41, .waveform = 0xffff }, + {} +}; + static const int cdclk_squash_len = 16; static int cdclk_squash_divider(u16 waveform) @@ -3561,7 +3596,9 @@ static int intel_compute_max_dotclk(struct intel_display *display) */ void intel_update_max_cdclk(struct intel_display *display) { - if (DISPLAY_VERx100(display) >= 3002) { + if (DISPLAY_VER(display) >= 35) { + display->cdclk.max_cdclk_freq = 787200; + } else if (DISPLAY_VERx100(display) >= 3002) { display->cdclk.max_cdclk_freq = 480000; } else if (DISPLAY_VER(display) >= 30) { display->cdclk.max_cdclk_freq = 691200; @@ -3912,7 +3949,10 @@ static const struct intel_cdclk_funcs i830_cdclk_funcs = { */ void intel_init_cdclk_hooks(struct intel_display *display) { - if (DISPLAY_VER(display) >= 30) { + if (DISPLAY_VER(display) >= 35) { + display->funcs.cdclk = &xe3lpd_cdclk_funcs; + display->cdclk.table = xe3p_lpd_cdclk_table; + } else if (DISPLAY_VER(display) >= 30) { display->funcs.cdclk = &xe3lpd_cdclk_funcs; display->cdclk.table = xe3lpd_cdclk_table; } else if (DISPLAY_VER(display) >= 20) { diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 1e97020e7304..a217a67ceb43 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -1090,18 +1090,19 @@ static void skl_get_config(struct intel_crtc_state *crtc_state) { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - u32 tmp; crtc_state->gamma_mode = hsw_read_gamma_mode(crtc); crtc_state->csc_mode = ilk_read_csc_mode(crtc); - tmp = intel_de_read(display, SKL_BOTTOM_COLOR(crtc->pipe)); + if (DISPLAY_VER(display) < 35) { + u32 tmp = intel_de_read(display, SKL_BOTTOM_COLOR(crtc->pipe)); - if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) - crtc_state->gamma_enable = true; + if (tmp & SKL_BOTTOM_COLOR_GAMMA_ENABLE) + crtc_state->gamma_enable = true; - if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) - crtc_state->csc_enable = true; + if (tmp & SKL_BOTTOM_COLOR_CSC_ENABLE) + crtc_state->csc_enable = true; + } } static void skl_color_commit_arm(struct intel_dsb *dsb, diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index b3b506d0e040..1551d30ec584 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -147,7 +147,7 @@ void intel_cx0_bus_reset(struct intel_encoder *encoder, int lane) if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_M2P_TRANSACTION_RESET, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_err_once(display->drm, "Failed to bring PHY %c to idle.\n", phy_name(phy)); @@ -168,8 +168,7 @@ int intel_cx0_wait_for_ack(struct intel_encoder *encoder, XELPDP_PORT_P2M_MSGBUS_STATUS(display, port, lane), XELPDP_PORT_P2M_RESPONSE_READY, XELPDP_PORT_P2M_RESPONSE_READY, - XELPDP_MSGBUS_TIMEOUT_FAST_US, - XELPDP_MSGBUS_TIMEOUT_SLOW, val)) { + 2, XELPDP_MSGBUS_TIMEOUT_MS, val)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for message ACK. Status: 0x%x\n", phy_name(phy), *val); @@ -216,7 +215,7 @@ static int __intel_cx0_read_once(struct intel_encoder *encoder, if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus and retry.\n", phy_name(phy)); intel_cx0_bus_reset(encoder, lane); @@ -287,7 +286,7 @@ static int __intel_cx0_write_once(struct intel_encoder *encoder, if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for previous transaction to complete. Resetting the bus.\n", phy_name(phy)); intel_cx0_bus_reset(encoder, lane); @@ -303,7 +302,7 @@ static int __intel_cx0_write_once(struct intel_encoder *encoder, if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for write to complete. Resetting the bus.\n", phy_name(phy)); intel_cx0_bus_reset(encoder, lane); @@ -2816,7 +2815,7 @@ void intel_cx0_powerdown_change_sequence(struct intel_encoder *encoder, for_each_cx0_lane_in_mask(lane_mask, lane) if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_M2P_TRANSACTION_PENDING, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for previous transaction to complete. Reset the bus.\n", phy_name(phy)); @@ -2830,10 +2829,10 @@ void intel_cx0_powerdown_change_sequence(struct intel_encoder *encoder, /* Update Timeout Value */ if (intel_de_wait_custom(display, buf_ctl2_reg, intel_cx0_get_powerdown_update(lane_mask), 0, - XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US, 2, NULL)) + 2, XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_MS, NULL)) drm_warn(display->drm, - "PHY %c failed to bring out of Lane reset after %dus.\n", - phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); + "PHY %c failed to bring out of lane reset\n", + phy_name(phy)); } void intel_cx0_setup_powerdown(struct intel_encoder *encoder) @@ -2894,8 +2893,8 @@ static void intel_cx0_phy_lane_reset(struct intel_encoder *encoder, XELPDP_PORT_BUF_SOC_PHY_READY, XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US, 0, NULL)) drm_warn(display->drm, - "PHY %c failed to bring out of SOC reset after %dus.\n", - phy_name(phy), XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US); + "PHY %c failed to bring out of SOC reset\n", + phy_name(phy)); intel_de_rmw(display, XELPDP_PORT_BUF_CTL2(display, port), lane_pipe_reset, lane_pipe_reset); @@ -2904,8 +2903,8 @@ static void intel_cx0_phy_lane_reset(struct intel_encoder *encoder, lane_phy_current_status, lane_phy_current_status, XELPDP_PORT_RESET_START_TIMEOUT_US, 0, NULL)) drm_warn(display->drm, - "PHY %c failed to bring out of Lane reset after %dus.\n", - phy_name(phy), XELPDP_PORT_RESET_START_TIMEOUT_US); + "PHY %c failed to bring out of lane reset\n", + phy_name(phy)); intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, port), intel_cx0_get_pclk_refclk_request(owned_lane_mask), @@ -2916,8 +2915,8 @@ static void intel_cx0_phy_lane_reset(struct intel_encoder *encoder, intel_cx0_get_pclk_refclk_ack(lane_mask), XELPDP_REFCLK_ENABLE_TIMEOUT_US, 0, NULL)) drm_warn(display->drm, - "PHY %c failed to request refclk after %dus.\n", - phy_name(phy), XELPDP_REFCLK_ENABLE_TIMEOUT_US); + "PHY %c failed to request refclk\n", + phy_name(phy)); intel_cx0_powerdown_change_sequence(encoder, INTEL_CX0_BOTH_LANES, XELPDP_P2_STATE_RESET); @@ -2927,10 +2926,10 @@ static void intel_cx0_phy_lane_reset(struct intel_encoder *encoder, if (intel_de_wait_for_clear(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_current_status, - XELPDP_PORT_RESET_END_TIMEOUT)) + XELPDP_PORT_RESET_END_TIMEOUT_MS)) drm_warn(display->drm, - "PHY %c failed to bring out of Lane reset after %dms.\n", - phy_name(phy), XELPDP_PORT_RESET_END_TIMEOUT); + "PHY %c failed to bring out of lane reset\n", + phy_name(phy)); } static void intel_cx0_program_phy_lane(struct intel_encoder *encoder, int lane_count, @@ -3069,8 +3068,8 @@ static void __intel_cx0pll_enable(struct intel_encoder *encoder, intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES), intel_cx0_get_pclk_pll_ack(maxpclk_lane), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US, 0, NULL)) - drm_warn(display->drm, "Port %c PLL not locked after %dus.\n", - phy_name(phy), XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US); + drm_warn(display->drm, "Port %c PLL not locked\n", + phy_name(phy)); /* * 11. Follow the Display Voltage Frequency Switching Sequence After @@ -3193,8 +3192,7 @@ void intel_mtl_tbt_pll_enable(struct intel_encoder *encoder, XELPDP_TBT_CLOCK_ACK, XELPDP_TBT_CLOCK_ACK, 100, 0, NULL)) - drm_warn(display->drm, - "[ENCODER:%d:%s][%c] PHY PLL not locked after 100us.\n", + drm_warn(display->drm, "[ENCODER:%d:%s][%c] PHY PLL not locked\n", encoder->base.base.id, encoder->base.name, phy_name(phy)); /* @@ -3308,9 +3306,8 @@ static void intel_cx0pll_disable(struct intel_encoder *encoder) intel_cx0_get_pclk_pll_ack(INTEL_CX0_BOTH_LANES) | intel_cx0_get_pclk_refclk_ack(INTEL_CX0_BOTH_LANES), 0, XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US, 0, NULL)) - drm_warn(display->drm, - "Port %c PLL not unlocked after %dus.\n", - phy_name(phy), XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US); + drm_warn(display->drm, "Port %c PLL not unlocked\n", + phy_name(phy)); /* * 6. Follow the Display Voltage Frequency Switching Sequence After @@ -3355,8 +3352,7 @@ void intel_mtl_tbt_pll_disable(struct intel_encoder *encoder) /* 3. Poll on PORT_CLOCK_CTL TBT CLOCK Ack == "0". */ if (intel_de_wait_custom(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port), XELPDP_TBT_CLOCK_ACK, 0, 10, 0, NULL)) - drm_warn(display->drm, - "[ENCODER:%d:%s][%c] PHY PLL not unlocked after 10us.\n", + drm_warn(display->drm, "[ENCODER:%d:%s][%c] PHY PLL not unlocked\n", encoder->base.base.id, encoder->base.name, phy_name(phy)); /* diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h index 635b35669348..8df5cd5ce418 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy_regs.h @@ -74,14 +74,13 @@ #define XELPDP_PORT_P2M_DATA(val) REG_FIELD_PREP(XELPDP_PORT_P2M_DATA_MASK, val) #define XELPDP_PORT_P2M_ERROR_SET REG_BIT(15) -#define XELPDP_MSGBUS_TIMEOUT_SLOW 1 -#define XELPDP_MSGBUS_TIMEOUT_FAST_US 2 +#define XELPDP_MSGBUS_TIMEOUT_MS 1 #define XELPDP_PCLK_PLL_ENABLE_TIMEOUT_US 3200 #define XELPDP_PCLK_PLL_DISABLE_TIMEOUT_US 20 #define XELPDP_PORT_BUF_SOC_READY_TIMEOUT_US 100 #define XELPDP_PORT_RESET_START_TIMEOUT_US 5 -#define XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_US 100 -#define XELPDP_PORT_RESET_END_TIMEOUT 15 +#define XELPDP_PORT_POWERDOWN_UPDATE_TIMEOUT_MS 2 +#define XELPDP_PORT_RESET_END_TIMEOUT_MS 15 #define XELPDP_REFCLK_ENABLE_TIMEOUT_US 1 #define _XELPDP_PORT_BUF_CTL1_LN0_A 0x64004 diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 42ec78798666..25986bd8fbdd 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -2658,7 +2658,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta crtc_vblank_start = crtc_vdisplay + crtc_state->set_context_latency; } - if (DISPLAY_VER(display) >= 4) + if (DISPLAY_VER(display) >= 4 && DISPLAY_VER(display) < 35) intel_de_write(display, TRANS_VSYNCSHIFT(display, cpu_transcoder), vsyncshift); @@ -2799,7 +2799,7 @@ static bool intel_pipe_is_interlaced(const struct intel_crtc_state *crtc_state) struct intel_display *display = to_intel_display(crtc_state); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; - if (DISPLAY_VER(display) == 2) + if (DISPLAY_VER(display) == 2 || DISPLAY_VER(display) >= 35) return false; if (DISPLAY_VER(display) >= 9 || @@ -3190,10 +3190,12 @@ static void hsw_set_transconf(const struct intel_crtc_state *crtc_state) if (display->platform.haswell && crtc_state->dither) val |= TRANSCONF_DITHER_EN | TRANSCONF_DITHER_TYPE_SP; - if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) - val |= TRANSCONF_INTERLACE_IF_ID_ILK; - else - val |= TRANSCONF_INTERLACE_PF_PD_ILK; + if (DISPLAY_VER(display) < 35) { + if (crtc_state->hw.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) + val |= TRANSCONF_INTERLACE_IF_ID_ILK; + else + val |= TRANSCONF_INTERLACE_PF_PD_ILK; + } if (display->platform.haswell && crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 893279be8409..9b8414b77c15 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -142,14 +142,13 @@ struct intel_dpll_global { }; struct intel_frontbuffer_tracking { + /* protects busy_bits */ spinlock_t lock; /* - * Tracking bits for delayed frontbuffer flushing du to gpu activity or - * scheduled flips. + * Tracking bits for delayed frontbuffer flushing due to gpu activity. */ unsigned busy_bits; - unsigned flip_bits; }; struct intel_hotplug { diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 0b3fd65dac0f..9bbfdae8d024 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -78,9 +78,6 @@ static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) seq_printf(m, "FB tracking busy bits: 0x%08x\n", display->fb_tracking.busy_bits); - seq_printf(m, "FB tracking flip bits: 0x%08x\n", - display->fb_tracking.flip_bits); - spin_unlock(&display->fb_tracking.lock); return 0; diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 328447a5e5e8..1170afaa8680 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -1507,6 +1507,7 @@ static const struct { { 20, 0, &xe2_lpd_display }, { 30, 0, &xe2_lpd_display }, { 30, 2, &wcl_display }, + { 35, 0, &xe2_lpd_display }, }; static const struct intel_display_device_info * diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index fbfa823b6dce..74fcd9cfe911 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -1438,6 +1438,9 @@ static void intel_pch_reset_handshake(struct intel_display *display, i915_reg_t reg; u32 reset_bits; + if (DISPLAY_VER(display) >= 35) + return; + if (display->platform.ivybridge) { reg = GEN7_MSG_CTL; reset_bits = WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK; diff --git a/drivers/gpu/drm/i915/display/intel_display_wa.c b/drivers/gpu/drm/i915/display/intel_display_wa.c index c528aaa679ca..e38e5e87877c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_wa.c +++ b/drivers/gpu/drm/i915/display/intel_display_wa.c @@ -49,7 +49,8 @@ void intel_display_wa_apply(struct intel_display *display) */ static bool intel_display_needs_wa_16025573575(struct intel_display *display) { - return DISPLAY_VERx100(display) == 3000 || DISPLAY_VERx100(display) == 3002; + return DISPLAY_VERx100(display) == 3000 || DISPLAY_VERx100(display) == 3002 || + DISPLAY_VERx100(display) == 3500; } /* diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 0bddb20a7c86..6ebbd97e6351 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -127,6 +127,9 @@ static bool dmc_firmware_param_disabled(struct intel_display *display) #define DISPLAY_VER13_DMC_MAX_FW_SIZE 0x20000 #define DISPLAY_VER12_DMC_MAX_FW_SIZE ICL_DMC_MAX_FW_SIZE +#define XE3P_LPD_DMC_PATH DMC_PATH(xe3p_lpd) +MODULE_FIRMWARE(XE3P_LPD_DMC_PATH); + #define XE3LPD_3002_DMC_PATH DMC_PATH(xe3lpd_3002) MODULE_FIRMWARE(XE3LPD_3002_DMC_PATH); @@ -186,7 +189,11 @@ static const char *dmc_firmware_default(struct intel_display *display, u32 *size { const char *fw_path = NULL; u32 max_fw_size = 0; - if (DISPLAY_VERx100(display) == 3002) { + + if (DISPLAY_VERx100(display) == 3500) { + fw_path = XE3P_LPD_DMC_PATH; + max_fw_size = XE2LPD_DMC_MAX_FW_SIZE; + } else if (DISPLAY_VERx100(display) == 3002) { fw_path = XE3LPD_3002_DMC_PATH; max_fw_size = XE2LPD_DMC_MAX_FW_SIZE; } else if (DISPLAY_VERx100(display) == 3000) { @@ -711,11 +718,11 @@ static bool need_pipedmc_load_program(struct intel_display *display) static bool need_pipedmc_load_mmio(struct intel_display *display, enum pipe pipe) { /* - * PTL: + * Xe3_LPD/Xe3p_LPD: * - pipe A/B DMC doesn't need save/restore * - pipe C/D DMC is in PG0, needs manual save/restore */ - if (DISPLAY_VER(display) == 30) + if (IS_DISPLAY_VER(display, 30, 35)) return pipe >= PIPE_C; /* @@ -1712,14 +1719,14 @@ void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC GTT fault\n", crtc->base.base.id, crtc->base.name); if (tmp & PIPEDMC_ERROR) - drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC error\n", + drm_err(display->drm, "[CRTC:%d:%s] PIPEDMC error\n", crtc->base.base.id, crtc->base.name); } int_vector = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; if (tmp == 0 && int_vector != 0) - drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n", - crtc->base.base.id, crtc->base.name, tmp); + drm_err(display->drm, "[CRTC:%d:%s] PIPEDMC interrupt vector 0x%x\n", + crtc->base.base.id, crtc->base.name, int_vector); } void intel_pipedmc_enable_event(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 064c0d3e8177..f9e0333e2674 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -2194,7 +2194,6 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, return ret; flush: - intel_bo_flush_if_display(obj); intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); return ret; } diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index c88bef22d366..03c4978fa5ec 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -58,8 +58,6 @@ #include <drm/drm_gem.h> #include <drm/drm_print.h> -#include "i915_active.h" -#include "i915_vma.h" #include "intel_bo.h" #include "intel_display_trace.h" #include "intel_display_types.h" @@ -104,51 +102,6 @@ static void frontbuffer_flush(struct intel_display *display, } /** - * intel_frontbuffer_flip_prepare - prepare asynchronous frontbuffer flip - * @display: display device - * @frontbuffer_bits: frontbuffer plane tracking bits - * - * This function gets called after scheduling a flip on @obj. The actual - * frontbuffer flushing will be delayed until completion is signalled with - * intel_frontbuffer_flip_complete. If an invalidate happens in between this - * flush will be cancelled. - * - * Can be called without any locks held. - */ -void intel_frontbuffer_flip_prepare(struct intel_display *display, - unsigned frontbuffer_bits) -{ - spin_lock(&display->fb_tracking.lock); - display->fb_tracking.flip_bits |= frontbuffer_bits; - /* Remove stale busy bits due to the old buffer. */ - display->fb_tracking.busy_bits &= ~frontbuffer_bits; - spin_unlock(&display->fb_tracking.lock); -} - -/** - * intel_frontbuffer_flip_complete - complete asynchronous frontbuffer flip - * @display: display device - * @frontbuffer_bits: frontbuffer plane tracking bits - * - * This function gets called after the flip has been latched and will complete - * on the next vblank. It will execute the flush if it hasn't been cancelled yet. - * - * Can be called without any locks held. - */ -void intel_frontbuffer_flip_complete(struct intel_display *display, - unsigned frontbuffer_bits) -{ - spin_lock(&display->fb_tracking.lock); - /* Mask any cancelled flips. */ - frontbuffer_bits &= display->fb_tracking.flip_bits; - display->fb_tracking.flip_bits &= ~frontbuffer_bits; - spin_unlock(&display->fb_tracking.lock); - - if (frontbuffer_bits) - frontbuffer_flush(display, frontbuffer_bits, ORIGIN_FLIP); -} - -/** * intel_frontbuffer_flip - synchronous frontbuffer flip * @display: display device * @frontbuffer_bits: frontbuffer plane tracking bits @@ -174,12 +127,11 @@ void __intel_fb_invalidate(struct intel_frontbuffer *front, enum fb_op_origin origin, unsigned int frontbuffer_bits) { - struct intel_display *display = to_intel_display(front->obj->dev); + struct intel_display *display = front->display; if (origin == ORIGIN_CS) { spin_lock(&display->fb_tracking.lock); display->fb_tracking.busy_bits |= frontbuffer_bits; - display->fb_tracking.flip_bits &= ~frontbuffer_bits; spin_unlock(&display->fb_tracking.lock); } @@ -195,7 +147,10 @@ void __intel_fb_flush(struct intel_frontbuffer *front, enum fb_op_origin origin, unsigned int frontbuffer_bits) { - struct intel_display *display = to_intel_display(front->obj->dev); + struct intel_display *display = front->display; + + if (origin == ORIGIN_DIRTYFB) + intel_bo_frontbuffer_flush_for_display(front); if (origin == ORIGIN_CS) { spin_lock(&display->fb_tracking.lock); @@ -209,12 +164,16 @@ void __intel_fb_flush(struct intel_frontbuffer *front, frontbuffer_flush(display, frontbuffer_bits, origin); } +static void intel_frontbuffer_ref(struct intel_frontbuffer *front) +{ + intel_bo_frontbuffer_ref(front); +} + static void intel_frontbuffer_flush_work(struct work_struct *work) { struct intel_frontbuffer *front = container_of(work, struct intel_frontbuffer, flush_work); - intel_bo_flush_if_display(front->obj); intel_frontbuffer_flush(front, ORIGIN_DIRTYFB); intel_frontbuffer_put(front); } @@ -231,93 +190,31 @@ void intel_frontbuffer_queue_flush(struct intel_frontbuffer *front) if (!front) return; - kref_get(&front->ref); + intel_frontbuffer_ref(front); if (!schedule_work(&front->flush_work)) intel_frontbuffer_put(front); } -static int frontbuffer_active(struct i915_active *ref) +void intel_frontbuffer_init(struct intel_frontbuffer *front, struct drm_device *drm) { - struct intel_frontbuffer *front = - container_of(ref, typeof(*front), write); - - kref_get(&front->ref); - return 0; + front->display = to_intel_display(drm); + atomic_set(&front->bits, 0); + INIT_WORK(&front->flush_work, intel_frontbuffer_flush_work); } -static void frontbuffer_retire(struct i915_active *ref) +void intel_frontbuffer_fini(struct intel_frontbuffer *front) { - struct intel_frontbuffer *front = - container_of(ref, typeof(*front), write); - - intel_frontbuffer_flush(front, ORIGIN_CS); - intel_frontbuffer_put(front); + drm_WARN_ON(front->display->drm, atomic_read(&front->bits)); } -static void frontbuffer_release(struct kref *ref) - __releases(&to_intel_display(front->obj->dev)->fb_tracking.lock) +struct intel_frontbuffer *intel_frontbuffer_get(struct drm_gem_object *obj) { - struct intel_frontbuffer *ret, *front = - container_of(ref, typeof(*front), ref); - struct drm_gem_object *obj = front->obj; - struct intel_display *display = to_intel_display(obj->dev); - - drm_WARN_ON(display->drm, atomic_read(&front->bits)); - - i915_ggtt_clear_scanout(to_intel_bo(obj)); - - ret = intel_bo_set_frontbuffer(obj, NULL); - drm_WARN_ON(display->drm, ret); - spin_unlock(&display->fb_tracking.lock); - - i915_active_fini(&front->write); - - drm_gem_object_put(obj); - kfree_rcu(front, rcu); -} - -struct intel_frontbuffer * -intel_frontbuffer_get(struct drm_gem_object *obj) -{ - struct intel_display *display = to_intel_display(obj->dev); - struct intel_frontbuffer *front, *cur; - - front = intel_bo_get_frontbuffer(obj); - if (front) - return front; - - front = kmalloc(sizeof(*front), GFP_KERNEL); - if (!front) - return NULL; - - drm_gem_object_get(obj); - - front->obj = obj; - kref_init(&front->ref); - atomic_set(&front->bits, 0); - i915_active_init(&front->write, - frontbuffer_active, - frontbuffer_retire, - I915_ACTIVE_RETIRE_SLEEPS); - INIT_WORK(&front->flush_work, intel_frontbuffer_flush_work); - - spin_lock(&display->fb_tracking.lock); - cur = intel_bo_set_frontbuffer(obj, front); - spin_unlock(&display->fb_tracking.lock); - - if (cur != front) { - drm_gem_object_put(obj); - kfree(front); - } - - return cur; + return intel_bo_frontbuffer_get(obj); } void intel_frontbuffer_put(struct intel_frontbuffer *front) { - kref_put_lock(&front->ref, - frontbuffer_release, - &to_intel_display(front->obj->dev)->fb_tracking.lock); + intel_bo_frontbuffer_put(front); } /** @@ -346,17 +243,13 @@ void intel_frontbuffer_track(struct intel_frontbuffer *old, BUILD_BUG_ON(I915_MAX_PLANES > INTEL_FRONTBUFFER_BITS_PER_PIPE); if (old) { - struct intel_display *display = to_intel_display(old->obj->dev); - - drm_WARN_ON(display->drm, + drm_WARN_ON(old->display->drm, !(atomic_read(&old->bits) & frontbuffer_bits)); atomic_andnot(frontbuffer_bits, &old->bits); } if (new) { - struct intel_display *display = to_intel_display(new->obj->dev); - - drm_WARN_ON(display->drm, + drm_WARN_ON(new->display->drm, atomic_read(&new->bits) & frontbuffer_bits); atomic_or(frontbuffer_bits, &new->bits); } diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.h b/drivers/gpu/drm/i915/display/intel_frontbuffer.h index 2fee12eaf9b6..22677acb4c06 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.h +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.h @@ -26,10 +26,9 @@ #include <linux/atomic.h> #include <linux/bits.h> -#include <linux/kref.h> - -#include "i915_active_types.h" +#include <linux/workqueue_types.h> +struct drm_device; struct drm_gem_object; struct intel_display; @@ -42,12 +41,8 @@ enum fb_op_origin { }; struct intel_frontbuffer { - struct kref ref; + struct intel_display *display; atomic_t bits; - struct i915_active write; - struct drm_gem_object *obj; - struct rcu_head rcu; - struct work_struct flush_work; }; @@ -68,10 +63,6 @@ struct intel_frontbuffer { GENMASK(INTEL_FRONTBUFFER_BITS_PER_PIPE * ((pipe) + 1) - 1, \ INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)) -void intel_frontbuffer_flip_prepare(struct intel_display *display, - unsigned frontbuffer_bits); -void intel_frontbuffer_flip_complete(struct intel_display *display, - unsigned frontbuffer_bits); void intel_frontbuffer_flip(struct intel_display *display, unsigned frontbuffer_bits); @@ -144,4 +135,7 @@ void intel_frontbuffer_track(struct intel_frontbuffer *old, struct intel_frontbuffer *new, unsigned int frontbuffer_bits); +void intel_frontbuffer_init(struct intel_frontbuffer *front, struct drm_device *drm); +void intel_frontbuffer_fini(struct intel_frontbuffer *front); + #endif /* __INTEL_FRONTBUFFER_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index 7195e8cf671c..d01733b6460e 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -412,7 +412,7 @@ static int intel_hdcp_load_keys(struct intel_display *display) /* Wait for the keys to load (500us) */ ret = intel_de_wait_custom(display, HDCP_KEY_STATUS, HDCP_KEY_LOAD_DONE, HDCP_KEY_LOAD_DONE, - 10, 1, &val); + 2, 1, &val); if (ret) return ret; else if (!(val & HDCP_KEY_LOAD_STATUS)) diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index af48d6cde226..b2413b385dc8 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -31,6 +31,32 @@ #define INTEL_LT_PHY_BOTH_LANES (INTEL_LT_PHY_LANE1 |\ INTEL_LT_PHY_LANE0) #define MODE_DP 3 +#define Q32_TO_INT(x) ((x) >> 32) +#define Q32_TO_FRAC(x) ((x) & 0xFFFFFFFF) +#define DCO_MIN_FREQ_MHZ 11850 +#define REF_CLK_KHZ 38400 +#define TDC_RES_MULTIPLIER 10000000ULL + +struct phy_param_t { + u32 val; + u32 addr; +}; + +struct lt_phy_params { + struct phy_param_t pll_reg4; + struct phy_param_t pll_reg3; + struct phy_param_t pll_reg5; + struct phy_param_t pll_reg57; + struct phy_param_t lf; + struct phy_param_t tdc; + struct phy_param_t ssc; + struct phy_param_t bias2; + struct phy_param_t bias_trim; + struct phy_param_t dco_med; + struct phy_param_t dco_fine; + struct phy_param_t ssc_inj; + struct phy_param_t surv_bonus; +}; static const struct intel_lt_phy_pll_state xe3plpd_lt_dp_rbr = { .clock = 162000, @@ -1043,7 +1069,7 @@ static int __intel_lt_phy_p2p_write_once(struct intel_encoder *encoder, if (intel_de_wait_for_clear(display, XELPDP_PORT_M2P_MSGBUS_CTL(display, port, lane), XELPDP_PORT_P2P_TRANSACTION_PENDING, - XELPDP_MSGBUS_TIMEOUT_SLOW)) { + XELPDP_MSGBUS_TIMEOUT_MS)) { drm_dbg_kms(display->drm, "PHY %c Timeout waiting for previous transaction to complete. Resetting bus.\n", phy_name(phy)); @@ -1178,10 +1204,9 @@ intel_lt_phy_lane_reset(struct intel_encoder *encoder, if (intel_de_wait_custom(display, XELPDP_PORT_CLOCK_CTL(display, port), XELPDP_LANE_PCLK_PLL_ACK(0), XELPDP_LANE_PCLK_PLL_ACK(0), - XE3PLPD_MACCLK_TURNON_LATENCY_US, - XE3PLPD_MACCLK_TURNON_LATENCY_MS, NULL)) - drm_warn(display->drm, "PHY %c PLL MacCLK assertion Ack not done after %dus.\n", - phy_name(phy), XE3PLPD_MACCLK_TURNON_LATENCY_MS * 1000); + 2, XE3PLPD_MACCLK_TURNON_LATENCY_MS, NULL)) + drm_warn(display->drm, "PHY %c PLL MacCLK assertion ack not done\n", + phy_name(phy)); intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, port), XELPDP_FORWARD_CLOCK_UNGATE, @@ -1192,16 +1217,15 @@ intel_lt_phy_lane_reset(struct intel_encoder *encoder, if (intel_de_wait_custom(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_current_status, 0, - XE3PLPD_RESET_END_LATENCY_US, 2, NULL)) - drm_warn(display->drm, - "PHY %c failed to bring out of Lane reset after %dus.\n", - phy_name(phy), XE3PLPD_RESET_END_LATENCY_US); + 2, XE3PLPD_RESET_END_LATENCY_MS, NULL)) + drm_warn(display->drm, "PHY %c failed to bring out of lane reset\n", + phy_name(phy)); if (intel_de_wait_custom(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_pulse_status, lane_phy_pulse_status, - XE3PLPD_RATE_CALIB_DONE_LATENCY_US, 0, NULL)) - drm_warn(display->drm, "PHY %c PLL rate not changed after %dus.\n", - phy_name(phy), XE3PLPD_RATE_CALIB_DONE_LATENCY_US); + 2, XE3PLPD_RATE_CALIB_DONE_LATENCY_MS, NULL)) + drm_warn(display->drm, "PHY %c PLL rate not changed\n", + phy_name(phy)); intel_de_rmw(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_pulse_status, 0); } @@ -1356,10 +1380,308 @@ intel_lt_phy_pll_is_ssc_enabled(struct intel_crtc_state *crtc_state, return false; } +static u64 mul_q32_u32(u64 a_q32, u32 b) +{ + u64 p0, p1, carry, result; + u64 x_hi = a_q32 >> 32; + u64 x_lo = a_q32 & 0xFFFFFFFFULL; + + p0 = x_lo * (u64)b; + p1 = x_hi * (u64)b; + carry = p0 >> 32; + result = (p1 << 32) + (carry << 32) + (p0 & 0xFFFFFFFFULL); + + return result; +} + +static bool +calculate_target_dco_and_loop_cnt(u32 frequency_khz, u64 *target_dco_mhz, u32 *loop_cnt) +{ + u32 ppm_value = 1; + u32 dco_min_freq = DCO_MIN_FREQ_MHZ; + u32 dco_max_freq = 16200; + u32 dco_min_freq_low = 10000; + u32 dco_max_freq_low = 12000; + u64 val = 0; + u64 refclk_khz = REF_CLK_KHZ; + u64 m2div = 0; + u64 val_with_frac = 0; + u64 ppm = 0; + u64 temp0 = 0, temp1, scale; + int ppm_cnt, dco_count, y; + + for (ppm_cnt = 0; ppm_cnt < 5; ppm_cnt++) { + ppm_value = ppm_cnt == 2 ? 2 : 1; + for (dco_count = 0; dco_count < 2; dco_count++) { + if (dco_count == 1) { + dco_min_freq = dco_min_freq_low; + dco_max_freq = dco_max_freq_low; + } + for (y = 2; y <= 255; y += 2) { + val = div64_u64((u64)y * frequency_khz, 200); + m2div = div64_u64(((u64)(val) << 32), refclk_khz); + m2div = mul_q32_u32(m2div, 500); + val_with_frac = mul_q32_u32(m2div, refclk_khz); + val_with_frac = div64_u64(val_with_frac, 500); + temp1 = Q32_TO_INT(val_with_frac); + temp0 = (temp1 > val) ? (temp1 - val) : + (val - temp1); + ppm = div64_u64(temp0, val); + if (temp1 >= dco_min_freq && + temp1 <= dco_max_freq && + ppm < ppm_value) { + /* Round to two places */ + scale = (1ULL << 32) / 100; + temp0 = DIV_ROUND_UP_ULL(val_with_frac, + scale); + *target_dco_mhz = temp0 * scale; + *loop_cnt = y; + return true; + } + } + } + } + + return false; +} + +static void set_phy_vdr_addresses(struct lt_phy_params *p, int pll_type) +{ + p->pll_reg4.addr = PLL_REG_ADDR(PLL_REG4_ADDR, pll_type); + p->pll_reg3.addr = PLL_REG_ADDR(PLL_REG3_ADDR, pll_type); + p->pll_reg5.addr = PLL_REG_ADDR(PLL_REG5_ADDR, pll_type); + p->pll_reg57.addr = PLL_REG_ADDR(PLL_REG57_ADDR, pll_type); + p->lf.addr = PLL_REG_ADDR(PLL_LF_ADDR, pll_type); + p->tdc.addr = PLL_REG_ADDR(PLL_TDC_ADDR, pll_type); + p->ssc.addr = PLL_REG_ADDR(PLL_SSC_ADDR, pll_type); + p->bias2.addr = PLL_REG_ADDR(PLL_BIAS2_ADDR, pll_type); + p->bias_trim.addr = PLL_REG_ADDR(PLL_BIAS_TRIM_ADDR, pll_type); + p->dco_med.addr = PLL_REG_ADDR(PLL_DCO_MED_ADDR, pll_type); + p->dco_fine.addr = PLL_REG_ADDR(PLL_DCO_FINE_ADDR, pll_type); + p->ssc_inj.addr = PLL_REG_ADDR(PLL_SSC_INJ_ADDR, pll_type); + p->surv_bonus.addr = PLL_REG_ADDR(PLL_SURV_BONUS_ADDR, pll_type); +} + +static void compute_ssc(struct lt_phy_params *p, u32 ana_cfg) +{ + int ssc_stepsize = 0; + int ssc_steplen = 0; + int ssc_steplog = 0; + + p->ssc.val = (1 << 31) | (ana_cfg << 24) | (ssc_steplog << 16) | + (ssc_stepsize << 8) | ssc_steplen; +} + +static void compute_bias2(struct lt_phy_params *p) +{ + u32 ssc_en_local = 0; + u64 dynctrl_ovrd_en = 0; + + p->bias2.val = (dynctrl_ovrd_en << 31) | (ssc_en_local << 30) | + (1 << 23) | (1 << 24) | (32 << 16) | (1 << 8); +} + +static void compute_tdc(struct lt_phy_params *p, u64 tdc_fine) +{ + u32 settling_time = 15; + u32 bias_ovr_en = 1; + u32 coldstart = 1; + u32 true_lock = 2; + u32 early_lock = 1; + u32 lock_ovr_en = 1; + u32 lock_thr = tdc_fine ? 3 : 5; + u32 unlock_thr = tdc_fine ? 5 : 11; + + p->tdc.val = (u32)((2 << 30) + (settling_time << 16) + (bias_ovr_en << 15) + + (lock_ovr_en << 14) + (coldstart << 12) + (true_lock << 10) + + (early_lock << 8) + (unlock_thr << 4) + lock_thr); +} + +static void compute_dco_med(struct lt_phy_params *p) +{ + u32 cselmed_en = 0; + u32 cselmed_dyn_adj = 0; + u32 cselmed_ratio = 39; + u32 cselmed_thr = 8; + + p->dco_med.val = (cselmed_en << 31) + (cselmed_dyn_adj << 30) + + (cselmed_ratio << 24) + (cselmed_thr << 21); +} + +static void compute_dco_fine(struct lt_phy_params *p, u32 dco_12g) +{ + u32 dco_fine0_tune_2_0 = 0; + u32 dco_fine1_tune_2_0 = 0; + u32 dco_fine2_tune_2_0 = 0; + u32 dco_fine3_tune_2_0 = 0; + u32 dco_dith0_tune_2_0 = 0; + u32 dco_dith1_tune_2_0 = 0; + + dco_fine0_tune_2_0 = dco_12g ? 4 : 3; + dco_fine1_tune_2_0 = 2; + dco_fine2_tune_2_0 = dco_12g ? 2 : 1; + dco_fine3_tune_2_0 = 5; + dco_dith0_tune_2_0 = dco_12g ? 4 : 3; + dco_dith1_tune_2_0 = 2; + + p->dco_fine.val = (dco_dith1_tune_2_0 << 19) + + (dco_dith0_tune_2_0 << 16) + + (dco_fine3_tune_2_0 << 11) + + (dco_fine2_tune_2_0 << 8) + + (dco_fine1_tune_2_0 << 3) + + dco_fine0_tune_2_0; +} + +int +intel_lt_phy_calculate_hdmi_state(struct intel_lt_phy_pll_state *lt_state, + u32 frequency_khz) +{ +#define DATA_ASSIGN(i, pll_reg) \ + do { \ + lt_state->data[i][0] = (u8)((((pll_reg).val) & 0xFF000000) >> 24); \ + lt_state->data[i][1] = (u8)((((pll_reg).val) & 0x00FF0000) >> 16); \ + lt_state->data[i][2] = (u8)((((pll_reg).val) & 0x0000FF00) >> 8); \ + lt_state->data[i][3] = (u8)((((pll_reg).val) & 0x000000FF)); \ + } while (0) +#define ADDR_ASSIGN(i, pll_reg) \ + do { \ + lt_state->addr_msb[i] = ((pll_reg).addr >> 8) & 0xFF; \ + lt_state->addr_lsb[i] = (pll_reg).addr & 0xFF; \ + } while (0) + + bool found = false; + struct lt_phy_params p; + u32 dco_fmin = DCO_MIN_FREQ_MHZ; + u64 refclk_khz = REF_CLK_KHZ; + u32 refclk_mhz_int = REF_CLK_KHZ / 1000; + u64 m2div = 0; + u64 target_dco_mhz = 0; + u64 tdc_fine, tdc_targetcnt; + u64 feedfwd_gain ,feedfwd_cal_en; + u64 tdc_res = 30; + u32 prop_coeff; + u32 int_coeff; + u32 ndiv = 1; + u32 m1div = 1, m2div_int, m2div_frac; + u32 frac_en; + u32 ana_cfg; + u32 loop_cnt = 0; + u32 gain_ctrl = 2; + u32 postdiv = 0; + u32 dco_12g = 0; + u32 pll_type = 0; + u32 d1 = 2, d3 = 5, d4 = 0, d5 = 0; + u32 d6 = 0, d6_new = 0; + u32 d7, d8 = 0; + u32 bonus_7_0 = 0; + u32 csel2fo = 11; + u32 csel2fo_ovrd_en = 1; + u64 temp0, temp1, temp2, temp3; + + p.surv_bonus.val = (bonus_7_0 << 16); + p.pll_reg4.val = (refclk_mhz_int << 17) + + (ndiv << 9) + (1 << 4); + p.bias_trim.val = (csel2fo_ovrd_en << 30) + (csel2fo << 24); + p.ssc_inj.val = 0; + found = calculate_target_dco_and_loop_cnt(frequency_khz, &target_dco_mhz, &loop_cnt); + if (!found) + return -EINVAL; + + m2div = div64_u64(target_dco_mhz, (refclk_khz * ndiv * m1div)); + m2div = mul_q32_u32(m2div, 1000); + if (Q32_TO_INT(m2div) > 511) + return -EINVAL; + + m2div_int = (u32)Q32_TO_INT(m2div); + m2div_frac = (u32)(Q32_TO_FRAC(m2div)); + frac_en = (m2div_frac > 0) ? 1 : 0; + + if (frac_en > 0) + tdc_res = 70; + else + tdc_res = 36; + tdc_fine = tdc_res > 50 ? 1 : 0; + temp0 = tdc_res * 40 * 11; + temp1 = div64_u64(((4 * TDC_RES_MULTIPLIER) + temp0) * 500, temp0 * refclk_khz); + temp2 = div64_u64(temp0 * refclk_khz, 1000); + temp3 = div64_u64(((8 * TDC_RES_MULTIPLIER) + temp2), temp2); + tdc_targetcnt = tdc_res < 50 ? (int)(temp1) : (int)(temp3); + tdc_targetcnt = (int)(tdc_targetcnt / 2); + temp0 = mul_q32_u32(target_dco_mhz, tdc_res); + temp0 >>= 32; + feedfwd_gain = (m2div_frac > 0) ? div64_u64(m1div * TDC_RES_MULTIPLIER, temp0) : 0; + feedfwd_cal_en = frac_en; + + temp0 = (u32)Q32_TO_INT(target_dco_mhz); + prop_coeff = (temp0 >= dco_fmin) ? 3 : 4; + int_coeff = (temp0 >= dco_fmin) ? 7 : 8; + ana_cfg = (temp0 >= dco_fmin) ? 8 : 6; + dco_12g = (temp0 >= dco_fmin) ? 0 : 1; + + if (temp0 > 12960) + d7 = 10; + else + d7 = 8; + + d8 = loop_cnt / 2; + d4 = d8 * 2; + + /* Compute pll_reg3,5,57 & lf */ + p.pll_reg3.val = (u32)((d4 << 21) + (d3 << 18) + (d1 << 15) + (m2div_int << 5)); + p.pll_reg5.val = m2div_frac; + postdiv = (d5 == 0) ? 9 : d5; + d6_new = (d6 == 0) ? 40 : d6; + p.pll_reg57.val = (d7 << 24) + (postdiv << 15) + (d8 << 7) + d6_new; + p.lf.val = (u32)((frac_en << 31) + (1 << 30) + (frac_en << 29) + + (feedfwd_cal_en << 28) + (tdc_fine << 27) + + (gain_ctrl << 24) + (feedfwd_gain << 16) + + (int_coeff << 12) + (prop_coeff << 8) + tdc_targetcnt); + + compute_ssc(&p, ana_cfg); + compute_bias2(&p); + compute_tdc(&p, tdc_fine); + compute_dco_med(&p); + compute_dco_fine(&p, dco_12g); + + pll_type = ((frequency_khz == 10000) || (frequency_khz == 20000) || + (frequency_khz == 2500) || (dco_12g == 1)) ? 0 : 1; + set_phy_vdr_addresses(&p, pll_type); + + lt_state->config[0] = 0x84; + lt_state->config[1] = 0x2d; + ADDR_ASSIGN(0, p.pll_reg4); + ADDR_ASSIGN(1, p.pll_reg3); + ADDR_ASSIGN(2, p.pll_reg5); + ADDR_ASSIGN(3, p.pll_reg57); + ADDR_ASSIGN(4, p.lf); + ADDR_ASSIGN(5, p.tdc); + ADDR_ASSIGN(6, p.ssc); + ADDR_ASSIGN(7, p.bias2); + ADDR_ASSIGN(8, p.bias_trim); + ADDR_ASSIGN(9, p.dco_med); + ADDR_ASSIGN(10, p.dco_fine); + ADDR_ASSIGN(11, p.ssc_inj); + ADDR_ASSIGN(12, p.surv_bonus); + DATA_ASSIGN(0, p.pll_reg4); + DATA_ASSIGN(1, p.pll_reg3); + DATA_ASSIGN(2, p.pll_reg5); + DATA_ASSIGN(3, p.pll_reg57); + DATA_ASSIGN(4, p.lf); + DATA_ASSIGN(5, p.tdc); + DATA_ASSIGN(6, p.ssc); + DATA_ASSIGN(7, p.bias2); + DATA_ASSIGN(8, p.bias_trim); + DATA_ASSIGN(9, p.dco_med); + DATA_ASSIGN(10, p.dco_fine); + DATA_ASSIGN(11, p.ssc_inj); + DATA_ASSIGN(12, p.surv_bonus); + + return 0; +} + static int -intel_lt_phy_calc_hdmi_port_clock(const struct intel_lt_phy_pll_state *lt_state) +intel_lt_phy_calc_hdmi_port_clock(const struct intel_crtc_state *crtc_state) { -#define REF_CLK_KHZ 38400 #define REGVAL(i) ( \ (lt_state->data[i][3]) | \ (lt_state->data[i][2] << 8) | \ @@ -1367,6 +1689,9 @@ intel_lt_phy_calc_hdmi_port_clock(const struct intel_lt_phy_pll_state *lt_state) (lt_state->data[i][0] << 24) \ ) + struct intel_display *display = to_intel_display(crtc_state); + const struct intel_lt_phy_pll_state *lt_state = + &crtc_state->dpll_hw_state.ltpll; int clk = 0; u32 d8, pll_reg_5, pll_reg_3, pll_reg_57, m2div_frac, m2div_int; u64 temp0, temp1; @@ -1409,11 +1734,14 @@ intel_lt_phy_calc_hdmi_port_clock(const struct intel_lt_phy_pll_state *lt_state) * frequency = (m2div * refclk_khz / (d8 * 10)) */ d8 = (pll_reg_57 & REG_GENMASK(14, 7)) >> 7; + if (d8 == 0) { + drm_WARN_ON(display->drm, + "Invalid port clock using lowest HDMI portclock\n"); + return xe3plpd_lt_hdmi_252.clock; + } m2div_int = (pll_reg_3 & REG_GENMASK(14, 5)) >> 5; temp0 = ((u64)m2div_frac * REF_CLK_KHZ) >> 32; temp1 = (u64)m2div_int * REF_CLK_KHZ; - if (d8 == 0) - return 0; clk = div_u64((temp1 + temp0), d8 * 10); @@ -1442,7 +1770,7 @@ intel_lt_phy_calc_port_clock(struct intel_encoder *encoder, lt_state->config[0]); clk = intel_lt_phy_get_dp_clock(rate); } else { - clk = intel_lt_phy_calc_hdmi_port_clock(lt_state); + clk = intel_lt_phy_calc_hdmi_port_clock(crtc_state); } return clk; @@ -1472,7 +1800,10 @@ intel_lt_phy_pll_calc_state(struct intel_crtc_state *crtc_state, } } - /* TODO: Add a function to compute the data for HDMI TMDS*/ + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) { + return intel_lt_phy_calculate_hdmi_state(&crtc_state->dpll_hw_state.ltpll, + crtc_state->port_clock); + } return -EINVAL; } @@ -1654,8 +1985,8 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, if (intel_de_wait_custom(display, XELPDP_PORT_CLOCK_CTL(display, port), XELPDP_LANE_PCLK_PLL_ACK(0), 0, XE3PLPD_MACCLK_TURNOFF_LATENCY_US, 0, NULL)) - drm_warn(display->drm, "PHY %c PLL MacCLK Ack deassertion Timeout after %dus.\n", - phy_name(phy), XE3PLPD_MACCLK_TURNOFF_LATENCY_US); + drm_warn(display->drm, "PHY %c PLL MacCLK ack deassertion timeout\n", + phy_name(phy)); /* * 9. Follow the Display Voltage Frequency Switching - Sequence Before Frequency @@ -1674,9 +2005,9 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, if (intel_de_wait_custom(display, XELPDP_PORT_CLOCK_CTL(display, port), XELPDP_LANE_PCLK_PLL_ACK(0), XELPDP_LANE_PCLK_PLL_ACK(0), - XE3PLPD_MACCLK_TURNON_LATENCY_US, 2, NULL)) - drm_warn(display->drm, "PHY %c PLL MacCLK Ack assertion Timeout after %dus.\n", - phy_name(phy), XE3PLPD_MACCLK_TURNON_LATENCY_US); + 2, XE3PLPD_MACCLK_TURNON_LATENCY_MS, NULL)) + drm_warn(display->drm, "PHY %c PLL MacCLK ack assertion timeout\n", + phy_name(phy)); /* * 13. Ungate the forward clock by setting @@ -1702,9 +2033,9 @@ void intel_lt_phy_pll_enable(struct intel_encoder *encoder, /* 16. Poll for PORT_BUF_CTL2 register PHY Pulse Status = 1 for Owned PHY Lanes. */ if (intel_de_wait_custom(display, XELPDP_PORT_BUF_CTL2(display, port), lane_phy_pulse_status, lane_phy_pulse_status, - XE3PLPD_RATE_CALIB_DONE_LATENCY_US, 2, NULL)) - drm_warn(display->drm, "PHY %c PLL rate not changed after %dus.\n", - phy_name(phy), XE3PLPD_RATE_CALIB_DONE_LATENCY_US); + 2, XE3PLPD_RATE_CALIB_DONE_LATENCY_MS, NULL)) + drm_warn(display->drm, "PHY %c PLL rate not changed\n", + phy_name(phy)); /* 17. SW clears PORT_BUF_CTL2 [PHY Pulse Status]. */ intel_de_rmw(display, XELPDP_PORT_BUF_CTL2(display, port), @@ -1762,9 +2093,8 @@ void intel_lt_phy_pll_disable(struct intel_encoder *encoder) lane_phy_current_status, lane_phy_current_status, XE3PLPD_RESET_START_LATENCY_US, 0, NULL)) - drm_warn(display->drm, - "PHY %c failed to reset Lane after %dms.\n", - phy_name(phy), XE3PLPD_RESET_START_LATENCY_US); + drm_warn(display->drm, "PHY %c failed to reset lane\n", + phy_name(phy)); /* 4. Clear for PHY pulse status on owned PHY lanes. */ intel_de_rmw(display, XELPDP_PORT_BUF_CTL2(display, port), @@ -1786,8 +2116,8 @@ void intel_lt_phy_pll_disable(struct intel_encoder *encoder) if (intel_de_wait_custom(display, XELPDP_PORT_CLOCK_CTL(display, port), XELPDP_LANE_PCLK_PLL_ACK(0), 0, XE3PLPD_MACCLK_TURNOFF_LATENCY_US, 0, NULL)) - drm_warn(display->drm, "PHY %c PLL MacCLK Ack deassertion Timeout after %dus.\n", - phy_name(phy), XE3PLPD_MACCLK_TURNOFF_LATENCY_US); + drm_warn(display->drm, "PHY %c PLL MacCLK ack deassertion timeout\n", + phy_name(phy)); /* * 9. Follow the Display Voltage Frequency Switching - diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.h b/drivers/gpu/drm/i915/display/intel_lt_phy.h index a538d4c69210..b7911acd7dcd 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.h @@ -35,6 +35,9 @@ void intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, struct intel_lt_phy_pll_state *pll_state); void intel_lt_phy_pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc); +int +intel_lt_phy_calculate_hdmi_state(struct intel_lt_phy_pll_state *lt_state, + u32 frequency_khz); void intel_xe3plpd_pll_enable(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_xe3plpd_pll_disable(struct intel_encoder *encoder); diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h b/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h index 9223487d764e..98ccc069a69b 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h +++ b/drivers/gpu/drm/i915/display/intel_lt_phy_regs.h @@ -7,13 +7,12 @@ #define __INTEL_LT_PHY_REGS_H__ #define XE3PLPD_MSGBUS_TIMEOUT_FAST_US 500 -#define XE3PLPD_MACCLK_TURNON_LATENCY_MS 1 -#define XE3PLPD_MACCLK_TURNON_LATENCY_US 21 +#define XE3PLPD_MACCLK_TURNON_LATENCY_MS 2 #define XE3PLPD_MACCLK_TURNOFF_LATENCY_US 1 -#define XE3PLPD_RATE_CALIB_DONE_LATENCY_US 50 +#define XE3PLPD_RATE_CALIB_DONE_LATENCY_MS 1 #define XE3PLPD_RESET_START_LATENCY_US 10 #define XE3PLPD_PWRDN_TO_RDY_LATENCY_US 4 -#define XE3PLPD_RESET_END_LATENCY_US 200 +#define XE3PLPD_RESET_END_LATENCY_MS 2 /* LT Phy MAC Register */ #define LT_PHY_MAC_VDR _MMIO(0xC00) @@ -72,4 +71,20 @@ #define XE3PLPD_PORT_P2M_MSGBUS_STATUS_P2P(port, lane) _XE3PLPD_PORT_P2M_MSGBUS_STATUS_P2P(__xe2lpd_port_idx(port), \ lane) #define XE3LPD_PORT_P2M_ADDR_MASK REG_GENMASK(11, 0) + +#define PLL_REG4_ADDR 0x8510 +#define PLL_REG3_ADDR 0x850C +#define PLL_REG5_ADDR 0x8514 +#define PLL_REG57_ADDR 0x85E4 +#define PLL_LF_ADDR 0x860C +#define PLL_TDC_ADDR 0x8610 +#define PLL_SSC_ADDR 0x8614 +#define PLL_BIAS2_ADDR 0x8618 +#define PLL_BIAS_TRIM_ADDR 0x8648 +#define PLL_DCO_MED_ADDR 0x8640 +#define PLL_DCO_FINE_ADDR 0x864C +#define PLL_SSC_INJ_ADDR 0x8624 +#define PLL_SURV_BONUS_ADDR 0x8644 +#define PLL_TYPE_OFFSET 0x200 +#define PLL_REG_ADDR(base, pll_type) ((pll_type) ? (base) + PLL_TYPE_OFFSET : (base)) #endif /* __INTEL_LT_PHY_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 231b1632d64a..88eb7ae5765c 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -308,8 +308,6 @@ static void intel_overlay_flip_prepare(struct intel_overlay *overlay, intel_frontbuffer_put(overlay->frontbuffer); overlay->frontbuffer = frontbuffer; - intel_frontbuffer_flip_prepare(display, INTEL_FRONTBUFFER_OVERLAY(pipe)); - overlay->old_vma = overlay->vma; if (vma) overlay->vma = i915_vma_get(vma); @@ -366,7 +364,7 @@ static void intel_overlay_release_old_vma(struct intel_overlay *overlay) if (drm_WARN_ON(display->drm, !vma)) return; - intel_frontbuffer_flip_complete(display, INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); + intel_frontbuffer_flip(display, INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe)); i915_vma_unpin(vma); i915_vma_put(vma); @@ -822,8 +820,6 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_pin_section; } - i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB); - if (!overlay->active) { const struct intel_crtc_state *crtc_state = overlay->crtc->config; diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 505c776c0585..5105e3278bc4 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -1051,6 +1051,9 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) DISPLAY_VERx100(display) == 3002) && src_x % 2 != 0) hsub = 2; + + if (DISPLAY_VER(display) == 35) + vsub = 2; } else { hsub = fb->format->hsub; vsub = fb->format->vsub; diff --git a/drivers/gpu/drm/i915/display/intel_pmdemand.c b/drivers/gpu/drm/i915/display/intel_pmdemand.c index f52abd4e2eb0..22d8f720ae7d 100644 --- a/drivers/gpu/drm/i915/display/intel_pmdemand.c +++ b/drivers/gpu/drm/i915/display/intel_pmdemand.c @@ -464,7 +464,7 @@ static void intel_pmdemand_poll(struct intel_display *display) ret = intel_de_wait_custom(display, XELPDP_INITIATE_PMDEMAND_REQUEST(1), XELPDP_PMDEMAND_REQ_ENABLE, 0, - 50, timeout_ms, &status); + 2, timeout_ms, &status); if (ret == -ETIMEDOUT) drm_err(display->drm, diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 05014ffe3ce1..00b06771ae2d 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -626,6 +626,10 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) struct intel_display *display = to_intel_display(intel_dp); int ret; + /* TODO: Enable Panel Replay on MST once it's properly implemented. */ + if (intel_dp->mst_detect == DRM_DP_MST) + return; + ret = drm_dp_dpcd_read_data(&intel_dp->aux, DP_PANEL_REPLAY_CAP_SUPPORT, &intel_dp->pr_dpcd, sizeof(intel_dp->pr_dpcd)); if (ret < 0) @@ -932,7 +936,8 @@ static bool is_dc5_dc6_blocked(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); u32 current_dc_state = intel_display_power_get_current_dc_state(display); - struct drm_vblank_crtc *vblank = &display->drm->vblank[intel_dp->psr.pipe]; + struct intel_crtc *crtc = intel_crtc_for_pipe(display, intel_dp->psr.pipe); + struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(&crtc->base); return (current_dc_state != DC_STATE_EN_UPTO_DC5 && current_dc_state != DC_STATE_EN_UPTO_DC6) || diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index ba1bf0bd4c55..bc55fafe9ce3 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -1748,7 +1748,8 @@ static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, } if (rotation & DRM_MODE_REFLECT_X && - fb->modifier == DRM_FORMAT_MOD_LINEAR) { + fb->modifier == DRM_FORMAT_MOD_LINEAR && + DISPLAY_VER(display) < 35) { drm_dbg_kms(display->drm, "[PLANE:%d:%s] horizontal flip is not supported with linear surface formats\n", plane->base.base.id, plane->base.name); diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h index 7c944d3ca855..6f815b231340 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h +++ b/drivers/gpu/drm/i915/display/skl_universal_plane_regs.h @@ -324,7 +324,7 @@ #define PLANE_WM_IGNORE_LINES REG_BIT(30) #define PLANE_WM_AUTO_MIN_ALLOC_EN REG_BIT(29) #define PLANE_WM_LINES_MASK REG_GENMASK(26, 14) -#define PLANE_WM_BLOCKS_MASK REG_GENMASK(11, 0) +#define PLANE_WM_BLOCKS_MASK REG_GENMASK(12, 0) #define _PLANE_WM_SAGV_1_A 0x70258 #define _PLANE_WM_SAGV_1_B 0x71258 @@ -375,10 +375,10 @@ _PLANE_BUF_CFG_1_A, _PLANE_BUF_CFG_1_B, \ _PLANE_BUF_CFG_2_A, _PLANE_BUF_CFG_2_B) -/* skl+: 10 bits, icl+ 11 bits, adlp+ 12 bits */ -#define PLANE_BUF_END_MASK REG_GENMASK(27, 16) +/* skl+: 10 bits, icl+ 11 bits, adlp+ 12 bits, xe3p_lpd 13 bits */ +#define PLANE_BUF_END_MASK REG_GENMASK(28, 16) #define PLANE_BUF_END(end) REG_FIELD_PREP(PLANE_BUF_END_MASK, (end)) -#define PLANE_BUF_START_MASK REG_GENMASK(11, 0) +#define PLANE_BUF_START_MASK REG_GENMASK(12, 0) #define PLANE_BUF_START(start) REG_FIELD_PREP(PLANE_BUF_START_MASK, (start)) #define _PLANE_MIN_BUF_CFG_1_A 0x70274 @@ -389,9 +389,9 @@ _PLANE_MIN_BUF_CFG_1_A, _PLANE_MIN_BUF_CFG_1_B, \ _PLANE_MIN_BUF_CFG_2_A, _PLANE_MIN_BUF_CFG_2_B) #define PLANE_AUTO_MIN_DBUF_EN REG_BIT(31) -#define PLANE_MIN_DBUF_BLOCKS_MASK REG_GENMASK(27, 16) +#define PLANE_MIN_DBUF_BLOCKS_MASK REG_GENMASK(28, 16) #define PLANE_MIN_DBUF_BLOCKS(val) REG_FIELD_PREP(PLANE_MIN_DBUF_BLOCKS_MASK, (val)) -#define PLANE_INTERIM_DBUF_BLOCKS_MASK REG_GENMASK(11, 0) +#define PLANE_INTERIM_DBUF_BLOCKS_MASK REG_GENMASK(12, 0) #define PLANE_INTERIM_DBUF_BLOCKS(val) REG_FIELD_PREP(PLANE_INTERIM_DBUF_BLOCKS_MASK, (val)) /* tgl+ */ diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 6d050408618c..36a266f882d1 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -1812,6 +1812,8 @@ static void skl_compute_plane_wm(const struct intel_crtc_state *crtc_state, if (wp->y_tiled) { selected_result = max_fixed16(method2, wp->y_tile_minimum); + } else if (DISPLAY_VER(display) >= 35) { + selected_result = method2; } else { if ((wp->cpp * crtc_state->hw.pipe_mode.crtc_htotal / wp->dbuf_block_size < 1) && @@ -3183,6 +3185,13 @@ static void sanitize_wm_latency(struct intel_display *display) int level, num_levels = display->wm.num_levels; /* + * Xe3p and beyond should ignore level 0's reported latency and + * always apply WaWmMemoryReadLatency logic. + */ + if (DISPLAY_VER(display) >= 35) + wm[0] = 0; + + /* * If a level n (n > 1) has a 0us latency, all levels m (m >= n) * need to be disabled. We make sure to sanitize the values out * of the punit to satisfy this requirement. @@ -3477,7 +3486,10 @@ void intel_dbuf_mdclk_cdclk_ratio_update(struct intel_display *display, if (!HAS_MBUS_JOINING(display)) return; - if (DISPLAY_VER(display) >= 20) + if (DISPLAY_VER(display) >= 35) + intel_de_rmw(display, MBUS_CTL, XE3P_MBUS_TRANSLATION_THROTTLE_MIN_MASK, + XE3P_MBUS_TRANSLATION_THROTTLE_MIN(ratio - 1)); + else if (DISPLAY_VER(display) >= 20) intel_de_rmw(display, MBUS_CTL, MBUS_TRANSLATION_THROTTLE_MIN_MASK, MBUS_TRANSLATION_THROTTLE_MIN(ratio - 1)); @@ -3488,9 +3500,14 @@ void intel_dbuf_mdclk_cdclk_ratio_update(struct intel_display *display, ratio, str_yes_no(joined_mbus)); for_each_dbuf_slice(display, slice) - intel_de_rmw(display, DBUF_CTL_S(slice), - DBUF_MIN_TRACKER_STATE_SERVICE_MASK, - DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); + if (DISPLAY_VER(display) >= 35) + intel_de_rmw(display, DBUF_CTL_S(slice), + XE3P_DBUF_MIN_TRACKER_STATE_SERVICE_MASK, + XE3P_DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); + else + intel_de_rmw(display, DBUF_CTL_S(slice), + DBUF_MIN_TRACKER_STATE_SERVICE_MASK, + DBUF_MIN_TRACKER_STATE_SERVICE(ratio - 1)); } static void intel_dbuf_mdclk_min_tracker_update(struct intel_atomic_state *state) diff --git a/drivers/gpu/drm/i915/display/skl_watermark_regs.h b/drivers/gpu/drm/i915/display/skl_watermark_regs.h index c5572fc0e847..abf56ac31105 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark_regs.h +++ b/drivers/gpu/drm/i915/display/skl_watermark_regs.h @@ -32,16 +32,18 @@ #define MBUS_BBOX_CTL_S1 _MMIO(0x45040) #define MBUS_BBOX_CTL_S2 _MMIO(0x45044) -#define MBUS_CTL _MMIO(0x4438C) -#define MBUS_JOIN REG_BIT(31) -#define MBUS_HASHING_MODE_MASK REG_BIT(30) -#define MBUS_HASHING_MODE_2x2 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 0) -#define MBUS_HASHING_MODE_1x4 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 1) -#define MBUS_JOIN_PIPE_SELECT_MASK REG_GENMASK(28, 26) -#define MBUS_JOIN_PIPE_SELECT(pipe) REG_FIELD_PREP(MBUS_JOIN_PIPE_SELECT_MASK, pipe) -#define MBUS_JOIN_PIPE_SELECT_NONE MBUS_JOIN_PIPE_SELECT(7) -#define MBUS_TRANSLATION_THROTTLE_MIN_MASK REG_GENMASK(15, 13) -#define MBUS_TRANSLATION_THROTTLE_MIN(val) REG_FIELD_PREP(MBUS_TRANSLATION_THROTTLE_MIN_MASK, val) +#define MBUS_CTL _MMIO(0x4438C) +#define MBUS_JOIN REG_BIT(31) +#define MBUS_HASHING_MODE_MASK REG_BIT(30) +#define MBUS_HASHING_MODE_2x2 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 0) +#define MBUS_HASHING_MODE_1x4 REG_FIELD_PREP(MBUS_HASHING_MODE_MASK, 1) +#define MBUS_JOIN_PIPE_SELECT_MASK REG_GENMASK(28, 26) +#define MBUS_JOIN_PIPE_SELECT(pipe) REG_FIELD_PREP(MBUS_JOIN_PIPE_SELECT_MASK, pipe) +#define MBUS_JOIN_PIPE_SELECT_NONE MBUS_JOIN_PIPE_SELECT(7) +#define XE3P_MBUS_TRANSLATION_THROTTLE_MIN_MASK REG_GENMASK(16, 13) +#define XE3P_MBUS_TRANSLATION_THROTTLE_MIN(val) REG_FIELD_PREP(XE3P_MBUS_TRANSLATION_THROTTLE_MIN_MASK, val) +#define MBUS_TRANSLATION_THROTTLE_MIN_MASK REG_GENMASK(15, 13) +#define MBUS_TRANSLATION_THROTTLE_MIN(val) REG_FIELD_PREP(MBUS_TRANSLATION_THROTTLE_MIN_MASK, val) /* * The below are numbered starting from "S1" on gen11/gen12, but starting @@ -51,20 +53,22 @@ * way things will be named by the hardware team going forward, plus it's more * consistent with how most of the rest of our registers are named. */ -#define _DBUF_CTL_S0 0x45008 -#define _DBUF_CTL_S1 0x44FE8 -#define _DBUF_CTL_S2 0x44300 -#define _DBUF_CTL_S3 0x44304 -#define DBUF_CTL_S(slice) _MMIO(_PICK(slice, \ - _DBUF_CTL_S0, \ - _DBUF_CTL_S1, \ - _DBUF_CTL_S2, \ - _DBUF_CTL_S3)) -#define DBUF_POWER_REQUEST REG_BIT(31) -#define DBUF_POWER_STATE REG_BIT(30) -#define DBUF_TRACKER_STATE_SERVICE_MASK REG_GENMASK(23, 19) -#define DBUF_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(DBUF_TRACKER_STATE_SERVICE_MASK, x) -#define DBUF_MIN_TRACKER_STATE_SERVICE_MASK REG_GENMASK(18, 16) /* ADL-P+ */ +#define _DBUF_CTL_S0 0x45008 +#define _DBUF_CTL_S1 0x44FE8 +#define _DBUF_CTL_S2 0x44300 +#define _DBUF_CTL_S3 0x44304 +#define DBUF_CTL_S(slice) _MMIO(_PICK(slice, \ + _DBUF_CTL_S0, \ + _DBUF_CTL_S1, \ + _DBUF_CTL_S2, \ + _DBUF_CTL_S3)) +#define DBUF_POWER_REQUEST REG_BIT(31) +#define DBUF_POWER_STATE REG_BIT(30) +#define DBUF_TRACKER_STATE_SERVICE_MASK REG_GENMASK(23, 19) +#define DBUF_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(DBUF_TRACKER_STATE_SERVICE_MASK, x) +#define XE3P_DBUF_MIN_TRACKER_STATE_SERVICE_MASK REG_GENMASK(20, 16) +#define XE3P_DBUF_MIN_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(XE3P_DBUF_MIN_TRACKER_STATE_SERVICE_MASK, x) +#define DBUF_MIN_TRACKER_STATE_SERVICE_MASK REG_GENMASK(18, 16) /* ADL-P+ */ #define DBUF_MIN_TRACKER_STATE_SERVICE(x) REG_FIELD_PREP(DBUF_MIN_TRACKER_STATE_SERVICE_MASK, x) /* ADL-P+ */ #define MTL_LATENCY_LP0_LP1 _MMIO(0x45780) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index e1348a0043db..3f6f040c359d 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -477,24 +477,24 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj) void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, enum fb_op_origin origin) { - struct intel_frontbuffer *front; + struct i915_frontbuffer *front; - front = i915_gem_object_get_frontbuffer(obj); + front = i915_gem_object_frontbuffer_lookup(obj); if (front) { - intel_frontbuffer_flush(front, origin); - intel_frontbuffer_put(front); + intel_frontbuffer_flush(&front->base, origin); + i915_gem_object_frontbuffer_put(front); } } void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, enum fb_op_origin origin) { - struct intel_frontbuffer *front; + struct i915_frontbuffer *front; - front = i915_gem_object_get_frontbuffer(obj); + front = i915_gem_object_frontbuffer_lookup(obj); if (front) { - intel_frontbuffer_invalidate(front, origin); - intel_frontbuffer_put(front); + intel_frontbuffer_invalidate(&front->base, origin); + i915_gem_object_frontbuffer_put(front); } } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.c new file mode 100644 index 000000000000..aaa15e7b3f17 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2025 Intel Corporation */ + +#include "i915_drv.h" +#include "i915_gem_object_frontbuffer.h" + +static int frontbuffer_active(struct i915_active *ref) +{ + struct i915_frontbuffer *front = + container_of(ref, typeof(*front), write); + + kref_get(&front->ref); + return 0; +} + +static void frontbuffer_retire(struct i915_active *ref) +{ + struct i915_frontbuffer *front = + container_of(ref, typeof(*front), write); + + intel_frontbuffer_flush(&front->base, ORIGIN_CS); + i915_gem_object_frontbuffer_put(front); +} + +struct i915_frontbuffer * +i915_gem_object_frontbuffer_get(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct i915_frontbuffer *front, *cur; + + front = i915_gem_object_frontbuffer_lookup(obj); + if (front) + return front; + + front = kmalloc(sizeof(*front), GFP_KERNEL); + if (!front) + return NULL; + + intel_frontbuffer_init(&front->base, &i915->drm); + + kref_init(&front->ref); + i915_gem_object_get(obj); + front->obj = obj; + + i915_active_init(&front->write, + frontbuffer_active, + frontbuffer_retire, + I915_ACTIVE_RETIRE_SLEEPS); + + spin_lock(&i915->frontbuffer_lock); + if (rcu_access_pointer(obj->frontbuffer)) { + cur = rcu_dereference_protected(obj->frontbuffer, true); + kref_get(&cur->ref); + } else { + cur = front; + rcu_assign_pointer(obj->frontbuffer, front); + } + spin_unlock(&i915->frontbuffer_lock); + + if (cur != front) { + i915_gem_object_put(obj); + intel_frontbuffer_fini(&front->base); + kfree(front); + } + + return cur; +} + +void i915_gem_object_frontbuffer_ref(struct i915_frontbuffer *front) +{ + kref_get(&front->ref); +} + +static void frontbuffer_release(struct kref *ref) + __releases(&i915->frontbuffer_lock) +{ + struct i915_frontbuffer *front = + container_of(ref, typeof(*front), ref); + struct drm_i915_gem_object *obj = front->obj; + struct drm_i915_private *i915 = to_i915(obj->base.dev); + + i915_ggtt_clear_scanout(obj); + + RCU_INIT_POINTER(obj->frontbuffer, NULL); + + spin_unlock(&i915->frontbuffer_lock); + + i915_active_fini(&front->write); + + i915_gem_object_put(obj); + + intel_frontbuffer_fini(&front->base); + + kfree_rcu(front, rcu); +} + +void i915_gem_object_frontbuffer_put(struct i915_frontbuffer *front) +{ + struct drm_i915_private *i915 = to_i915(front->obj->base.dev); + + kref_put_lock(&front->ref, frontbuffer_release, + &i915->frontbuffer_lock); +} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h index b682969e3a29..2133e29047c5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h @@ -12,6 +12,14 @@ #include "display/intel_frontbuffer.h" #include "i915_gem_object_types.h" +struct i915_frontbuffer { + struct intel_frontbuffer base; + struct drm_i915_gem_object *obj; + struct i915_active write; + struct rcu_head rcu; + struct kref ref; +}; + void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj, enum fb_op_origin origin); void __i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, @@ -33,19 +41,23 @@ i915_gem_object_invalidate_frontbuffer(struct drm_i915_gem_object *obj, __i915_gem_object_invalidate_frontbuffer(obj, origin); } +struct i915_frontbuffer *i915_gem_object_frontbuffer_get(struct drm_i915_gem_object *obj); +void i915_gem_object_frontbuffer_ref(struct i915_frontbuffer *front); +void i915_gem_object_frontbuffer_put(struct i915_frontbuffer *front); + /** - * i915_gem_object_get_frontbuffer - Get the object's frontbuffer - * @obj: The object whose frontbuffer to get. + * i915_gem_object_frontbuffer_lookup - Look up the object's frontbuffer + * @obj: The object whose frontbuffer to look up. * * Get pointer to object's frontbuffer if such exists. Please note that RCU * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. * * Return: pointer to object's frontbuffer is such exists or NULL */ -static inline struct intel_frontbuffer * -i915_gem_object_get_frontbuffer(const struct drm_i915_gem_object *obj) +static inline struct i915_frontbuffer * +i915_gem_object_frontbuffer_lookup(const struct drm_i915_gem_object *obj) { - struct intel_frontbuffer *front; + struct i915_frontbuffer *front; if (likely(!rcu_access_pointer(obj->frontbuffer))) return NULL; @@ -62,41 +74,11 @@ i915_gem_object_get_frontbuffer(const struct drm_i915_gem_object *obj) if (likely(front == rcu_access_pointer(obj->frontbuffer))) break; - intel_frontbuffer_put(front); + i915_gem_object_frontbuffer_put(front); } while (1); rcu_read_unlock(); return front; } -/** - * i915_gem_object_set_frontbuffer - Set the object's frontbuffer - * @obj: The object whose frontbuffer to set. - * @front: The frontbuffer to set - * - * Set object's frontbuffer pointer. If frontbuffer is already set for the - * object keep it and return it's pointer to the caller. Please note that RCU - * mechanism is used to handle e.g. ongoing removal of frontbuffer pointer. This - * function is protected by i915->display->fb_tracking.lock - * - * Return: pointer to frontbuffer which was set. - */ -static inline struct intel_frontbuffer * -i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj, - struct intel_frontbuffer *front) -{ - struct intel_frontbuffer *cur = front; - - if (!front) { - RCU_INIT_POINTER(obj->frontbuffer, NULL); - } else if (rcu_access_pointer(obj->frontbuffer)) { - cur = rcu_dereference_protected(obj->frontbuffer, true); - kref_get(&cur->ref); - } else { - rcu_assign_pointer(obj->frontbuffer, front); - } - - return cur; -} - #endif diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h index 64600aa8227f..465ce94aee76 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -574,7 +574,7 @@ struct drm_i915_gem_object { */ u16 write_domain; - struct intel_frontbuffer __rcu *frontbuffer; + struct i915_frontbuffer __rcu *frontbuffer; /** Current tiling stride for the object, if it's tiled. */ unsigned int tiling_and_stride; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 95f9ddf22ce4..5381a934a671 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -311,6 +311,8 @@ struct drm_i915_private { struct file *mmap_singleton; } gem; + spinlock_t frontbuffer_lock; /* protects obj->frontbuffer (write-side) */ + struct intel_pxp *pxp; struct i915_pmu pmu; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 638fe20dfe54..4c82c9544b93 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1299,6 +1299,8 @@ void i915_gem_init_early(struct drm_i915_private *dev_priv) { i915_gem_init__mm(dev_priv); i915_gem_init__contexts(dev_priv); + + spin_lock_init(&dev_priv->frontbuffer_lock); } void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 354ef75ef6a5..5bf3b4ab2baa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1233,6 +1233,7 @@ #define OROM_OFFSET_MASK REG_GENMASK(20, 16) #define MTL_MEM_SS_INFO_GLOBAL _MMIO(0x45700) +#define XE3P_ECC_IMPACTING_DE REG_BIT(12) #define MTL_N_OF_ENABLED_QGV_POINTS_MASK REG_GENMASK(11, 8) #define MTL_N_OF_POPULATED_CH_MASK REG_GENMASK(7, 4) #define MTL_DDR_TYPE_MASK REG_GENMASK(3, 0) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index ef9c272e60e5..1ce2dac75a66 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -1992,13 +1992,13 @@ int _i915_vma_move_to_active(struct i915_vma *vma, } if (flags & EXEC_OBJECT_WRITE) { - struct intel_frontbuffer *front; + struct i915_frontbuffer *front; - front = i915_gem_object_get_frontbuffer(obj); + front = i915_gem_object_frontbuffer_lookup(obj); if (unlikely(front)) { - if (intel_frontbuffer_invalidate(front, ORIGIN_CS)) + if (intel_frontbuffer_invalidate(&front->base, ORIGIN_CS)) i915_active_add_request(&front->write, rq); - intel_frontbuffer_put(front); + i915_gem_object_frontbuffer_put(front); } } diff --git a/drivers/gpu/drm/i915/soc/intel_dram.c b/drivers/gpu/drm/i915/soc/intel_dram.c index 2e16346a6cc0..3e588762709a 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.c +++ b/drivers/gpu/drm/i915/soc/intel_dram.c @@ -686,6 +686,7 @@ static int gen12_get_dram_info(struct drm_i915_private *i915, struct dram_info * static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info *dram_info) { + struct intel_display *display = i915->display; u32 val = intel_uncore_read(&i915->uncore, MTL_MEM_SS_INFO_GLOBAL); switch (REG_FIELD_GET(MTL_DDR_TYPE_MASK, val)) { @@ -724,6 +725,9 @@ static int xelpdp_get_dram_info(struct drm_i915_private *i915, struct dram_info dram_info->num_qgv_points = REG_FIELD_GET(MTL_N_OF_ENABLED_QGV_POINTS_MASK, val); /* PSF GV points not supported in D14+ */ + if (DISPLAY_VER(display) >= 35) + dram_info->ecc_impacting_de_bw = REG_FIELD_GET(XE3P_ECC_IMPACTING_DE, val); + return 0; } diff --git a/drivers/gpu/drm/i915/soc/intel_dram.h b/drivers/gpu/drm/i915/soc/intel_dram.h index 03a973f1c941..8475ee379daa 100644 --- a/drivers/gpu/drm/i915/soc/intel_dram.h +++ b/drivers/gpu/drm/i915/soc/intel_dram.h @@ -30,6 +30,7 @@ struct dram_info { u8 num_channels; u8 num_qgv_points; u8 num_psf_gv_points; + bool ecc_impacting_de_bw; /* Only valid from Xe3p_LPD onward. */ bool symmetric_memory; bool has_16gb_dimms; }; diff --git a/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h b/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h index 4465c40f8134..b17e3bab23d5 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/i915_vma.h @@ -26,8 +26,6 @@ struct i915_vma { struct xe_ggtt_node *node; }; -#define i915_ggtt_clear_scanout(bo) do { } while (0) - #define i915_vma_fence_id(vma) -1 static inline u32 i915_ggtt_offset(const struct i915_vma *vma) diff --git a/drivers/gpu/drm/xe/display/intel_bo.c b/drivers/gpu/drm/xe/display/intel_bo.c index 27437c22bd70..bad2243b9114 100644 --- a/drivers/gpu/drm/xe/display/intel_bo.c +++ b/drivers/gpu/drm/xe/display/intel_bo.c @@ -5,6 +5,7 @@ #include "xe_bo.h" #include "intel_bo.h" +#include "intel_frontbuffer.h" bool intel_bo_is_tiled(struct drm_gem_object *obj) { @@ -28,10 +29,6 @@ bool intel_bo_is_protected(struct drm_gem_object *obj) return xe_bo_is_protected(gem_to_xe_bo(obj)); } -void intel_bo_flush_if_display(struct drm_gem_object *obj) -{ -} - int intel_bo_fb_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) { return drm_gem_prime_mmap(obj, vma); @@ -44,15 +41,60 @@ int intel_bo_read_from_page(struct drm_gem_object *obj, u64 offset, void *dst, i return xe_bo_read(bo, offset, dst, size); } -struct intel_frontbuffer *intel_bo_get_frontbuffer(struct drm_gem_object *obj) +struct xe_frontbuffer { + struct intel_frontbuffer base; + struct drm_gem_object *obj; + struct kref ref; +}; + +struct intel_frontbuffer *intel_bo_frontbuffer_get(struct drm_gem_object *obj) +{ + struct xe_frontbuffer *front; + + front = kmalloc(sizeof(*front), GFP_KERNEL); + if (!front) + return NULL; + + intel_frontbuffer_init(&front->base, obj->dev); + + kref_init(&front->ref); + + drm_gem_object_get(obj); + front->obj = obj; + + return &front->base; +} + +void intel_bo_frontbuffer_ref(struct intel_frontbuffer *_front) { - return NULL; + struct xe_frontbuffer *front = + container_of(_front, typeof(*front), base); + + kref_get(&front->ref); +} + +static void frontbuffer_release(struct kref *ref) +{ + struct xe_frontbuffer *front = + container_of(ref, typeof(*front), ref); + + intel_frontbuffer_fini(&front->base); + + drm_gem_object_put(front->obj); + + kfree(front); +} + +void intel_bo_frontbuffer_put(struct intel_frontbuffer *_front) +{ + struct xe_frontbuffer *front = + container_of(_front, typeof(*front), base); + + kref_put(&front->ref, frontbuffer_release); } -struct intel_frontbuffer *intel_bo_set_frontbuffer(struct drm_gem_object *obj, - struct intel_frontbuffer *front) +void intel_bo_frontbuffer_flush_for_display(struct intel_frontbuffer *front) { - return front; } void intel_bo_describe(struct seq_file *m, struct drm_gem_object *obj) |