drm/i915: Do panel VBT init early if the VBT declares an explicit panel type
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 25 Nov 2022 17:31:49 +0000 (19:31 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 9 Dec 2022 17:02:49 +0000 (19:02 +0200)
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 <animesh.manna@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20221125173156.31689-3-ville.syrjala@linux.intel.com
drivers/gpu/drm/i915/display/icl_dsi.c
drivers/gpu/drm/i915/display/intel_bios.c
drivers/gpu/drm/i915/display/intel_bios.h
drivers/gpu/drm/i915/display/intel_display_types.h
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_lvds.c
drivers/gpu/drm/i915/display/intel_panel.c
drivers/gpu/drm/i915/display/intel_sdvo.c
drivers/gpu/drm/i915/display/vlv_dsi.c

index d16b30a2dded3349d1a83ee0a46bb39d8fb5a778..ae14c794c4bc09f8eeb63edb3c478f0bf9781271 100644 (file)
@@ -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);
index 572a4e3769f3886d0d37b6fc70e0af56b25e68db..55544d48431888c9b055346dfcab7cd5c36cd2d8 100644 (file)
@@ -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;
 
@@ -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;
@@ -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 {
@@ -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] = {
@@ -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);
@@ -3183,14 +3184,26 @@ out:
        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);
@@ -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
index e375405a7828413360e4f9b6dded44b1dd92b841..ff1fdd2e0c1c5cf367336ce036f6653dd5c2c77f 100644 (file)
@@ -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);
index ff3ef37d099e7db8fa6afa11100b55d8614e714c..cc64e787e4018eee58a839b22e5c6547bb5246dc 100644 (file)
@@ -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 */
 
index 0820e58cb6b8cdaa7ce0ed445ed753af57b9ffd5..06844f45df4150c73c891ed93728069aa9a78a80 100644 (file)
@@ -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. */
@@ -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);
 
index 7bf1bdfd03ec0cb867cb7f487f4f1ac318aea75b..aecec992cd0d2d332bfed1df489b1c831f5fab08 100644 (file)
@@ -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);
index b49228eb79e75601271bb043ae662bed7594d556..609fcdbd7d58dc30c07e23bfe00223bb0b1afa98 100644 (file)
@@ -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);
 }
 
index 329b9d9af66798ede07f92560cc3aba15f68e420..21805c15d5eb8ab93435d5e935e0db50c1879c0a 100644 (file)
@@ -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
index 84481030883ac00e3114347a7f1066ef4a9b1c5c..662bdb656aa304d95cde08b1dc19beb356e628b7 100644 (file)
@@ -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);