Skip to content

Commit

Permalink
drm/i915: Do panel VBT init early if the VBT declares an explicit pan…
Browse files Browse the repository at this point in the history
…el type

Lots of ADL machines out there with bogus VBTs that declare
two eDP child devices. In order for those to work we need to
figure out which power sequencer to use before we try the EDID
read. So let's do the panel VBT init early if we can, falling
back to the post-EDID init otherwise.

The post-EDID init panel_type=0xff approach of assuming the
power sequencer should already be enabled doesn't really work
with multiple eDP panels, and currently we just end up using
the same power sequencer for both eDP ports, which at least
confuses the wakeref tracking, and potentially also causes us
to toggle the VDD for the panel when we should not.

Cc: Animesh Manna <[email protected]>
Reviewed-by: Jani Nikula <[email protected]>
Signed-off-by: Ville Syrjälä <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
vsyrjala committed Dec 9, 2022
1 parent f70f815 commit 3f9ffce
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 26 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/display/icl_dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2043,7 +2043,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, NULL, NULL);
intel_bios_init_panel_late(dev_priv, &intel_connector->panel, NULL, NULL);

mutex_lock(&dev_priv->drm.mode_config.mutex);
intel_panel_add_vbt_lfp_fixed_mode(intel_connector);
Expand Down
56 changes: 42 additions & 14 deletions drivers/gpu/drm/i915/display/intel_bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,14 +620,14 @@ static void dump_pnp_id(struct drm_i915_private *i915,

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

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

Expand All @@ -652,7 +652,7 @@ static int vbt_get_panel_type(struct drm_i915_private *i915,

static int pnpid_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
const struct edid *edid, bool use_fallback)
{
const struct bdb_lvds_lfp_data *data;
const struct bdb_lvds_lfp_data_ptrs *ptrs;
Expand Down Expand Up @@ -701,9 +701,9 @@ static int pnpid_get_panel_type(struct drm_i915_private *i915,

static int fallback_get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
const struct edid *edid, bool use_fallback)
{
return 0;
return use_fallback ? 0 : -1;
}

enum panel_type {
Expand All @@ -715,13 +715,13 @@ enum panel_type {

static int get_panel_type(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
const struct edid *edid, bool use_fallback)
{
struct {
const char *name;
int (*get_panel_type)(struct drm_i915_private *i915,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid);
const struct edid *edid, bool use_fallback);
int panel_type;
} panel_types[] = {
[PANEL_TYPE_OPREGION] = {
Expand All @@ -744,7 +744,8 @@ 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, devdata, edid);
panel_types[i].panel_type = panel_types[i].get_panel_type(i915, devdata,
edid, use_fallback);

drm_WARN_ON(&i915->drm, panel_types[i].panel_type > 0xf &&
panel_types[i].panel_type != 0xff);
Expand Down Expand Up @@ -3183,14 +3184,26 @@ void intel_bios_init(struct drm_i915_private *i915)
kfree(oprom_vbt);
}

void intel_bios_init_panel(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
static void intel_bios_init_panel(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid,
bool use_fallback)
{
init_vbt_panel_defaults(panel);
/* already have it? */
if (panel->vbt.panel_type >= 0) {
drm_WARN_ON(&i915->drm, !use_fallback);
return;
}

panel->vbt.panel_type = get_panel_type(i915, devdata, edid);
panel->vbt.panel_type = get_panel_type(i915, devdata,
edid, use_fallback);
if (panel->vbt.panel_type < 0) {
drm_WARN_ON(&i915->drm, use_fallback);
return;
}

init_vbt_panel_defaults(panel);

parse_panel_options(i915, panel);
parse_generic_dtd(i915, panel);
Expand All @@ -3205,6 +3218,21 @@ void intel_bios_init_panel(struct drm_i915_private *i915,
parse_mipi_sequence(i915, panel);
}

void intel_bios_init_panel_early(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata)
{
intel_bios_init_panel(i915, panel, devdata, NULL, false);
}

void intel_bios_init_panel_late(struct drm_i915_private *i915,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid)
{
intel_bios_init_panel(i915, panel, devdata, edid, true);
}

/**
* intel_bios_driver_remove - Free any resources allocated by intel_bios_init()
* @i915: i915 device instance
Expand Down
11 changes: 7 additions & 4 deletions drivers/gpu/drm/i915/display/intel_bios.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,13 @@ struct mipi_pps_data {
} __packed;

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,
const struct intel_bios_encoder_data *devdata,
const struct edid *edid);
void intel_bios_init_panel_early(struct drm_i915_private *dev_priv,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata);
void intel_bios_init_panel_late(struct drm_i915_private *dev_priv,
struct intel_panel *panel,
const struct intel_bios_encoder_data *devdata,
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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/display/intel_display_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ struct intel_vbt_panel_data {
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */

/* Feature bits */
unsigned int panel_type:4;
int panel_type;
unsigned int lvds_dither:1;
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */

Expand Down
7 changes: 5 additions & 2 deletions drivers/gpu/drm/i915/display/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -5221,6 +5221,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
return false;
}

intel_bios_init_panel_early(dev_priv, &intel_connector->panel,
encoder->devdata);

intel_pps_init(intel_dp);

/* Cache DPCD and EDID for edp. */
Expand Down Expand Up @@ -5256,8 +5259,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,
encoder->devdata, IS_ERR(edid) ? NULL : edid);
intel_bios_init_panel_late(dev_priv, &intel_connector->panel,
encoder->devdata, IS_ERR(edid) ? NULL : edid);

intel_panel_add_edid_fixed_modes(intel_connector, true);

Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/display/intel_lvds.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,8 +964,8 @@ void intel_lvds_init(struct drm_i915_private *dev_priv)
}
intel_connector->edid = edid;

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

/* Try EDID first */
intel_panel_add_edid_fixed_modes(intel_connector, true);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/display/intel_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ void intel_panel_init_alloc(struct intel_connector *connector)
{
struct intel_panel *panel = &connector->panel;

connector->panel.vbt.panel_type = -1;
INIT_LIST_HEAD(&panel->fixed_modes);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/display/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -2886,7 +2886,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, u16 type)
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;

intel_bios_init_panel(i915, &intel_connector->panel, NULL, NULL);
intel_bios_init_panel_late(i915, &intel_connector->panel, NULL, NULL);

/*
* Fetch modes from VBT. For SDVO prefer the VBT mode since some
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/display/vlv_dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1916,7 +1916,7 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv)

intel_dsi->panel_power_off_time = ktime_get_boottime();

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

if (intel_connector->panel.vbt.dsi.config->dual_link)
intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C);
Expand Down

0 comments on commit 3f9ffce

Please sign in to comment.