Commit c518a775 authored by Ville Syrjälä's avatar Ville Syrjälä
Browse files

drm/i915/bios: Determine panel type via PNPID match

Apparently when the VBT panel_type==0xff we should trawl through
the PNPID table and check for a match against the EDID. If a
match is found the index gives us the panel_type.

Tried to match the Windows behaviour here with first looking
for an exact match, and if one isn't found we fall back to
looking for a match w/o the mfg year/week.

v2: Rebase due to vlv_dsi changes
v3: Adjust to .get_panel_type() vfunc

Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/5545


Reviewed-by: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-14-ville.syrjala@linux.intel.com
parent 3cf05076
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2049,7 +2049,7 @@ void icl_dsi_init(struct drm_i915_private *dev_priv)
	/* attach connector to encoder */
	intel_connector_attach_encoder(intel_connector, encoder);

	intel_bios_init_panel(dev_priv, &intel_connector->panel);
	intel_bios_init_panel(dev_priv, &intel_connector->panel, NULL);

	mutex_lock(&dev->mode_config.mutex);
	intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
+85 −13
Original line number Diff line number Diff line
@@ -584,6 +584,14 @@ get_lvds_fp_timing(const struct bdb_lvds_lfp_data *data,
	return (const void *)data + ptrs->ptr[index].fp_timing.offset;
}

static const struct lvds_pnp_id *
get_lvds_pnp_id(const struct bdb_lvds_lfp_data *data,
		const struct bdb_lvds_lfp_data_ptrs *ptrs,
		int index)
{
	return (const void *)data + ptrs->ptr[index].panel_pnp_id.offset;
}

static const struct bdb_lvds_lfp_data_tail *
get_lfp_data_tail(const struct bdb_lvds_lfp_data *data,
		  const struct bdb_lvds_lfp_data_ptrs *ptrs)
@@ -594,12 +602,14 @@ get_lfp_data_tail(const struct bdb_lvds_lfp_data *data,
		return NULL;
}

static int opregion_get_panel_type(struct drm_i915_private *i915)
static int opregion_get_panel_type(struct drm_i915_private *i915,
				   const struct edid *edid)
{
	return intel_opregion_get_panel_type(i915);
}

static int vbt_get_panel_type(struct drm_i915_private *i915)
static int vbt_get_panel_type(struct drm_i915_private *i915,
			      const struct edid *edid)
{
	const struct bdb_lvds_options *lvds_options;

@@ -607,7 +617,8 @@ static int vbt_get_panel_type(struct drm_i915_private *i915)
	if (!lvds_options)
		return -1;

	if (lvds_options->panel_type > 0xf) {
	if (lvds_options->panel_type > 0xf &&
	    lvds_options->panel_type != 0xff) {
		drm_dbg_kms(&i915->drm, "Invalid VBT panel type 0x%x\n",
			    lvds_options->panel_type);
		return -1;
@@ -616,7 +627,54 @@ static int vbt_get_panel_type(struct drm_i915_private *i915)
	return lvds_options->panel_type;
}

static int fallback_get_panel_type(struct drm_i915_private *i915)
static int pnpid_get_panel_type(struct drm_i915_private *i915,
				const struct edid *edid)
{
	const struct bdb_lvds_lfp_data *data;
	const struct bdb_lvds_lfp_data_ptrs *ptrs;
	const struct lvds_pnp_id *edid_id;
	struct lvds_pnp_id edid_id_nodate;
	int i, best = -1;

	if (!edid)
		return -1;

	edid_id = (const void *)&edid->mfg_id[0];

	edid_id_nodate = *edid_id;
	edid_id_nodate.mfg_week = 0;
	edid_id_nodate.mfg_year = 0;

	ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS);
	if (!ptrs)
		return -1;

	data = find_section(i915, BDB_LVDS_LFP_DATA);
	if (!data)
		return -1;

	for (i = 0; i < 16; i++) {
		const struct lvds_pnp_id *vbt_id =
			get_lvds_pnp_id(data, ptrs, i);

		/* full match? */
		if (!memcmp(vbt_id, edid_id, sizeof(*vbt_id)))
			return i;

		/*
		 * Accept a match w/o date if no full match is found,
		 * and the VBT entry does not specify a date.
		 */
		if (best < 0 &&
		    !memcmp(vbt_id, &edid_id_nodate, sizeof(*vbt_id)))
			best = i;
	}

	return best;
}

static int fallback_get_panel_type(struct drm_i915_private *i915,
				   const struct edid *edid)
{
	return 0;
}
@@ -624,14 +682,17 @@ static int fallback_get_panel_type(struct drm_i915_private *i915)
enum panel_type {
	PANEL_TYPE_OPREGION,
	PANEL_TYPE_VBT,
	PANEL_TYPE_PNPID,
	PANEL_TYPE_FALLBACK,
};

static int get_panel_type(struct drm_i915_private *i915)
static int get_panel_type(struct drm_i915_private *i915,
			  const struct edid *edid)
{
	struct {
		const char *name;
		int (*get_panel_type)(struct drm_i915_private *i915);
		int (*get_panel_type)(struct drm_i915_private *i915,
				      const struct edid *edid);
		int panel_type;
	} panel_types[] = {
		[PANEL_TYPE_OPREGION] = {
@@ -642,6 +703,10 @@ static int get_panel_type(struct drm_i915_private *i915)
			.name = "VBT",
			.get_panel_type = vbt_get_panel_type,
		},
		[PANEL_TYPE_PNPID] = {
			.name = "PNPID",
			.get_panel_type = pnpid_get_panel_type,
		},
		[PANEL_TYPE_FALLBACK] = {
			.name = "fallback",
			.get_panel_type = fallback_get_panel_type,
@@ -650,9 +715,10 @@ static int get_panel_type(struct drm_i915_private *i915)
	int i;

	for (i = 0; i < ARRAY_SIZE(panel_types); i++) {
		panel_types[i].panel_type = panel_types[i].get_panel_type(i915);
		panel_types[i].panel_type = panel_types[i].get_panel_type(i915, edid);

		drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf);
		drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf &&
			    panel_types[i].panel_type != 0xff);

		if (panel_types[i].panel_type >= 0)
			drm_dbg_kms(&i915->drm, "Panel type (%s): %d\n",
@@ -661,7 +727,11 @@ static int get_panel_type(struct drm_i915_private *i915)

	if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0)
		i = PANEL_TYPE_OPREGION;
	else if (panel_types[PANEL_TYPE_VBT].panel_type >= 0)
	else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff &&
		 panel_types[PANEL_TYPE_PNPID].panel_type >= 0)
		i = PANEL_TYPE_PNPID;
	else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff &&
		 panel_types[PANEL_TYPE_VBT].panel_type >= 0)
		i = PANEL_TYPE_VBT;
	else
		i = PANEL_TYPE_FALLBACK;
@@ -675,7 +745,8 @@ static int get_panel_type(struct drm_i915_private *i915)
/* Parse general panel options */
static void
parse_panel_options(struct drm_i915_private *i915,
		    struct intel_panel *panel)
		    struct intel_panel *panel,
		    const struct edid *edid)
{
	const struct bdb_lvds_options *lvds_options;
	int panel_type;
@@ -687,7 +758,7 @@ parse_panel_options(struct drm_i915_private *i915,

	panel->vbt.lvds_dither = lvds_options->pixel_dither;

	panel_type = get_panel_type(i915);
	panel_type = get_panel_type(i915, edid);

	panel->vbt.panel_type = panel_type;

@@ -2998,11 +3069,12 @@ void intel_bios_init(struct drm_i915_private *i915)
}

void intel_bios_init_panel(struct drm_i915_private *i915,
			   struct intel_panel *panel)
			   struct intel_panel *panel,
			   const struct edid *edid)
{
	init_vbt_panel_defaults(panel);

	parse_panel_options(i915, panel);
	parse_panel_options(i915, panel, edid);
	parse_generic_dtd(i915, panel);
	parse_lfp_data(i915, panel);
	parse_lfp_backlight(i915, panel);
+3 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/types.h>

struct drm_i915_private;
struct edid;
struct intel_bios_encoder_data;
struct intel_crtc_state;
struct intel_encoder;
@@ -232,7 +233,8 @@ struct mipi_pps_data {

void intel_bios_init(struct drm_i915_private *dev_priv);
void intel_bios_init_panel(struct drm_i915_private *dev_priv,
			   struct intel_panel *panel);
			   struct intel_panel *panel,
			   const struct edid *edid);
void intel_bios_fini_panel(struct intel_panel *panel);
void intel_bios_driver_remove(struct drm_i915_private *dev_priv);
bool intel_bios_is_valid_vbt(const void *buf, size_t size);
+2 −1
Original line number Diff line number Diff line
@@ -5212,7 +5212,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
	}
	intel_connector->edid = edid;

	intel_bios_init_panel(dev_priv, &intel_connector->panel);
	intel_bios_init_panel(dev_priv, &intel_connector->panel,
			      IS_ERR(edid) ? NULL : edid);

	intel_panel_add_edid_fixed_modes(intel_connector,
					 intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE);
+2 −1
Original line number Diff line number Diff line
@@ -967,7 +967,8 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
	}
	intel_connector->edid = edid;

	intel_bios_init_panel(dev_priv, &intel_connector->panel);
	intel_bios_init_panel(dev_priv, &intel_connector->panel,
			      IS_ERR(edid) ? NULL : edid);

	/* Try EDID first */
	intel_panel_add_edid_fixed_modes(intel_connector,
Loading