From 549402d95931caca81c3e8d7f8485ac33b8dd092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 6 Apr 2016 16:48:32 +0300 Subject: [PATCH] drm/i915: Try to get EDID via ACPI _DDC if i2c fails for LVDS/eDP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI has the _DDC method which can be used to get an EDID for a panel if the panel doesn't actually have an EDID itself. Try to use the ACPI way if the i2c EDID read fails. Somewhat stolen from nouveau, but for extra paranoia I went and used drm_do_get_edid() to make sure we validate the extension block count and whatnot. Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_acpi.c | 46 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 2 ++ drivers/gpu/drm/i915/intel_lvds.c | 2 ++ 4 files changed, 52 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 313bc3576d87..933774383b0d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3440,9 +3440,11 @@ intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) #ifdef CONFIG_ACPI extern void intel_register_dsm_handler(void); extern void intel_unregister_dsm_handler(void); +extern void *intel_acpi_get_edid(struct drm_connector *connector); #else static inline void intel_register_dsm_handler(void) { return; } static inline void intel_unregister_dsm_handler(void) { return; } +static inline void *intel_acpi_get_edid(struct drm_connector *connector) { return NULL }; #endif /* CONFIG_ACPI */ /* modesetting */ diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index eb638a1e69d2..bf531b4618c9 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -5,7 +5,9 @@ */ #include #include +#include #include +#include #include "i915_drv.h" #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ @@ -162,3 +164,47 @@ void intel_register_dsm_handler(void) void intel_unregister_dsm_handler(void) { } + +static int acpi_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct acpi_device *acpidev = data; + void *edid; + int ret; + + ret = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, &edid); + if (ret < 0) + return ret; + + if (ret < block * EDID_LENGTH + len) + return -ENOMEM; + + memcpy(buf, edid, len); + + return 0; +} + +void *intel_acpi_get_edid(struct drm_connector *connector) +{ + struct acpi_device *acpidev; + acpi_handle handle; + int ret; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + break; + default: + MISSING_CASE(connector->connector_type); + return NULL; + } + + handle = ACPI_HANDLE(&connector->dev->pdev->dev); + if (!handle) + return NULL; + + ret = acpi_bus_get_device(handle, &acpidev); + if (ret) + return NULL; + + return drm_do_get_edid(connector, acpi_get_edid_block, acpidev); +} diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index da0c3d29fda8..2b704a46e945 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5756,6 +5756,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, mutex_lock(&dev->mode_config.mutex); edid = drm_get_edid(connector, &intel_dp->aux.ddc); + if (!edid) + edid = intel_acpi_get_edid(connector); if (edid) { if (drm_add_edid_modes(connector, edid)) { drm_mode_connector_update_edid_property(connector, diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 66e832beeb37..7ba9701234d0 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1035,6 +1035,8 @@ void intel_lvds_init(struct drm_device *dev) else edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin)); + if (!edid) + edid = intel_acpi_get_edid(connector); if (edid) { if (drm_add_edid_modes(connector, edid)) { drm_mode_connector_update_edid_property(connector, -- 2.7.4