Merge tag 'drm-intel-fixes-2024-09-05' of https://gitlab.freedesktop.org/drm/i915/kernel into drm-fixes
- drm/i915: Do not attempt to load the GSC multiple times (Daniele Ceraolo Spurio) - drm/i915: Fix readout degamma_lut mismatch on ilk/snb (Ville Syrjälä) - drm/i915/fence: Mark debug_fence_init_onstack() with __maybe_unused (Andy Shevchenko) - drm/i915/fence: Mark debug_fence_free() with __maybe_unused (Andy Shevchenko) - drm/i915/display: Add mechanism to use sink model when applying quirk [display] (Jouni Högander) - drm/i915/display: Increase Fast Wake Sync length as a quirk [display] (Jouni Högander) Signed-off-by: Dave Airlie <airlied@redhat.com> From: Tvrtko Ursulin <tursulin@igalia.com> Link: https://patchwork.freedesktop.org/patch/msgid/Ztlo2hVO4SBvfAnq@linux
This commit is contained in:
@@ -228,7 +228,7 @@ bool intel_alpm_compute_params(struct intel_dp *intel_dp,
|
||||
int tfw_exit_latency = 20; /* eDP spec */
|
||||
int phy_wake = 4; /* eDP spec */
|
||||
int preamble = 8; /* eDP spec */
|
||||
int precharge = intel_dp_aux_fw_sync_len() - preamble;
|
||||
int precharge = intel_dp_aux_fw_sync_len(intel_dp) - preamble;
|
||||
u8 max_wake_lines;
|
||||
|
||||
io_wake_time = max(precharge, io_buffer_wake_time(crtc_state)) +
|
||||
|
||||
@@ -1885,6 +1885,10 @@ struct intel_dp {
|
||||
} alpm_parameters;
|
||||
|
||||
u8 alpm_dpcd;
|
||||
|
||||
struct {
|
||||
unsigned long mask;
|
||||
} quirks;
|
||||
};
|
||||
|
||||
enum lspcon_vendor {
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
#include "intel_pch_display.h"
|
||||
#include "intel_pps.h"
|
||||
#include "intel_psr.h"
|
||||
#include "intel_quirks.h"
|
||||
#include "intel_tc.h"
|
||||
#include "intel_vdsc.h"
|
||||
#include "intel_vrr.h"
|
||||
@@ -3952,6 +3953,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector
|
||||
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
|
||||
|
||||
/*
|
||||
* Read the eDP display control registers.
|
||||
@@ -4064,6 +4066,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
|
||||
intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
|
||||
|
||||
intel_dp_update_sink_caps(intel_dp);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "intel_dp_aux.h"
|
||||
#include "intel_dp_aux_regs.h"
|
||||
#include "intel_pps.h"
|
||||
#include "intel_quirks.h"
|
||||
#include "intel_tc.h"
|
||||
|
||||
#define AUX_CH_NAME_BUFSIZE 6
|
||||
@@ -142,16 +143,21 @@ static int intel_dp_aux_sync_len(void)
|
||||
return precharge + preamble;
|
||||
}
|
||||
|
||||
int intel_dp_aux_fw_sync_len(void)
|
||||
int intel_dp_aux_fw_sync_len(struct intel_dp *intel_dp)
|
||||
{
|
||||
int precharge = 10; /* 10-16 */
|
||||
int preamble = 8;
|
||||
|
||||
/*
|
||||
* We faced some glitches on Dell Precision 5490 MTL laptop with panel:
|
||||
* "Manufacturer: AUO, Model: 63898" when using HW default 18. Using 20
|
||||
* is fixing these problems with the panel. It is still within range
|
||||
* mentioned in eDP specification.
|
||||
* mentioned in eDP specification. Increasing Fast Wake sync length is
|
||||
* causing problems with other panels: increase length as a quirk for
|
||||
* this specific laptop.
|
||||
*/
|
||||
int precharge = 12; /* 10-16 */
|
||||
int preamble = 8;
|
||||
if (intel_has_dpcd_quirk(intel_dp, QUIRK_FW_SYNC_LEN))
|
||||
precharge += 2;
|
||||
|
||||
return precharge + preamble;
|
||||
}
|
||||
@@ -211,7 +217,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp,
|
||||
DP_AUX_CH_CTL_TIME_OUT_MAX |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR |
|
||||
DP_AUX_CH_CTL_MESSAGE_SIZE(send_bytes) |
|
||||
DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(intel_dp_aux_fw_sync_len()) |
|
||||
DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(intel_dp_aux_fw_sync_len(intel_dp)) |
|
||||
DP_AUX_CH_CTL_SYNC_PULSE_SKL(intel_dp_aux_sync_len());
|
||||
|
||||
if (intel_tc_port_in_tbt_alt_mode(dig_port))
|
||||
|
||||
@@ -20,6 +20,6 @@ enum aux_ch intel_dp_aux_ch(struct intel_encoder *encoder);
|
||||
|
||||
void intel_dp_aux_irq_handler(struct drm_i915_private *i915);
|
||||
u32 intel_dp_aux_pack(const u8 *src, int src_bytes);
|
||||
int intel_dp_aux_fw_sync_len(void);
|
||||
int intel_dp_aux_fw_sync_len(struct intel_dp *intel_dp);
|
||||
|
||||
#endif /* __INTEL_DP_AUX_H__ */
|
||||
|
||||
@@ -326,6 +326,8 @@ static void intel_modeset_update_connector_atomic_state(struct drm_i915_private
|
||||
|
||||
static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
|
||||
|
||||
if (intel_crtc_is_joiner_secondary(crtc_state))
|
||||
return;
|
||||
|
||||
@@ -337,11 +339,30 @@ static void intel_crtc_copy_hw_to_uapi_state(struct intel_crtc_state *crtc_state
|
||||
crtc_state->uapi.adjusted_mode = crtc_state->hw.adjusted_mode;
|
||||
crtc_state->uapi.scaling_filter = crtc_state->hw.scaling_filter;
|
||||
|
||||
/* assume 1:1 mapping */
|
||||
drm_property_replace_blob(&crtc_state->hw.degamma_lut,
|
||||
crtc_state->pre_csc_lut);
|
||||
drm_property_replace_blob(&crtc_state->hw.gamma_lut,
|
||||
crtc_state->post_csc_lut);
|
||||
if (DISPLAY_INFO(i915)->color.degamma_lut_size) {
|
||||
/* assume 1:1 mapping */
|
||||
drm_property_replace_blob(&crtc_state->hw.degamma_lut,
|
||||
crtc_state->pre_csc_lut);
|
||||
drm_property_replace_blob(&crtc_state->hw.gamma_lut,
|
||||
crtc_state->post_csc_lut);
|
||||
} else {
|
||||
/*
|
||||
* ilk/snb hw may be configured for either pre_csc_lut
|
||||
* or post_csc_lut, but we don't advertise degamma_lut as
|
||||
* being available in the uapi since there is only one
|
||||
* hardware LUT. Always assign the result of the readout
|
||||
* to gamma_lut as that is the only valid source of LUTs
|
||||
* in the uapi.
|
||||
*/
|
||||
drm_WARN_ON(&i915->drm, crtc_state->post_csc_lut &&
|
||||
crtc_state->pre_csc_lut);
|
||||
|
||||
drm_property_replace_blob(&crtc_state->hw.degamma_lut,
|
||||
NULL);
|
||||
drm_property_replace_blob(&crtc_state->hw.gamma_lut,
|
||||
crtc_state->post_csc_lut ?:
|
||||
crtc_state->pre_csc_lut);
|
||||
}
|
||||
|
||||
drm_property_replace_blob(&crtc_state->uapi.degamma_lut,
|
||||
crtc_state->hw.degamma_lut);
|
||||
|
||||
@@ -14,6 +14,11 @@ static void intel_set_quirk(struct intel_display *display, enum intel_quirk_id q
|
||||
display->quirks.mask |= BIT(quirk);
|
||||
}
|
||||
|
||||
static void intel_set_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk)
|
||||
{
|
||||
intel_dp->quirks.mask |= BIT(quirk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
|
||||
*/
|
||||
@@ -65,6 +70,14 @@ static void quirk_no_pps_backlight_power_hook(struct intel_display *display)
|
||||
drm_info(display->drm, "Applying no pps backlight power quirk\n");
|
||||
}
|
||||
|
||||
static void quirk_fw_sync_len(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
|
||||
intel_set_dpcd_quirk(intel_dp, QUIRK_FW_SYNC_LEN);
|
||||
drm_info(display->drm, "Applying Fast Wake sync pulse count quirk\n");
|
||||
}
|
||||
|
||||
struct intel_quirk {
|
||||
int device;
|
||||
int subsystem_vendor;
|
||||
@@ -72,6 +85,21 @@ struct intel_quirk {
|
||||
void (*hook)(struct intel_display *display);
|
||||
};
|
||||
|
||||
struct intel_dpcd_quirk {
|
||||
int device;
|
||||
int subsystem_vendor;
|
||||
int subsystem_device;
|
||||
u8 sink_oui[3];
|
||||
u8 sink_device_id[6];
|
||||
void (*hook)(struct intel_dp *intel_dp);
|
||||
};
|
||||
|
||||
#define SINK_OUI(first, second, third) { (first), (second), (third) }
|
||||
#define SINK_DEVICE_ID(first, second, third, fourth, fifth, sixth) \
|
||||
{ (first), (second), (third), (fourth), (fifth), (sixth) }
|
||||
|
||||
#define SINK_DEVICE_ID_ANY SINK_DEVICE_ID(0, 0, 0, 0, 0, 0)
|
||||
|
||||
/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
|
||||
struct intel_dmi_quirk {
|
||||
void (*hook)(struct intel_display *display);
|
||||
@@ -203,6 +231,18 @@ static struct intel_quirk intel_quirks[] = {
|
||||
{ 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
|
||||
};
|
||||
|
||||
static struct intel_dpcd_quirk intel_dpcd_quirks[] = {
|
||||
/* Dell Precision 5490 */
|
||||
{
|
||||
.device = 0x7d55,
|
||||
.subsystem_vendor = 0x1028,
|
||||
.subsystem_device = 0x0cc7,
|
||||
.sink_oui = SINK_OUI(0x38, 0xec, 0x11),
|
||||
.hook = quirk_fw_sync_len,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
void intel_init_quirks(struct intel_display *display)
|
||||
{
|
||||
struct pci_dev *d = to_pci_dev(display->drm->dev);
|
||||
@@ -224,7 +264,35 @@ void intel_init_quirks(struct intel_display *display)
|
||||
}
|
||||
}
|
||||
|
||||
void intel_init_dpcd_quirks(struct intel_dp *intel_dp,
|
||||
const struct drm_dp_dpcd_ident *ident)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(intel_dp);
|
||||
struct pci_dev *d = to_pci_dev(display->drm->dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(intel_dpcd_quirks); i++) {
|
||||
struct intel_dpcd_quirk *q = &intel_dpcd_quirks[i];
|
||||
|
||||
if (d->device == q->device &&
|
||||
(d->subsystem_vendor == q->subsystem_vendor ||
|
||||
q->subsystem_vendor == PCI_ANY_ID) &&
|
||||
(d->subsystem_device == q->subsystem_device ||
|
||||
q->subsystem_device == PCI_ANY_ID) &&
|
||||
!memcmp(q->sink_oui, ident->oui, sizeof(ident->oui)) &&
|
||||
(!memcmp(q->sink_device_id, ident->device_id,
|
||||
sizeof(ident->device_id)) ||
|
||||
!memchr_inv(q->sink_device_id, 0, sizeof(q->sink_device_id))))
|
||||
q->hook(intel_dp);
|
||||
}
|
||||
}
|
||||
|
||||
bool intel_has_quirk(struct intel_display *display, enum intel_quirk_id quirk)
|
||||
{
|
||||
return display->quirks.mask & BIT(quirk);
|
||||
}
|
||||
|
||||
bool intel_has_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk)
|
||||
{
|
||||
return intel_dp->quirks.mask & BIT(quirk);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
struct intel_display;
|
||||
struct intel_dp;
|
||||
struct drm_dp_dpcd_ident;
|
||||
|
||||
enum intel_quirk_id {
|
||||
QUIRK_BACKLIGHT_PRESENT,
|
||||
@@ -17,9 +19,13 @@ enum intel_quirk_id {
|
||||
QUIRK_INVERT_BRIGHTNESS,
|
||||
QUIRK_LVDS_SSC_DISABLE,
|
||||
QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
|
||||
QUIRK_FW_SYNC_LEN,
|
||||
};
|
||||
|
||||
void intel_init_quirks(struct intel_display *display);
|
||||
void intel_init_dpcd_quirks(struct intel_dp *intel_dp,
|
||||
const struct drm_dp_dpcd_ident *ident);
|
||||
bool intel_has_quirk(struct intel_display *display, enum intel_quirk_id quirk);
|
||||
bool intel_has_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk);
|
||||
|
||||
#endif /* __INTEL_QUIRKS_H__ */
|
||||
|
||||
@@ -302,7 +302,7 @@ void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)
|
||||
{
|
||||
struct intel_gt *gt = gsc_uc_to_gt(gsc);
|
||||
|
||||
if (!intel_uc_fw_is_loadable(&gsc->fw))
|
||||
if (!intel_uc_fw_is_loadable(&gsc->fw) || intel_uc_fw_is_in_error(&gsc->fw))
|
||||
return;
|
||||
|
||||
if (intel_gsc_uc_fw_init_done(gsc))
|
||||
|
||||
@@ -258,6 +258,11 @@ static inline bool intel_uc_fw_is_running(struct intel_uc_fw *uc_fw)
|
||||
return __intel_uc_fw_status(uc_fw) == INTEL_UC_FIRMWARE_RUNNING;
|
||||
}
|
||||
|
||||
static inline bool intel_uc_fw_is_in_error(struct intel_uc_fw *uc_fw)
|
||||
{
|
||||
return intel_uc_fw_status_to_error(__intel_uc_fw_status(uc_fw)) != 0;
|
||||
}
|
||||
|
||||
static inline bool intel_uc_fw_is_overridden(const struct intel_uc_fw *uc_fw)
|
||||
{
|
||||
return uc_fw->user_overridden;
|
||||
|
||||
@@ -51,7 +51,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence)
|
||||
debug_object_init(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
|
||||
static inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
{
|
||||
debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
@@ -77,7 +77,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence)
|
||||
debug_object_destroy(fence, &i915_sw_fence_debug_descr);
|
||||
}
|
||||
|
||||
static inline void debug_fence_free(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence)
|
||||
{
|
||||
debug_object_free(fence, &i915_sw_fence_debug_descr);
|
||||
smp_wmb(); /* flush the change in state before reallocation */
|
||||
@@ -94,7 +94,7 @@ static inline void debug_fence_init(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_init_onstack(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ static inline void debug_fence_destroy(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void debug_fence_free(struct i915_sw_fence *fence)
|
||||
static inline __maybe_unused void debug_fence_free(struct i915_sw_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user