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