http://bugs.freedesktop.org/show_bug.cgi?id=21042 diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 7b31f55..3586d81 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -30,6 +30,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "drm_edid.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -1377,14 +1378,92 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect return connector_status_disconnected; } +#define MAX_EDID_EXT_NUM 4 +/** + * This function will fetch EDID by switch ddc bus, instead of drm_get_edid + * function. + */ +static struct edid *intel_sdvo_hdmi_get_edid(struct intel_output *intel_output) +{ + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + struct edid *edid; + int ret = 0; + + edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1), + GFP_KERNEL); + + if (edid == NULL) { + DRM_DEBUG("Failed to allocated EDID for SDVO HDMI\n"); + goto end; + } + + /* Read first EDID block */ + ret = drm_do_probe_ddc_edid(&intel_output->ddc_bus->adapter, + (unsigned char *)edid, EDID_LENGTH); + if (ret != 0) { + DRM_DEBUG("Failed to read basic EDID for SDVO HDMI\n"); + goto clean_up; + } + + /* There are EDID extensions to be read */ + if (edid->extensions != 0) { + int edid_ext_num = edid->extensions; + + if (edid_ext_num > MAX_EDID_EXT_NUM) { + DRM_DEBUG("The number of extension(%d) is " + "over max (%d), actually read number (%d)\n", + edid_ext_num, MAX_EDID_EXT_NUM, + MAX_EDID_EXT_NUM); + /* Reset EDID extension number to be read */ + edid_ext_num = MAX_EDID_EXT_NUM; + } + /* set the bus switch and get the modes */ + intel_sdvo_set_control_bus_switch(intel_output, + sdvo_priv->ddc_bus); + /* Read EDID including extensions too */ + ret = drm_do_probe_ddc_edid(&intel_output->ddc_bus->adapter, + (unsigned char *)edid, + EDID_LENGTH * (edid_ext_num + 1)); + if (ret != 0) { + DRM_DEBUG("Failed to read EDID EXT for SDVO HDMI\n"); + goto clean_up; + } + } + goto end; + +clean_up: + kfree(edid); + edid = NULL; +end: + return edid; +} + +static void intel_sdvo_hdmi_ddc_get_modes(struct intel_output *intel_output) +{ + struct edid *edid; + + edid = intel_sdvo_hdmi_get_edid(intel_output); + if (edid != NULL) { + drm_mode_connector_update_edid_property(&intel_output->base, + edid); + drm_add_edid_modes(&intel_output->base, edid); + kfree(edid); + } +} + static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; /* set the bus switch and get the modes */ - intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); - intel_ddc_get_modes(intel_output); + intel_sdvo_set_control_bus_switch(intel_output, + sdvo_priv->ddc_bus); + if (sdvo_priv->is_hdmi == true) + intel_sdvo_hdmi_ddc_get_modes(intel_output); + else + intel_ddc_get_modes(intel_output); + #if 0 struct drm_device *dev = encoder->dev;