xref: /openbmc/linux/drivers/gpu/drm/drm_edid_load.c (revision 1c2dd16a)
1 /*
2    drm_edid_load.c: use a built-in EDID data set or load it via the firmware
3 		    interface
4 
5    Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License
9    as published by the Free Software Foundation; either version 2
10    of the License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
20 */
21 
22 #include <linux/module.h>
23 #include <linux/firmware.h>
24 #include <drm/drmP.h>
25 #include <drm/drm_crtc.h>
26 #include <drm/drm_crtc_helper.h>
27 #include <drm/drm_edid.h>
28 
29 static char edid_firmware[PATH_MAX];
30 module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
31 MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
32 	"from built-in data or /lib/firmware instead. ");
33 
34 #define GENERIC_EDIDS 6
35 static const char * const generic_edid_name[GENERIC_EDIDS] = {
36 	"edid/800x600.bin",
37 	"edid/1024x768.bin",
38 	"edid/1280x1024.bin",
39 	"edid/1600x1200.bin",
40 	"edid/1680x1050.bin",
41 	"edid/1920x1080.bin",
42 };
43 
44 static const u8 generic_edid[GENERIC_EDIDS][128] = {
45 	{
46 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
47 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
49 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
50 	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
51 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
52 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
53 	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
54 	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
55 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
56 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
57 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
58 	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
59 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
60 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
61 	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
62 	},
63 	{
64 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
65 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
67 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
68 	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
69 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
70 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
71 	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
72 	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
73 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
74 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
75 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
76 	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
77 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
78 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
79 	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
80 	},
81 	{
82 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
83 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
85 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
86 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
87 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
88 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
89 	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
90 	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
91 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
92 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
93 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
94 	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
95 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
96 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
97 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
98 	},
99 	{
100 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
101 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
103 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
104 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
105 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
106 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
107 	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
108 	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
109 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
110 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
111 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
112 	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
113 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
114 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
115 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
116 	},
117 	{
118 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
119 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
121 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
122 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
123 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
124 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
125 	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
126 	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
127 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
128 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
129 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
130 	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
131 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
132 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
133 	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
134 	},
135 	{
136 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
137 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
139 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
140 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
141 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
142 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
143 	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
144 	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
145 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
146 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
147 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
148 	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
149 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
150 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
151 	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
152 	},
153 };
154 
155 static int edid_size(const u8 *edid, int data_size)
156 {
157 	if (data_size < EDID_LENGTH)
158 		return 0;
159 
160 	return (edid[0x7e] + 1) * EDID_LENGTH;
161 }
162 
163 static void *edid_load(struct drm_connector *connector, const char *name,
164 			const char *connector_name)
165 {
166 	const struct firmware *fw = NULL;
167 	const u8 *fwdata;
168 	u8 *edid;
169 	int fwsize, builtin;
170 	int i, valid_extensions = 0;
171 	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
172 
173 	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
174 	if (builtin >= 0) {
175 		fwdata = generic_edid[builtin];
176 		fwsize = sizeof(generic_edid[builtin]);
177 	} else {
178 		struct platform_device *pdev;
179 		int err;
180 
181 		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
182 		if (IS_ERR(pdev)) {
183 			DRM_ERROR("Failed to register EDID firmware platform device "
184 				  "for connector \"%s\"\n", connector_name);
185 			return ERR_CAST(pdev);
186 		}
187 
188 		err = request_firmware(&fw, name, &pdev->dev);
189 		platform_device_unregister(pdev);
190 		if (err) {
191 			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
192 				  name, err);
193 			return ERR_PTR(err);
194 		}
195 
196 		fwdata = fw->data;
197 		fwsize = fw->size;
198 	}
199 
200 	if (edid_size(fwdata, fwsize) != fwsize) {
201 		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
202 			  "(expected %d, got %d\n", name,
203 			  edid_size(fwdata, fwsize), (int)fwsize);
204 		edid = ERR_PTR(-EINVAL);
205 		goto out;
206 	}
207 
208 	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
209 	if (edid == NULL) {
210 		edid = ERR_PTR(-ENOMEM);
211 		goto out;
212 	}
213 
214 	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
215 				  &connector->edid_corrupt)) {
216 		connector->bad_edid_counter++;
217 		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
218 		    name);
219 		kfree(edid);
220 		edid = ERR_PTR(-EINVAL);
221 		goto out;
222 	}
223 
224 	for (i = 1; i <= edid[0x7e]; i++) {
225 		if (i != valid_extensions + 1)
226 			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
227 			    edid + i * EDID_LENGTH, EDID_LENGTH);
228 		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
229 					 print_bad_edid,
230 					 NULL))
231 			valid_extensions++;
232 	}
233 
234 	if (valid_extensions != edid[0x7e]) {
235 		u8 *new_edid;
236 
237 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
238 		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
239 		    "\"%s\" for connector \"%s\"\n", valid_extensions,
240 		    edid[0x7e], name, connector_name);
241 		edid[0x7e] = valid_extensions;
242 
243 		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
244 				    GFP_KERNEL);
245 		if (new_edid)
246 			edid = new_edid;
247 	}
248 
249 	DRM_INFO("Got %s EDID base block and %d extension%s from "
250 	    "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
251 	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
252 	    name, connector_name);
253 
254 out:
255 	release_firmware(fw);
256 	return edid;
257 }
258 
259 int drm_load_edid_firmware(struct drm_connector *connector)
260 {
261 	const char *connector_name = connector->name;
262 	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
263 	int ret;
264 	struct edid *edid;
265 
266 	if (edid_firmware[0] == '\0')
267 		return 0;
268 
269 	/*
270 	 * If there are multiple edid files specified and separated
271 	 * by commas, search through the list looking for one that
272 	 * matches the connector.
273 	 *
274 	 * If there's one or more that doesn't specify a connector, keep
275 	 * the last one found one as a fallback.
276 	 */
277 	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
278 	edidstr = fwstr;
279 
280 	while ((edidname = strsep(&edidstr, ","))) {
281 		colon = strchr(edidname, ':');
282 		if (colon != NULL) {
283 			if (strncmp(connector_name, edidname, colon - edidname))
284 				continue;
285 			edidname = colon + 1;
286 			break;
287 		}
288 
289 		if (*edidname != '\0') /* corner case: multiple ',' */
290 			fallback = edidname;
291 	}
292 
293 	if (!edidname) {
294 		if (!fallback) {
295 			kfree(fwstr);
296 			return 0;
297 		}
298 		edidname = fallback;
299 	}
300 
301 	last = edidname + strlen(edidname) - 1;
302 	if (*last == '\n')
303 		*last = '\0';
304 
305 	edid = edid_load(connector, edidname, connector_name);
306 	kfree(fwstr);
307 
308 	if (IS_ERR_OR_NULL(edid))
309 		return 0;
310 
311 	drm_mode_connector_update_edid_property(connector, edid);
312 	ret = drm_add_edid_modes(connector, edid);
313 	drm_edid_to_eld(connector, edid);
314 	kfree(edid);
315 
316 	return ret;
317 }
318