]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.1/drm-add-fallback-override-firmware-edid-modes-workaround.patch
move all the pending queues back to their "real" places
[thirdparty/kernel/stable-queue.git] / queue-5.1 / drm-add-fallback-override-firmware-edid-modes-workaround.patch
1 From 48eaeb7664c76139438724d520a1ea4a84a3ed92 Mon Sep 17 00:00:00 2001
2 From: Jani Nikula <jani.nikula@intel.com>
3 Date: Mon, 10 Jun 2019 12:30:54 +0300
4 Subject: drm: add fallback override/firmware EDID modes workaround
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Jani Nikula <jani.nikula@intel.com>
10
11 commit 48eaeb7664c76139438724d520a1ea4a84a3ed92 upstream.
12
13 We've moved the override and firmware EDID (simply "override EDID" from
14 now on) handling to the low level drm_do_get_edid() function in order to
15 transparently use the override throughout the stack. The idea is that
16 you get the override EDID via the ->get_modes() hook.
17
18 Unfortunately, there are scenarios where the DDC probe in drm_get_edid()
19 called via ->get_modes() fails, although the preceding ->detect()
20 succeeds.
21
22 In the case reported by Paul Wise, the ->detect() hook,
23 intel_crt_detect(), relies on hotplug detect, bypassing the DDC. In the
24 case reported by Ilpo Järvinen, there is no ->detect() hook, which is
25 interpreted as connected. The subsequent DDC probe reached via
26 ->get_modes() fails, and we don't even look at the override EDID,
27 resulting in no modes being added.
28
29 Because drm_get_edid() is used via ->detect() all over the place, we
30 can't trivially remove the DDC probe, as it leads to override EDID
31 effectively meaning connector forcing. The goal is that connector
32 forcing and override EDID remain orthogonal.
33
34 Generally, the underlying problem here is the conflation of ->detect()
35 and ->get_modes() via drm_get_edid(). The former should just detect, and
36 the latter should just get the modes, typically via reading the EDID. As
37 long as drm_get_edid() is used in ->detect(), it needs to retain the DDC
38 probe. Or such users need to have a separate DDC probe step first.
39
40 The EDID caching between ->detect() and ->get_modes() done by some
41 drivers is a further complication that prevents us from making
42 drm_do_get_edid() adapt to the two cases.
43
44 Work around the regression by falling back to a separate attempt at
45 getting the override EDID at drm_helper_probe_single_connector_modes()
46 level. With a working DDC and override EDID, it'll never be called; the
47 override EDID will come via ->get_modes(). There will still be a failing
48 DDC probe attempt in the cases that require the fallback.
49
50 v2:
51 - Call drm_connector_update_edid_property (Paul)
52 - Update commit message about EDID caching (Daniel)
53
54 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107583
55 Reported-by: Paul Wise <pabs3@bonedaddy.net>
56 Cc: Paul Wise <pabs3@bonedaddy.net>
57 References: http://mid.mail-archive.com/alpine.DEB.2.20.1905262211270.24390@whs-18.cs.helsinki.fi
58 Reported-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
59 Cc: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
60 Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
61 References: 15f080f08d48 ("drm/edid: respect connector force for drm_get_edid ddc probe")
62 Fixes: 53fd40a90f3c ("drm: handle override and firmware EDID at drm_do_get_edid() level")
63 Cc: <stable@vger.kernel.org> # v4.15+ 56a2b7f2a39a drm/edid: abstract override/firmware EDID retrieval
64 Cc: <stable@vger.kernel.org> # v4.15+
65 Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
66 Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
67 Cc: Harish Chegondi <harish.chegondi@intel.com>
68 Tested-by: Paul Wise <pabs3@bonedaddy.net>
69 Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
70 Signed-off-by: Jani Nikula <jani.nikula@intel.com>
71 Link: https://patchwork.freedesktop.org/patch/msgid/20190610093054.28445-1-jani.nikula@intel.com
72 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
73
74 ---
75 drivers/gpu/drm/drm_edid.c | 30 ++++++++++++++++++++++++++++++
76 drivers/gpu/drm/drm_probe_helper.c | 7 +++++++
77 include/drm/drm_edid.h | 1 +
78 3 files changed, 38 insertions(+)
79
80 --- a/drivers/gpu/drm/drm_edid.c
81 +++ b/drivers/gpu/drm/drm_edid.c
82 @@ -1595,6 +1595,36 @@ static struct edid *drm_get_override_edi
83 }
84
85 /**
86 + * drm_add_override_edid_modes - add modes from override/firmware EDID
87 + * @connector: connector we're probing
88 + *
89 + * Add modes from the override/firmware EDID, if available. Only to be used from
90 + * drm_helper_probe_single_connector_modes() as a fallback for when DDC probe
91 + * failed during drm_get_edid() and caused the override/firmware EDID to be
92 + * skipped.
93 + *
94 + * Return: The number of modes added or 0 if we couldn't find any.
95 + */
96 +int drm_add_override_edid_modes(struct drm_connector *connector)
97 +{
98 + struct edid *override;
99 + int num_modes = 0;
100 +
101 + override = drm_get_override_edid(connector);
102 + if (override) {
103 + drm_connector_update_edid_property(connector, override);
104 + num_modes = drm_add_edid_modes(connector, override);
105 + kfree(override);
106 +
107 + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback override/firmware EDID\n",
108 + connector->base.id, connector->name, num_modes);
109 + }
110 +
111 + return num_modes;
112 +}
113 +EXPORT_SYMBOL(drm_add_override_edid_modes);
114 +
115 +/**
116 * drm_do_get_edid - get EDID data using a custom EDID block read function
117 * @connector: connector we're probing
118 * @get_edid_block: EDID block read function
119 --- a/drivers/gpu/drm/drm_probe_helper.c
120 +++ b/drivers/gpu/drm/drm_probe_helper.c
121 @@ -479,6 +479,13 @@ retry:
122
123 count = (*connector_funcs->get_modes)(connector);
124
125 + /*
126 + * Fallback for when DDC probe failed in drm_get_edid() and thus skipped
127 + * override/firmware EDID.
128 + */
129 + if (count == 0 && connector->status == connector_status_connected)
130 + count = drm_add_override_edid_modes(connector);
131 +
132 if (count == 0 && connector->status == connector_status_connected)
133 count = drm_add_modes_noedid(connector, 1024, 768);
134 count += drm_helper_probe_add_cmdline_mode(connector);
135 --- a/include/drm/drm_edid.h
136 +++ b/include/drm/drm_edid.h
137 @@ -465,6 +465,7 @@ struct edid *drm_get_edid_switcheroo(str
138 struct i2c_adapter *adapter);
139 struct edid *drm_edid_duplicate(const struct edid *edid);
140 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
141 +int drm_add_override_edid_modes(struct drm_connector *connector);
142
143 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
144 enum hdmi_picture_aspect drm_get_cea_aspect_ratio(const u8 video_code);