xref: /openbmc/linux/drivers/gpu/drm/drm_edid_load.c (revision 37be287c)
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 5
35 static const char *generic_edid_name[GENERIC_EDIDS] = {
36 	"edid/1024x768.bin",
37 	"edid/1280x1024.bin",
38 	"edid/1600x1200.bin",
39 	"edid/1680x1050.bin",
40 	"edid/1920x1080.bin",
41 };
42 
43 static const u8 generic_edid[GENERIC_EDIDS][128] = {
44 	{
45 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
46 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
48 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
49 	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
50 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
51 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
52 	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
53 	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
54 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
55 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
56 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
57 	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
58 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
59 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
60 	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
61 	},
62 	{
63 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
64 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
66 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
67 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
68 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
69 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
70 	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
71 	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
72 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
73 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
74 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
75 	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
76 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
77 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
78 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
79 	},
80 	{
81 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
82 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
84 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
85 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
86 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
87 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
88 	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
89 	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
90 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
91 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
92 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
93 	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
94 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
95 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
96 	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
97 	},
98 	{
99 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
100 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
102 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
103 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
104 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
105 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
106 	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
107 	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
108 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
109 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
110 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
111 	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
112 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
113 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
114 	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
115 	},
116 	{
117 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
118 	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
120 	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
121 	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
122 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
123 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
124 	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
125 	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
126 	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
127 	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
128 	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
129 	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
130 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
131 	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
132 	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
133 	},
134 };
135 
136 static int edid_size(const u8 *edid, int data_size)
137 {
138 	if (data_size < EDID_LENGTH)
139 		return 0;
140 
141 	return (edid[0x7e] + 1) * EDID_LENGTH;
142 }
143 
144 static void *edid_load(struct drm_connector *connector, const char *name,
145 			const char *connector_name)
146 {
147 	const struct firmware *fw = NULL;
148 	const u8 *fwdata;
149 	u8 *edid;
150 	int fwsize, builtin;
151 	int i, valid_extensions = 0;
152 	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
153 
154 	builtin = 0;
155 	for (i = 0; i < GENERIC_EDIDS; i++) {
156 		if (strcmp(name, generic_edid_name[i]) == 0) {
157 			fwdata = generic_edid[i];
158 			fwsize = sizeof(generic_edid[i]);
159 			builtin = 1;
160 			break;
161 		}
162 	}
163 	if (!builtin) {
164 		struct platform_device *pdev;
165 		int err;
166 
167 		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
168 		if (IS_ERR(pdev)) {
169 			DRM_ERROR("Failed to register EDID firmware platform device "
170 				  "for connector \"%s\"\n", connector_name);
171 			return ERR_CAST(pdev);
172 		}
173 
174 		err = request_firmware(&fw, name, &pdev->dev);
175 		platform_device_unregister(pdev);
176 		if (err) {
177 			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
178 				  name, err);
179 			return ERR_PTR(err);
180 		}
181 
182 		fwdata = fw->data;
183 		fwsize = fw->size;
184 	}
185 
186 	if (edid_size(fwdata, fwsize) != fwsize) {
187 		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
188 			  "(expected %d, got %d\n", name,
189 			  edid_size(fwdata, fwsize), (int)fwsize);
190 		edid = ERR_PTR(-EINVAL);
191 		goto out;
192 	}
193 
194 	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
195 	if (edid == NULL) {
196 		edid = ERR_PTR(-ENOMEM);
197 		goto out;
198 	}
199 
200 	if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
201 		connector->bad_edid_counter++;
202 		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
203 		    name);
204 		kfree(edid);
205 		edid = ERR_PTR(-EINVAL);
206 		goto out;
207 	}
208 
209 	for (i = 1; i <= edid[0x7e]; i++) {
210 		if (i != valid_extensions + 1)
211 			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
212 			    edid + i * EDID_LENGTH, EDID_LENGTH);
213 		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
214 			valid_extensions++;
215 	}
216 
217 	if (valid_extensions != edid[0x7e]) {
218 		u8 *new_edid;
219 
220 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
221 		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
222 		    "\"%s\" for connector \"%s\"\n", valid_extensions,
223 		    edid[0x7e], name, connector_name);
224 		edid[0x7e] = valid_extensions;
225 
226 		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
227 				    GFP_KERNEL);
228 		if (new_edid)
229 			edid = new_edid;
230 	}
231 
232 	DRM_INFO("Got %s EDID base block and %d extension%s from "
233 	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
234 	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
235 	    name, connector_name);
236 
237 out:
238 	if (fw)
239 		release_firmware(fw);
240 	return edid;
241 }
242 
243 int drm_load_edid_firmware(struct drm_connector *connector)
244 {
245 	const char *connector_name = drm_get_connector_name(connector);
246 	char *edidname = edid_firmware, *last, *colon;
247 	int ret;
248 	struct edid *edid;
249 
250 	if (*edidname == '\0')
251 		return 0;
252 
253 	colon = strchr(edidname, ':');
254 	if (colon != NULL) {
255 		if (strncmp(connector_name, edidname, colon - edidname))
256 			return 0;
257 		edidname = colon + 1;
258 		if (*edidname == '\0')
259 			return 0;
260 	}
261 
262 	last = edidname + strlen(edidname) - 1;
263 	if (*last == '\n')
264 		*last = '\0';
265 
266 	edid = edid_load(connector, edidname, connector_name);
267 	if (IS_ERR_OR_NULL(edid))
268 		return 0;
269 
270 	drm_mode_connector_update_edid_property(connector, edid);
271 	ret = drm_add_edid_modes(connector, edid);
272 	kfree(edid);
273 
274 	return ret;
275 }
276