diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_dmc.c')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dmc.c | 123 |
1 files changed, 101 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 77a0199f9ea5..6ebbd97e6351 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -30,13 +30,13 @@ #include <drm/drm_print.h> #include "i915_reg.h" -#include "i915_utils.h" #include "intel_crtc.h" #include "intel_de.h" #include "intel_display_power_well.h" #include "intel_display_regs.h" #include "intel_display_rpm.h" #include "intel_display_types.h" +#include "intel_display_utils.h" #include "intel_dmc.h" #include "intel_dmc_regs.h" #include "intel_flipq.h" @@ -127,6 +127,12 @@ 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); + #define XE3LPD_DMC_PATH DMC_PATH(xe3lpd) MODULE_FIRMWARE(XE3LPD_DMC_PATH); @@ -184,8 +190,13 @@ 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 || - DISPLAY_VERx100(display) == 3000) { + 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) { fw_path = XE3LPD_DMC_PATH; max_fw_size = XE2LPD_DMC_MAX_FW_SIZE; } else if (DISPLAY_VERx100(display) == 2000) { @@ -509,10 +520,16 @@ static u32 pipedmc_interrupt_mask(struct intel_display *display) PIPEDMC_ATS_FAULT; } -static u32 dmc_evt_ctl_disable(void) +static u32 dmc_evt_ctl_disable(u32 dmc_evt_ctl) { - return REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, - DMC_EVT_CTL_TYPE_EDGE_0_1) | + /* + * DMC_EVT_CTL_ENABLE cannot be cleared once set. Always + * configure it based on the original event definition to + * avoid mismatches in assert_dmc_loaded(). + */ + return (dmc_evt_ctl & DMC_EVT_CTL_ENABLE) | + 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); } @@ -546,6 +563,51 @@ static bool is_event_handler(struct intel_display *display, REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == event_id; } +static bool fixup_dmc_evt(struct intel_display *display, + enum intel_dmc_id dmc_id, + i915_reg_t reg_ctl, u32 *data_ctl, + i915_reg_t reg_htp, u32 *data_htp) +{ + if (!is_dmc_evt_ctl_reg(display, dmc_id, reg_ctl)) + return false; + + if (!is_dmc_evt_htp_reg(display, dmc_id, reg_htp)) + return false; + + /* make sure reg_ctl and reg_htp are for the same event */ + if (i915_mmio_reg_offset(reg_ctl) - i915_mmio_reg_offset(DMC_EVT_CTL(display, dmc_id, 0)) != + i915_mmio_reg_offset(reg_htp) - i915_mmio_reg_offset(DMC_EVT_HTP(display, dmc_id, 0))) + return false; + + /* + * On ADL-S the HRR event handler is not restored after DC6. + * Clear it to zero from the beginning to avoid mismatches later. + */ + if (display->platform.alderlake_s && dmc_id == DMC_FW_MAIN && + is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg_ctl, *data_ctl)) { + *data_ctl = 0; + *data_htp = 0; + return true; + } + + /* + * TGL/ADL-S DMC firmware incorrectly uses the undelayed vblank + * event for the HRR handler, when it should be using the delayed + * vblank event instead. Fixed firmware was never released + * so the Windows driver just hacks around it by overriding + * the event ID. Do the same. + */ + if ((display->platform.tigerlake || display->platform.alderlake_s) && + is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg_ctl, *data_ctl)) { + *data_ctl &= ~DMC_EVT_CTL_EVENT_ID_MASK; + *data_ctl |= REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, + MAINDMC_EVENT_VBLANK_DELAYED_A); + return true; + } + + return false; +} + static bool disable_dmc_evt(struct intel_display *display, enum intel_dmc_id dmc_id, i915_reg_t reg, u32 data) @@ -564,7 +626,7 @@ static bool disable_dmc_evt(struct intel_display *display, /* also disable the HRR event on the main DMC on TGL/ADLS */ if ((display->platform.tigerlake || display->platform.alderlake_s) && - is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_A, reg, data)) + is_event_handler(display, dmc_id, MAINDMC_EVENT_VBLANK_DELAYED_A, reg, data)) return true; return false; @@ -577,7 +639,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 dmc_evt_ctl_disable(); + return dmc_evt_ctl_disable(dmc->dmc_info[dmc_id].mmiodata[i]); else return dmc->dmc_info[dmc_id].mmiodata[i]; } @@ -636,12 +698,6 @@ static void assert_dmc_loaded(struct intel_display *display, found = intel_de_read(display, reg); expected = dmc_mmiodata(display, dmc, dmc_id, i); - /* once set DMC_EVT_CTL_ENABLE can't be cleared :/ */ - if (is_dmc_evt_ctl_reg(display, dmc_id, reg)) { - found &= ~DMC_EVT_CTL_ENABLE; - expected &= ~DMC_EVT_CTL_ENABLE; - } - drm_WARN(display->drm, found != expected, "DMC %d mmio[%d]/0x%x incorrect (expected 0x%x, current 0x%x)\n", dmc_id, i, i915_mmio_reg_offset(reg), expected, found); @@ -662,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; /* @@ -794,7 +850,7 @@ static void dmc_configure_event(struct intel_display *display, if (!is_event_handler(display, dmc_id, event_id, reg, data)) continue; - intel_de_write(display, reg, enable ? data : dmc_evt_ctl_disable()); + intel_de_write(display, reg, enable ? data : dmc_evt_ctl_disable(data)); num_handlers++; } @@ -1064,9 +1120,32 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc, for (i = 0; i < mmio_count; i++) { dmc_info->mmioaddr[i] = _MMIO(mmioaddr[i]); dmc_info->mmiodata[i] = mmiodata[i]; + } + + for (i = 0; i < mmio_count - 1; i++) { + u32 orig_mmiodata[2] = { + dmc_info->mmiodata[i], + dmc_info->mmiodata[i+1], + }; + if (!fixup_dmc_evt(display, dmc_id, + dmc_info->mmioaddr[i], &dmc_info->mmiodata[i], + dmc_info->mmioaddr[i+1], &dmc_info->mmiodata[i+1])) + continue; + + drm_dbg_kms(display->drm, + " mmio[%d]: 0x%x = 0x%x->0x%x (EVT_CTL)\n", + i, i915_mmio_reg_offset(dmc_info->mmioaddr[i]), + orig_mmiodata[0], dmc_info->mmiodata[i]); + drm_dbg_kms(display->drm, + " mmio[%d]: 0x%x = 0x%x->0x%x (EVT_HTP)\n", + i+1, i915_mmio_reg_offset(dmc_info->mmioaddr[i+1]), + orig_mmiodata[1], dmc_info->mmiodata[i+1]); + } + + for (i = 0; i < mmio_count; i++) { drm_dbg_kms(display->drm, " mmio[%d]: 0x%x = 0x%x%s%s\n", - i, mmioaddr[i], mmiodata[i], + i, i915_mmio_reg_offset(dmc_info->mmioaddr[i]), dmc_info->mmiodata[i], is_dmc_evt_ctl_reg(display, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_CTL)" : is_dmc_evt_htp_reg(display, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_HTP)" : "", disable_dmc_evt(display, dmc_id, dmc_info->mmioaddr[i], @@ -1141,7 +1220,7 @@ parse_dmc_fw_package(struct intel_dmc *dmc, } num_entries = package_header->num_entries; - if (WARN_ON(package_header->num_entries > max_entries)) + if (WARN_ON(num_entries > max_entries)) num_entries = max_entries; fw_info = (const struct intel_fw_info *) @@ -1640,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, |
