Commit 43cf50eb authored by Jouni Högander's avatar Jouni Högander Committed by Joonas Lahtinen

drm/i915/display: Add mechanism to use sink model when applying quirk

Currently there is no way to apply quirk on device only if certain panel
model is installed. This patch implements such mechanism by adding new
quirk type intel_dpcd_quirk which contains also sink_oui and sink_device_id
fields and using also them to figure out if applying quirk is needed.

New intel_init_dpcd_quirks is added and called after drm_dp_read_desc with
proper sink device identity read from dpcdc.

v3:
  - !mem_is_zero fixed to mem_is_zero
v2:
  - instead of using struct intel_quirk add new struct intel_dpcd_quirk
Signed-off-by: default avatarJouni Högander <jouni.hogander@intel.com>
Reviewed-by: default avatarJani Nikula <jani.nikula@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240902064241.1020965-2-jouni.hogander@intel.com
(cherry picked from commit b3b91369)
Signed-off-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
parent f9999953
......@@ -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);
}
......
......@@ -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
*/
......@@ -72,6 +77,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 +223,9 @@ static struct intel_quirk intel_quirks[] = {
{ 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
};
static struct intel_dpcd_quirk intel_dpcd_quirks[] = {
};
void intel_init_quirks(struct intel_display *display)
{
struct pci_dev *d = to_pci_dev(display->drm->dev);
......@@ -224,7 +247,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)) ||
mem_is_zero(q->sink_device_id, 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,
......@@ -20,6 +22,9 @@ enum intel_quirk_id {
};
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__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment