This patch series is for making the GPD Win Max display usable with Linux.
The GPD Win Max is a small laptop, and its eDP panel does not send an EDID over DPCD; the EDID is instead available in the intel opregion, in mailbox #5 [1]
The first two patches are based on Jani's patch series [2] adding support for the opregion, with minimal changes. I've change authorship for the first, but we can revert it.
The third patch is just to fix the orientation of the panel. For some reason it does not work at boot when an external display is plugged, but I doubt this is specific to this hardware.
[1]: https://gitlab.freedesktop.org/drm/intel/-/issues/3454 [2]: https://patchwork.kernel.org/project/intel-gfx/patch/20200828061941.17051-1-...
Anisse Astier (2): drm/i915/opregion: add support for mailbox #5 EDID drm: Add orientation quirk for GPD Win Max
Jani Nikula (1): drm/i915/dp: use opregion mailbox #5 EDID for eDP, if available
.../gpu/drm/drm_panel_orientation_quirks.c | 6 ++ drivers/gpu/drm/i915/display/intel_dp.c | 3 + drivers/gpu/drm/i915/display/intel_opregion.c | 69 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_opregion.h | 8 +++ 4 files changed, 85 insertions(+), 1 deletion(-)
The ACPI OpRegion Mailbox #5 ASLE extension may contain an EDID to be used for the embedded display. Add support for using it via by adding the EDID to the list of available modes on the connector.
Based on original patch by: Jani Nikula jani.nikula@intel.com
Changes: - EDID is copied and validated with drm_edid_is_valid - Mode is now added via drm_add_edid_modes instead of using override mechanism
Cc: Jani Nikula jani.nikula@intel.com Cc: Uma Shankar uma.shankar@intel.com Cc: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Anisse Astier anisse@astier.eu --- drivers/gpu/drm/i915/display/intel_opregion.c | 69 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_opregion.h | 8 +++ 2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index dfd724e506b5..ef8d38f041eb 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -196,6 +196,8 @@ struct opregion_asle_ext { #define ASLE_IUER_WINDOWS_BTN (1 << 1) #define ASLE_IUER_POWER_BTN (1 << 0)
+#define ASLE_PHED_EDID_VALID_MASK 0x3 + /* Software System Control Interrupt (SWSCI) */ #define SWSCI_SCIC_INDICATOR (1 << 0) #define SWSCI_SCIC_MAIN_FUNCTION_SHIFT 1 @@ -909,8 +911,10 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) opregion->asle->ardy = ASLE_ARDY_NOT_READY; }
- if (mboxes & MBOX_ASLE_EXT) + if (mboxes & MBOX_ASLE_EXT) { drm_dbg(&dev_priv->drm, "ASLE extension supported\n"); + opregion->asle_ext = base + OPREGION_ASLE_EXT_OFFSET; + }
if (intel_load_vbt_firmware(dev_priv) == 0) goto out; @@ -1037,6 +1041,68 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv) return ret - 1; }
+/** + * intel_opregion_edid_probe - Add EDID from ACPI OpRegion mailbox #5 + * @intel_connector: eDP connector + * + * This reads the ACPI Opregion mailbox #5 to extract the EDID that is passed + * to it. + * + * Will take a lock on the DRM mode_config to add the EDID; make sure it isn't + * called with lock taken. + * + */ +void intel_opregion_edid_probe(struct intel_connector *intel_connector) +{ + struct drm_connector *connector = &intel_connector->base; + struct drm_i915_private *i915 = to_i915(connector->dev); + struct intel_opregion *opregion = &i915->opregion; + const void *in_edid; + const struct edid *edid; + struct edid *new_edid; + int len, ret, num; + + if (!opregion->asle_ext || connector->override_edid) + return; + + in_edid = opregion->asle_ext->bddc; + + /* Validity corresponds to number of 128-byte blocks */ + len = (opregion->asle_ext->phed & ASLE_PHED_EDID_VALID_MASK) * 128; + if (!len || !memchr_inv(in_edid, 0, len)) + return; + + edid = in_edid; + + if (len < EDID_LENGTH * (1 + edid->extensions)) { + drm_dbg_kms(&i915->drm, "Invalid EDID in ACPI OpRegion (Mailbox #5)\n"); + return; + } + new_edid = drm_edid_duplicate(edid); + if (!new_edid) { + drm_err(&i915->drm, "Cannot duplicate EDID\n"); + return; + } + if (!drm_edid_is_valid(new_edid)) { + kfree(new_edid); + drm_dbg_kms(&i915->drm, "Cannot validate EDID in ACPI OpRegion (Mailbox #5)\n"); + return; + } + + ret = drm_connector_update_edid_property(connector, new_edid); + if (ret) { + kfree(new_edid); + return; + } + + mutex_lock(&connector->dev->mode_config.mutex); + num = drm_add_edid_modes(connector, new_edid); + mutex_unlock(&connector->dev->mode_config.mutex); + + drm_dbg_kms(&i915->drm, "Using OpRegion EDID for [CONNECTOR:%d:%s], added %d mode(s)\n", + connector->base.id, connector->name, num); +} + void intel_opregion_register(struct drm_i915_private *i915) { struct intel_opregion *opregion = &i915->opregion; @@ -1127,6 +1193,7 @@ void intel_opregion_unregister(struct drm_i915_private *i915) opregion->acpi = NULL; opregion->swsci = NULL; opregion->asle = NULL; + opregion->asle_ext = NULL; opregion->vbt = NULL; opregion->lid_state = NULL; } diff --git a/drivers/gpu/drm/i915/display/intel_opregion.h b/drivers/gpu/drm/i915/display/intel_opregion.h index 4aa68ffbd30e..c1ecfcbb6f55 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.h +++ b/drivers/gpu/drm/i915/display/intel_opregion.h @@ -29,12 +29,14 @@ #include <linux/pci.h>
struct drm_i915_private; +struct intel_connector; struct intel_encoder;
struct opregion_header; struct opregion_acpi; struct opregion_swsci; struct opregion_asle; +struct opregion_asle_ext;
struct intel_opregion { struct opregion_header *header; @@ -43,6 +45,7 @@ struct intel_opregion { u32 swsci_gbda_sub_functions; u32 swsci_sbcb_sub_functions; struct opregion_asle *asle; + struct opregion_asle_ext *asle_ext; void *rvda; void *vbt_firmware; const void *vbt; @@ -71,6 +74,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv, pci_power_t state); int intel_opregion_get_panel_type(struct drm_i915_private *dev_priv); +void intel_opregion_edid_probe(struct intel_connector *connector);
#else /* CONFIG_ACPI*/
@@ -117,6 +121,10 @@ static inline int intel_opregion_get_panel_type(struct drm_i915_private *dev) return -ENODEV; }
+void intel_opregion_edid_probe(struct intel_connector *connector) +{ +} + #endif /* CONFIG_ACPI */
#endif
From: Jani Nikula jani.nikula@intel.com
If a panel's EDID is broken, there may be an override EDID set in the ACPI OpRegion mailbox #5. Use it if available.
Fixes the GPD Win Max display.
Cc: Uma Shankar uma.shankar@intel.com Signed-off-by: Jani Nikula jani.nikula@intel.com Signed-off-by: Anisse Astier anisse@astier.eu
[Anisse changes: function name] --- drivers/gpu/drm/i915/display/intel_dp.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 5c9222283044..43fb485c0e02 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5191,6 +5191,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, goto out_vdd_off; }
+ /* Set up override EDID, if any, from ACPI OpRegion */ + intel_opregion_edid_probe(intel_connector); + mutex_lock(&dev->mode_config.mutex); edid = drm_get_edid(connector, &intel_dp->aux.ddc); if (edid) {
Panel is 800x1280, but mounted on a laptop form factor, sideways.
Signed-off-by: Anisse Astier anisse@astier.eu --- drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index f6bdec7fa925..3c3f4ed89173 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -148,6 +148,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC"), }, .driver_data = (void *)&lcd720x1280_rightside_up, + }, { /* GPD Win Max */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1619-01"), + }, + .driver_data = (void *)&lcd800x1280_rightside_up, }, { /* * GPD Pocket, note that the the DMI data is less generic then * it seems, devices with a board-vendor of "AMI Corporation"
Hi,
On 5/24/21 6:47 PM, Anisse Astier wrote:
Panel is 800x1280, but mounted on a laptop form factor, sideways.
Signed-off-by: Anisse Astier anisse@astier.eu
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede hdegoede@redhat.com
Regards,
Hans
drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/drm_panel_orientation_quirks.c b/drivers/gpu/drm/drm_panel_orientation_quirks.c index f6bdec7fa925..3c3f4ed89173 100644 --- a/drivers/gpu/drm/drm_panel_orientation_quirks.c +++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c @@ -148,6 +148,12 @@ static const struct dmi_system_id orientation_data[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC"), }, .driver_data = (void *)&lcd720x1280_rightside_up,
- }, { /* GPD Win Max */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1619-01"),
},
}, { /*.driver_data = (void *)&lcd800x1280_rightside_up,
- GPD Pocket, note that the the DMI data is less generic then
- it seems, devices with a board-vendor of "AMI Corporation"
dri-devel@lists.freedesktop.org