diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dmc.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dmc.c | 185 |
1 files changed, 151 insertions, 34 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 98f80a6c63e8..a10e56e7cf31 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -27,9 +27,12 @@ #include "i915_drv.h" #include "i915_reg.h" +#include "intel_crtc.h" #include "intel_de.h" -#include "intel_display_rpm.h" #include "intel_display_power_well.h" +#include "intel_display_regs.h" +#include "intel_display_rpm.h" +#include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dmc_regs.h" #include "intel_step.h" @@ -173,7 +176,6 @@ MODULE_FIRMWARE(BXT_DMC_PATH); static const char *dmc_firmware_default(struct intel_display *display, u32 *size) { - struct drm_i915_private *i915 = to_i915(display->drm); const char *fw_path = NULL; u32 max_fw_size = 0; @@ -189,39 +191,39 @@ static const char *dmc_firmware_default(struct intel_display *display, u32 *size } else if (DISPLAY_VERx100(display) == 1400) { fw_path = MTL_DMC_PATH; max_fw_size = XELPDP_DMC_MAX_FW_SIZE; - } else if (IS_DG2(i915)) { + } else if (display->platform.dg2) { fw_path = DG2_DMC_PATH; max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE; - } else if (IS_ALDERLAKE_P(i915)) { + } else if (display->platform.alderlake_p) { fw_path = ADLP_DMC_PATH; max_fw_size = DISPLAY_VER13_DMC_MAX_FW_SIZE; - } else if (IS_ALDERLAKE_S(i915)) { + } else if (display->platform.alderlake_s) { fw_path = ADLS_DMC_PATH; max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; - } else if (IS_DG1(i915)) { + } else if (display->platform.dg1) { fw_path = DG1_DMC_PATH; max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; - } else if (IS_ROCKETLAKE(i915)) { + } else if (display->platform.rocketlake) { fw_path = RKL_DMC_PATH; max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; - } else if (IS_TIGERLAKE(i915)) { + } else if (display->platform.tigerlake) { fw_path = TGL_DMC_PATH; max_fw_size = DISPLAY_VER12_DMC_MAX_FW_SIZE; } else if (DISPLAY_VER(display) == 11) { fw_path = ICL_DMC_PATH; max_fw_size = ICL_DMC_MAX_FW_SIZE; - } else if (IS_GEMINILAKE(i915)) { + } else if (display->platform.geminilake) { fw_path = GLK_DMC_PATH; max_fw_size = GLK_DMC_MAX_FW_SIZE; - } else if (IS_KABYLAKE(i915) || - IS_COFFEELAKE(i915) || - IS_COMETLAKE(i915)) { + } else if (display->platform.kabylake || + display->platform.coffeelake || + display->platform.cometlake) { fw_path = KBL_DMC_PATH; max_fw_size = KBL_DMC_MAX_FW_SIZE; - } else if (IS_SKYLAKE(i915)) { + } else if (display->platform.skylake) { fw_path = SKL_DMC_PATH; max_fw_size = SKL_DMC_MAX_FW_SIZE; - } else if (IS_BROXTON(i915)) { + } else if (display->platform.broxton) { fw_path = BXT_DMC_PATH; max_fw_size = BXT_DMC_MAX_FW_SIZE; } @@ -426,7 +428,7 @@ static void disable_event_handler(struct intel_display *display, REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, DMC_EVT_CTL_TYPE_EDGE_0_1) | REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, - DMC_EVT_CTL_EVENT_ID_FALSE)); + DMC_EVENT_FALSE)); intel_de_write(display, htp_reg, 0); } @@ -491,6 +493,17 @@ static void pipedmc_clock_gating_wa(struct intel_display *display, bool enable) adlp_pipedmc_clock_gating_wa(display, enable); } +static u32 pipedmc_interrupt_mask(struct intel_display *display) +{ + /* + * FIXME PIPEDMC_ERROR not enabled for now due to LNL pipe B + * triggering it during the first DC state transition. Figure + * out what is going on... + */ + return PIPEDMC_GTT_FAULT | + PIPEDMC_ATS_FAULT; +} + void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe) { enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); @@ -498,6 +511,11 @@ void intel_dmc_enable_pipe(struct intel_display *display, enum pipe pipe) if (!is_valid_dmc_id(dmc_id) || !has_dmc_id_fw(display, dmc_id)) return; + if (DISPLAY_VER(display) >= 20) { + intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); + intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~pipedmc_interrupt_mask(display)); + } + if (DISPLAY_VER(display) >= 14) intel_de_rmw(display, MTL_PIPEDMC_CONTROL, 0, PIPEDMC_ENABLE_MTL(pipe)); else @@ -515,6 +533,19 @@ void intel_dmc_disable_pipe(struct intel_display *display, enum pipe pipe) intel_de_rmw(display, MTL_PIPEDMC_CONTROL, PIPEDMC_ENABLE_MTL(pipe), 0); else intel_de_rmw(display, PIPEDMC_CONTROL(pipe), PIPEDMC_ENABLE, 0); + + if (DISPLAY_VER(display) >= 20) { + intel_de_write(display, PIPEDMC_INTERRUPT_MASK(pipe), ~0); + intel_de_write(display, PIPEDMC_INTERRUPT(pipe), pipedmc_interrupt_mask(display)); + } +} + +static u32 dmc_evt_ctl_disable(void) +{ + return REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, + DMC_EVT_CTL_TYPE_EDGE_0_1) | + REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, + DMC_EVENT_FALSE); } static bool is_dmc_evt_ctl_reg(struct intel_display *display, @@ -537,12 +568,79 @@ static bool is_dmc_evt_htp_reg(struct intel_display *display, return offset >= start && offset < end; } +static bool is_event_handler(struct intel_display *display, + enum intel_dmc_id dmc_id, + unsigned int event_id, + i915_reg_t reg, u32 data) +{ + return is_dmc_evt_ctl_reg(display, dmc_id, reg) && + REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == event_id; +} + +static void dmc_configure_event(struct intel_display *display, + enum intel_dmc_id dmc_id, + unsigned int event_id, + bool enable) +{ + struct intel_dmc *dmc = display_to_dmc(display); + int num_handlers = 0; + int i; + + for (i = 0; i < dmc->dmc_info[dmc_id].mmio_count; i++) { + i915_reg_t reg = dmc->dmc_info[dmc_id].mmioaddr[i]; + u32 data = dmc->dmc_info[dmc_id].mmiodata[i]; + + if (!is_event_handler(display, dmc_id, event_id, reg, data)) + continue; + + intel_de_write(display, reg, enable ? data : dmc_evt_ctl_disable()); + num_handlers++; + } + + drm_WARN_ONCE(display->drm, num_handlers != 1, + "DMC %d has %d handlers for event 0x%x\n", + dmc_id, num_handlers, event_id); +} + +/** + * intel_dmc_block_pkgc() - block PKG C-state + * @display: display instance + * @pipe: pipe which register use to block + * @block: block/unblock + * + * This interface is target for Wa_16025596647 usage. I.e. to set/clear + * PIPEDMC_BLOCK_PKGC_SW_BLOCK_PKGC_ALWAYS bit in PIPEDMC_BLOCK_PKGC_SW register. + */ +void intel_dmc_block_pkgc(struct intel_display *display, enum pipe pipe, + bool block) +{ + intel_de_rmw(display, PIPEDMC_BLOCK_PKGC_SW(pipe), + PIPEDMC_BLOCK_PKGC_SW_BLOCK_PKGC_ALWAYS, block ? + PIPEDMC_BLOCK_PKGC_SW_BLOCK_PKGC_ALWAYS : 0); +} + +/** + * intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank() - start of PKG + * C-state exit + * @display: display instance + * @pipe: pipe which register use to block + * @enable: enable/disable + * + * This interface is target for Wa_16025596647 usage. I.e. start the package C + * exit at the start of the undelayed vblank + */ +void intel_dmc_start_pkgc_exit_at_start_of_undelayed_vblank(struct intel_display *display, + enum pipe pipe, bool enable) +{ + enum intel_dmc_id dmc_id = PIPE_TO_DMC_ID(pipe); + + dmc_configure_event(display, dmc_id, PIPEDMC_EVENT_VBLANK, enable); +} + static bool disable_dmc_evt(struct intel_display *display, enum intel_dmc_id dmc_id, i915_reg_t reg, u32 data) { - struct drm_i915_private *i915 = to_i915(display->drm); - if (!is_dmc_evt_ctl_reg(display, dmc_id, reg)) return false; @@ -551,13 +649,13 @@ static bool disable_dmc_evt(struct intel_display *display, return true; /* also disable the flip queue event on the main DMC on TGL */ - if (IS_TIGERLAKE(i915) && - REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == DMC_EVT_CTL_EVENT_ID_CLK_MSEC) + if (display->platform.tigerlake && + is_event_handler(display, dmc_id, MAINDMC_EVENT_CLK_MSEC, reg, data)) return true; /* also disable the HRR event on the main DMC on TGL/ADLS */ - if ((IS_TIGERLAKE(i915) || IS_ALDERLAKE_S(i915)) && - REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == DMC_EVT_CTL_EVENT_ID_VBLANK_A) + if ((display->platform.tigerlake || display->platform.alderlake_s) && + is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg, data)) return true; return false; @@ -570,10 +668,7 @@ static u32 dmc_mmiodata(struct intel_display *display, if (disable_dmc_evt(display, dmc_id, dmc->dmc_info[dmc_id].mmioaddr[i], dmc->dmc_info[dmc_id].mmiodata[i])) - return REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, - DMC_EVT_CTL_TYPE_EDGE_0_1) | - REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, - DMC_EVT_CTL_EVENT_ID_FALSE); + return dmc_evt_ctl_disable(); else return dmc->dmc_info[dmc_id].mmiodata[i]; } @@ -588,7 +683,6 @@ static u32 dmc_mmiodata(struct intel_display *display, */ void intel_dmc_load_program(struct intel_display *display) { - struct drm_i915_private *i915 __maybe_unused = to_i915(display->drm); struct i915_power_domains *power_domains = &display->power.domains; struct intel_dmc *dmc = display_to_dmc(display); enum intel_dmc_id dmc_id; @@ -1012,9 +1106,7 @@ static void intel_dmc_runtime_pm_put(struct intel_display *display) static const char *dmc_fallback_path(struct intel_display *display) { - struct drm_i915_private *i915 = to_i915(display->drm); - - if (IS_ALDERLAKE_P(i915)) + if (display->platform.alderlake_p) return ADLP_DMC_FALLBACK_PATH; return NULL; @@ -1279,7 +1371,6 @@ static bool intel_dmc_get_dc6_allowed_count(struct intel_display *display, u32 * static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) { struct intel_display *display = m->private; - struct drm_i915_private *i915 = to_i915(display->drm); struct intel_dmc *dmc = display_to_dmc(display); struct ref_tracker *wakeref; i915_reg_t dc5_reg, dc6_reg = INVALID_MMIO_REG; @@ -1299,7 +1390,7 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) seq_printf(m, "Pipe A fw loaded: %s\n", str_yes_no(has_dmc_id_fw(display, DMC_FW_PIPEA))); seq_printf(m, "Pipe B fw needed: %s\n", - str_yes_no(IS_ALDERLAKE_P(i915) || + str_yes_no(display->platform.alderlake_p || DISPLAY_VER(display) >= 14)); seq_printf(m, "Pipe B fw loaded: %s\n", str_yes_no(has_dmc_id_fw(display, DMC_FW_PIPEB))); @@ -1313,7 +1404,7 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) if (DISPLAY_VER(display) >= 12) { i915_reg_t dc3co_reg; - if (IS_DGFX(i915) || DISPLAY_VER(display) >= 14) { + if (display->platform.dgfx || DISPLAY_VER(display) >= 14) { dc3co_reg = DG1_DMC_DEBUG3; dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; } else { @@ -1325,9 +1416,9 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) seq_printf(m, "DC3CO count: %d\n", intel_de_read(display, dc3co_reg)); } else { - dc5_reg = IS_BROXTON(i915) ? BXT_DMC_DC3_DC5_COUNT : + dc5_reg = display->platform.broxton ? BXT_DMC_DC3_DC5_COUNT : SKL_DMC_DC3_DC5_COUNT; - if (!IS_GEMINILAKE(i915) && !IS_BROXTON(i915)) + if (!display->platform.geminilake && !display->platform.broxton) dc6_reg = SKL_DMC_DC5_DC6_COUNT; } @@ -1362,3 +1453,29 @@ void intel_dmc_debugfs_register(struct intel_display *display) debugfs_create_file("i915_dmc_info", 0444, minor->debugfs_root, display, &intel_dmc_debugfs_status_fops); } + +void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) +{ + struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); + u32 tmp; + + if (DISPLAY_VER(display) >= 20) { + tmp = intel_de_read(display, PIPEDMC_INTERRUPT(pipe)); + intel_de_write(display, PIPEDMC_INTERRUPT(pipe), tmp); + + if (tmp & PIPEDMC_ATS_FAULT) + drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC ATS fault\n", + crtc->base.base.id, crtc->base.name); + if (tmp & PIPEDMC_GTT_FAULT) + 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", + crtc->base.base.id, crtc->base.name); + } + + tmp = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; + if (tmp) + drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n", + crtc->base.base.id, crtc->base.name, tmp); +} |
