xref: /openbmc/linux/drivers/gpu/drm/drm_edid_load.c (revision 09bae3b6)
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 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
35 int __drm_set_edid_firmware_path(const char *path)
36 {
37 	scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
38 
39 	return 0;
40 }
41 EXPORT_SYMBOL(__drm_set_edid_firmware_path);
42 
43 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
44 int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
45 {
46 	return scnprintf(buf, bufsize, "%s", edid_firmware);
47 }
48 EXPORT_SYMBOL(__drm_get_edid_firmware_path);
49 
50 #define GENERIC_EDIDS 6
51 static const char * const generic_edid_name[GENERIC_EDIDS] = {
52 	"edid/800x600.bin",
53 	"edid/1024x768.bin",
54 	"edid/1280x1024.bin",
55 	"edid/1600x1200.bin",
56 	"edid/1680x1050.bin",
57 	"edid/1920x1080.bin",
58 };
59 
60 static const u8 generic_edid[GENERIC_EDIDS][128] = {
61 	{
62 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
63 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
65 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
66 	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
67 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
68 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
69 	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
70 	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
71 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
72 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
73 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
74 	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
75 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
76 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
77 	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
78 	},
79 	{
80 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
81 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
83 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
84 	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
85 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
86 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
87 	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
88 	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
89 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
90 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
91 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
92 	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
93 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
94 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
95 	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
96 	},
97 	{
98 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
99 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
101 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
102 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
103 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
104 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
105 	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
106 	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
107 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
108 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
109 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
110 	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
111 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
112 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
113 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
114 	},
115 	{
116 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
117 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
119 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
120 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
121 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
122 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
123 	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
124 	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
125 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
126 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
127 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
128 	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
129 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
130 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
131 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
132 	},
133 	{
134 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
135 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
137 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
138 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
139 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
140 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
141 	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
142 	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
143 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
144 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
145 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
146 	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
147 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
148 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
149 	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
150 	},
151 	{
152 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
153 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
155 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
156 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
157 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
158 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
159 	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
160 	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
161 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
162 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
163 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
164 	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
165 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
166 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
167 	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
168 	},
169 };
170 
171 static int edid_size(const u8 *edid, int data_size)
172 {
173 	if (data_size < EDID_LENGTH)
174 		return 0;
175 
176 	return (edid[0x7e] + 1) * EDID_LENGTH;
177 }
178 
179 static void *edid_load(struct drm_connector *connector, const char *name,
180 			const char *connector_name)
181 {
182 	const struct firmware *fw = NULL;
183 	const u8 *fwdata;
184 	u8 *edid;
185 	int fwsize, builtin;
186 	int i, valid_extensions = 0;
187 	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
188 
189 	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
190 	if (builtin >= 0) {
191 		fwdata = generic_edid[builtin];
192 		fwsize = sizeof(generic_edid[builtin]);
193 	} else {
194 		struct platform_device *pdev;
195 		int err;
196 
197 		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
198 		if (IS_ERR(pdev)) {
199 			DRM_ERROR("Failed to register EDID firmware platform device "
200 				  "for connector \"%s\"\n", connector_name);
201 			return ERR_CAST(pdev);
202 		}
203 
204 		err = request_firmware(&fw, name, &pdev->dev);
205 		platform_device_unregister(pdev);
206 		if (err) {
207 			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
208 				  name, err);
209 			return ERR_PTR(err);
210 		}
211 
212 		fwdata = fw->data;
213 		fwsize = fw->size;
214 	}
215 
216 	if (edid_size(fwdata, fwsize) != fwsize) {
217 		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
218 			  "(expected %d, got %d\n", name,
219 			  edid_size(fwdata, fwsize), (int)fwsize);
220 		edid = ERR_PTR(-EINVAL);
221 		goto out;
222 	}
223 
224 	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
225 	if (edid == NULL) {
226 		edid = ERR_PTR(-ENOMEM);
227 		goto out;
228 	}
229 
230 	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
231 				  &connector->edid_corrupt)) {
232 		connector->bad_edid_counter++;
233 		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
234 		    name);
235 		kfree(edid);
236 		edid = ERR_PTR(-EINVAL);
237 		goto out;
238 	}
239 
240 	for (i = 1; i <= edid[0x7e]; i++) {
241 		if (i != valid_extensions + 1)
242 			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
243 			    edid + i * EDID_LENGTH, EDID_LENGTH);
244 		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
245 					 print_bad_edid,
246 					 NULL))
247 			valid_extensions++;
248 	}
249 
250 	if (valid_extensions != edid[0x7e]) {
251 		u8 *new_edid;
252 
253 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
254 		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
255 		    "\"%s\" for connector \"%s\"\n", valid_extensions,
256 		    edid[0x7e], name, connector_name);
257 		edid[0x7e] = valid_extensions;
258 
259 		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
260 				    GFP_KERNEL);
261 		if (new_edid)
262 			edid = new_edid;
263 	}
264 
265 	DRM_INFO("Got %s EDID base block and %d extension%s from "
266 	    "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
267 	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
268 	    name, connector_name);
269 
270 out:
271 	release_firmware(fw);
272 	return edid;
273 }
274 
275 struct edid *drm_load_edid_firmware(struct drm_connector *connector)
276 {
277 	const char *connector_name = connector->name;
278 	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
279 	struct edid *edid;
280 
281 	if (edid_firmware[0] == '\0')
282 		return ERR_PTR(-ENOENT);
283 
284 	/*
285 	 * If there are multiple edid files specified and separated
286 	 * by commas, search through the list looking for one that
287 	 * matches the connector.
288 	 *
289 	 * If there's one or more that doesn't specify a connector, keep
290 	 * the last one found one as a fallback.
291 	 */
292 	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
293 	edidstr = fwstr;
294 
295 	while ((edidname = strsep(&edidstr, ","))) {
296 		colon = strchr(edidname, ':');
297 		if (colon != NULL) {
298 			if (strncmp(connector_name, edidname, colon - edidname))
299 				continue;
300 			edidname = colon + 1;
301 			break;
302 		}
303 
304 		if (*edidname != '\0') /* corner case: multiple ',' */
305 			fallback = edidname;
306 	}
307 
308 	if (!edidname) {
309 		if (!fallback) {
310 			kfree(fwstr);
311 			return ERR_PTR(-ENOENT);
312 		}
313 		edidname = fallback;
314 	}
315 
316 	last = edidname + strlen(edidname) - 1;
317 	if (*last == '\n')
318 		*last = '\0';
319 
320 	edid = edid_load(connector, edidname, connector_name);
321 	kfree(fwstr);
322 
323 	return edid;
324 }
325