aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2012-06-14 15:28:33 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-06-16 09:39:02 -0400
commitd6f24d0fa6cdf3431a2fe3330a74bc6c5871f496 (patch)
tree51543b813773c65f397774dbb496e5d1363d7c92 /drivers/gpu
parent6b4e0a93ff6e45714c72bdce193f719ed94810e3 (diff)
drm/i915: cache the EDID for eDP panels
They aren't going anywhere, and probing on DDC can cause the panel to blank briefly, so read them up front and cache them for later queries. v2: fix potential NULL derefs in intel_dp_get_edid_modes and intel_dp_get_edid (Jani) copy full EDID length, including extension blocks (Takashi) free EDID on teardown (Takashi) v3: malloc a new EDID buffer that's big enough for the memcpy (Chris) v4: change handling of NULL EDIDs, just preserve the NULL behavior across detects and mode list fetches rather than trying to re-fetch the EDID (Chris) v5: be glad that Chris is around to remind me to hit C-x C-s before committing. References: https://bugs.freedesktop.org/show_bug.cgi?id=46856 Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index a4b3887575a1..c0449324143c 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -32,6 +32,7 @@
32#include "drm.h" 32#include "drm.h"
33#include "drm_crtc.h" 33#include "drm_crtc.h"
34#include "drm_crtc_helper.h" 34#include "drm_crtc_helper.h"
35#include "drm_edid.h"
35#include "intel_drv.h" 36#include "intel_drv.h"
36#include "i915_drm.h" 37#include "i915_drm.h"
37#include "i915_drv.h" 38#include "i915_drv.h"
@@ -67,6 +68,8 @@ struct intel_dp {
67 struct drm_display_mode *panel_fixed_mode; /* for eDP */ 68 struct drm_display_mode *panel_fixed_mode; /* for eDP */
68 struct delayed_work panel_vdd_work; 69 struct delayed_work panel_vdd_work;
69 bool want_panel_vdd; 70 bool want_panel_vdd;
71 struct edid *edid; /* cached EDID for eDP */
72 int edid_mode_count;
70}; 73};
71 74
72/** 75/**
@@ -2125,10 +2128,22 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
2125{ 2128{
2126 struct intel_dp *intel_dp = intel_attached_dp(connector); 2129 struct intel_dp *intel_dp = intel_attached_dp(connector);
2127 struct edid *edid; 2130 struct edid *edid;
2131 int size;
2132
2133 if (is_edp(intel_dp)) {
2134 if (!intel_dp->edid)
2135 return NULL;
2136
2137 size = (intel_dp->edid->extensions + 1) * EDID_LENGTH;
2138 edid = kmalloc(size, GFP_KERNEL);
2139 if (!edid)
2140 return NULL;
2141
2142 memcpy(edid, intel_dp->edid, size);
2143 return edid;
2144 }
2128 2145
2129 ironlake_edp_panel_vdd_on(intel_dp);
2130 edid = drm_get_edid(connector, adapter); 2146 edid = drm_get_edid(connector, adapter);
2131 ironlake_edp_panel_vdd_off(intel_dp, false);
2132 return edid; 2147 return edid;
2133} 2148}
2134 2149
@@ -2138,9 +2153,17 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *ada
2138 struct intel_dp *intel_dp = intel_attached_dp(connector); 2153 struct intel_dp *intel_dp = intel_attached_dp(connector);
2139 int ret; 2154 int ret;
2140 2155
2141 ironlake_edp_panel_vdd_on(intel_dp); 2156 if (is_edp(intel_dp)) {
2157 drm_mode_connector_update_edid_property(connector,
2158 intel_dp->edid);
2159 ret = drm_add_edid_modes(connector, intel_dp->edid);
2160 drm_edid_to_eld(connector,
2161 intel_dp->edid);
2162 connector->display_info.raw_edid = NULL;
2163 return intel_dp->edid_mode_count;
2164 }
2165
2142 ret = intel_ddc_get_modes(connector, adapter); 2166 ret = intel_ddc_get_modes(connector, adapter);
2143 ironlake_edp_panel_vdd_off(intel_dp, false);
2144 return ret; 2167 return ret;
2145} 2168}
2146 2169
@@ -2330,6 +2353,7 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
2330 i2c_del_adapter(&intel_dp->adapter); 2353 i2c_del_adapter(&intel_dp->adapter);
2331 drm_encoder_cleanup(encoder); 2354 drm_encoder_cleanup(encoder);
2332 if (is_edp(intel_dp)) { 2355 if (is_edp(intel_dp)) {
2356 kfree(intel_dp->edid);
2333 cancel_delayed_work_sync(&intel_dp->panel_vdd_work); 2357 cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
2334 ironlake_panel_vdd_off_sync(intel_dp); 2358 ironlake_panel_vdd_off_sync(intel_dp);
2335 } 2359 }
@@ -2513,11 +2537,14 @@ intel_dp_init(struct drm_device *dev, int output_reg)
2513 break; 2537 break;
2514 } 2538 }
2515 2539
2540 intel_dp_i2c_init(intel_dp, intel_connector, name);
2541
2516 /* Cache some DPCD data in the eDP case */ 2542 /* Cache some DPCD data in the eDP case */
2517 if (is_edp(intel_dp)) { 2543 if (is_edp(intel_dp)) {
2518 bool ret; 2544 bool ret;
2519 struct edp_power_seq cur, vbt; 2545 struct edp_power_seq cur, vbt;
2520 u32 pp_on, pp_off, pp_div; 2546 u32 pp_on, pp_off, pp_div;
2547 struct edid *edid;
2521 2548
2522 pp_on = I915_READ(PCH_PP_ON_DELAYS); 2549 pp_on = I915_READ(PCH_PP_ON_DELAYS);
2523 pp_off = I915_READ(PCH_PP_OFF_DELAYS); 2550 pp_off = I915_READ(PCH_PP_OFF_DELAYS);
@@ -2585,9 +2612,19 @@ intel_dp_init(struct drm_device *dev, int output_reg)
2585 intel_dp_destroy(&intel_connector->base); 2612 intel_dp_destroy(&intel_connector->base);
2586 return; 2613 return;
2587 } 2614 }
2588 }
2589 2615
2590 intel_dp_i2c_init(intel_dp, intel_connector, name); 2616 ironlake_edp_panel_vdd_on(intel_dp);
2617 edid = drm_get_edid(connector, &intel_dp->adapter);
2618 if (edid) {
2619 drm_mode_connector_update_edid_property(connector,
2620 edid);
2621 intel_dp->edid_mode_count =
2622 drm_add_edid_modes(connector, edid);
2623 drm_edid_to_eld(connector, edid);
2624 intel_dp->edid = edid;
2625 }
2626 ironlake_edp_panel_vdd_off(intel_dp, false);
2627 }
2591 2628
2592 intel_encoder->hot_plug = intel_dp_hot_plug; 2629 intel_encoder->hot_plug = intel_dp_hot_plug;
2593 2630