xref: /openbmc/linux/drivers/gpu/drm/drm_edid_load.c (revision e2f1cf25)
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 *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 = 0;
174 	for (i = 0; i < GENERIC_EDIDS; i++) {
175 		if (strcmp(name, generic_edid_name[i]) == 0) {
176 			fwdata = generic_edid[i];
177 			fwsize = sizeof(generic_edid[i]);
178 			builtin = 1;
179 			break;
180 		}
181 	}
182 	if (!builtin) {
183 		struct platform_device *pdev;
184 		int err;
185 
186 		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
187 		if (IS_ERR(pdev)) {
188 			DRM_ERROR("Failed to register EDID firmware platform device "
189 				  "for connector \"%s\"\n", connector_name);
190 			return ERR_CAST(pdev);
191 		}
192 
193 		err = request_firmware(&fw, name, &pdev->dev);
194 		platform_device_unregister(pdev);
195 		if (err) {
196 			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
197 				  name, err);
198 			return ERR_PTR(err);
199 		}
200 
201 		fwdata = fw->data;
202 		fwsize = fw->size;
203 	}
204 
205 	if (edid_size(fwdata, fwsize) != fwsize) {
206 		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
207 			  "(expected %d, got %d\n", name,
208 			  edid_size(fwdata, fwsize), (int)fwsize);
209 		edid = ERR_PTR(-EINVAL);
210 		goto out;
211 	}
212 
213 	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
214 	if (edid == NULL) {
215 		edid = ERR_PTR(-ENOMEM);
216 		goto out;
217 	}
218 
219 	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
220 				  &connector->edid_corrupt)) {
221 		connector->bad_edid_counter++;
222 		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
223 		    name);
224 		kfree(edid);
225 		edid = ERR_PTR(-EINVAL);
226 		goto out;
227 	}
228 
229 	for (i = 1; i <= edid[0x7e]; i++) {
230 		if (i != valid_extensions + 1)
231 			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
232 			    edid + i * EDID_LENGTH, EDID_LENGTH);
233 		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
234 					 print_bad_edid,
235 					 NULL))
236 			valid_extensions++;
237 	}
238 
239 	if (valid_extensions != edid[0x7e]) {
240 		u8 *new_edid;
241 
242 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
243 		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
244 		    "\"%s\" for connector \"%s\"\n", valid_extensions,
245 		    edid[0x7e], name, connector_name);
246 		edid[0x7e] = valid_extensions;
247 
248 		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
249 				    GFP_KERNEL);
250 		if (new_edid)
251 			edid = new_edid;
252 	}
253 
254 	DRM_INFO("Got %s EDID base block and %d extension%s from "
255 	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
256 	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
257 	    name, connector_name);
258 
259 out:
260 	release_firmware(fw);
261 	return edid;
262 }
263 
264 int drm_load_edid_firmware(struct drm_connector *connector)
265 {
266 	const char *connector_name = connector->name;
267 	char *edidname = edid_firmware, *last, *colon;
268 	int ret;
269 	struct edid *edid;
270 
271 	if (*edidname == '\0')
272 		return 0;
273 
274 	colon = strchr(edidname, ':');
275 	if (colon != NULL) {
276 		if (strncmp(connector_name, edidname, colon - edidname))
277 			return 0;
278 		edidname = colon + 1;
279 		if (*edidname == '\0')
280 			return 0;
281 	}
282 
283 	last = edidname + strlen(edidname) - 1;
284 	if (*last == '\n')
285 		*last = '\0';
286 
287 	edid = edid_load(connector, edidname, connector_name);
288 	if (IS_ERR_OR_NULL(edid))
289 		return 0;
290 
291 	drm_mode_connector_update_edid_property(connector, edid);
292 	ret = drm_add_edid_modes(connector, edid);
293 	drm_edid_to_eld(connector, edid);
294 	kfree(edid);
295 
296 	return ret;
297 }
298