xref: /openbmc/linux/drivers/gpu/drm/drm_edid_load.c (revision f35e839a)
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 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 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 u8 *edid_load(struct drm_connector *connector, char *name,
137 			char *connector_name)
138 {
139 	const struct firmware *fw;
140 	struct platform_device *pdev;
141 	u8 *fwdata = NULL, *edid, *new_edid;
142 	int fwsize, expected;
143 	int builtin = 0, err = 0;
144 	int i, valid_extensions = 0;
145 	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
146 
147 	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
148 	if (IS_ERR(pdev)) {
149 		DRM_ERROR("Failed to register EDID firmware platform device "
150 		    "for connector \"%s\"\n", connector_name);
151 		err = -EINVAL;
152 		goto out;
153 	}
154 
155 	err = request_firmware(&fw, name, &pdev->dev);
156 	platform_device_unregister(pdev);
157 
158 	if (err) {
159 		i = 0;
160 		while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
161 			i++;
162 		if (i < GENERIC_EDIDS) {
163 			err = 0;
164 			builtin = 1;
165 			fwdata = generic_edid[i];
166 			fwsize = sizeof(generic_edid[i]);
167 		}
168 	}
169 
170 	if (err) {
171 		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
172 		    name, err);
173 		goto out;
174 	}
175 
176 	if (fwdata == NULL) {
177 		fwdata = (u8 *) fw->data;
178 		fwsize = fw->size;
179 	}
180 
181 	expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
182 	if (expected != fwsize) {
183 		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
184 		    "(expected %d, got %d)\n", name, expected, (int) fwsize);
185 		err = -EINVAL;
186 		goto relfw_out;
187 	}
188 
189 	edid = kmalloc(fwsize, GFP_KERNEL);
190 	if (edid == NULL) {
191 		err = -ENOMEM;
192 		goto relfw_out;
193 	}
194 	memcpy(edid, fwdata, fwsize);
195 
196 	if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
197 		connector->bad_edid_counter++;
198 		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
199 		    name);
200 		kfree(edid);
201 		err = -EINVAL;
202 		goto relfw_out;
203 	}
204 
205 	for (i = 1; i <= edid[0x7e]; i++) {
206 		if (i != valid_extensions + 1)
207 			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
208 			    edid + i * EDID_LENGTH, EDID_LENGTH);
209 		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
210 			valid_extensions++;
211 	}
212 
213 	if (valid_extensions != edid[0x7e]) {
214 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
215 		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
216 		    "\"%s\" for connector \"%s\"\n", valid_extensions,
217 		    edid[0x7e], name, connector_name);
218 		edid[0x7e] = valid_extensions;
219 		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
220 		    GFP_KERNEL);
221 		if (new_edid == NULL) {
222 			err = -ENOMEM;
223 			kfree(edid);
224 			goto relfw_out;
225 		}
226 		edid = new_edid;
227 	}
228 
229 	DRM_INFO("Got %s EDID base block and %d extension%s from "
230 	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
231 	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
232 	    name, connector_name);
233 
234 relfw_out:
235 	release_firmware(fw);
236 
237 out:
238 	if (err)
239 		return ERR_PTR(err);
240 
241 	return edid;
242 }
243 
244 int drm_load_edid_firmware(struct drm_connector *connector)
245 {
246 	char *connector_name = drm_get_connector_name(connector);
247 	char *edidname = edid_firmware, *last, *colon;
248 	int ret;
249 	struct edid *edid;
250 
251 	if (*edidname == '\0')
252 		return 0;
253 
254 	colon = strchr(edidname, ':');
255 	if (colon != NULL) {
256 		if (strncmp(connector_name, edidname, colon - edidname))
257 			return 0;
258 		edidname = colon + 1;
259 		if (*edidname == '\0')
260 			return 0;
261 	}
262 
263 	last = edidname + strlen(edidname) - 1;
264 	if (*last == '\n')
265 		*last = '\0';
266 
267 	edid = (struct edid *) edid_load(connector, edidname, connector_name);
268 	if (IS_ERR_OR_NULL(edid))
269 		return 0;
270 
271 	drm_mode_connector_update_edid_property(connector, edid);
272 	ret = drm_add_edid_modes(connector, edid);
273 	kfree(edid);
274 
275 	return ret;
276 }
277