1 // SPDX-License-Identifier: GPL-2.0-or-later
3 drm_edid_load.c: use a built-in EDID data set or load it via the firmware
6 Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
10 #include <linux/firmware.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
14 #include <drm/drm_crtc.h>
15 #include <drm/drm_crtc_helper.h>
16 #include <drm/drm_drv.h>
17 #include <drm/drm_edid.h>
18 #include <drm/drm_print.h>
20 static char edid_firmware[PATH_MAX];
21 module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
22 MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
23 "from built-in data or /lib/firmware instead. ");
25 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
26 int __drm_set_edid_firmware_path(const char *path)
28 scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
32 EXPORT_SYMBOL(__drm_set_edid_firmware_path);
34 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
35 int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
37 return scnprintf(buf, bufsize, "%s", edid_firmware);
39 EXPORT_SYMBOL(__drm_get_edid_firmware_path);
41 #define GENERIC_EDIDS 6
42 static const char * const generic_edid_name[GENERIC_EDIDS] = {
51 static const u8 generic_edid[GENERIC_EDIDS][128] = {
53 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
54 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
56 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
57 0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
58 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
59 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
60 0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
61 0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
62 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
63 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
64 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
65 0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
66 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
67 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
68 0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
71 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
72 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
74 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
75 0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
76 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
77 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
78 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
79 0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
80 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
81 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
82 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
83 0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
84 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
85 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
86 0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
89 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
90 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
92 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
93 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
94 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
95 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
96 0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
97 0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
98 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
99 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
100 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
101 0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
102 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
103 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
104 0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
107 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
108 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
110 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
111 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
112 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
113 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
114 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
115 0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
116 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
117 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
118 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
119 0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
120 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
121 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
122 0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
125 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
126 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
128 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
129 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
130 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
131 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
132 0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
133 0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
134 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
135 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
136 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
137 0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
138 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
139 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
140 0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
143 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
144 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
146 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
147 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
148 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
149 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
150 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
151 0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
152 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
153 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
154 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
155 0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
156 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
157 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
158 0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
162 static int edid_size(const u8 *edid, int data_size)
164 if (data_size < EDID_LENGTH)
167 return (edid[0x7e] + 1) * EDID_LENGTH;
170 static void *edid_load(struct drm_connector *connector, const char *name)
172 const struct firmware *fw = NULL;
176 int i, valid_extensions = 0;
177 bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS);
179 builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
181 fwdata = generic_edid[builtin];
182 fwsize = sizeof(generic_edid[builtin]);
184 struct platform_device *pdev;
187 pdev = platform_device_register_simple(connector->name, -1, NULL, 0);
189 DRM_ERROR("Failed to register EDID firmware platform device "
190 "for connector \"%s\"\n", connector->name);
191 return ERR_CAST(pdev);
194 err = request_firmware(&fw, name, &pdev->dev);
195 platform_device_unregister(pdev);
197 DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
206 if (edid_size(fwdata, fwsize) != fwsize) {
207 DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
208 "(expected %d, got %d\n", name,
209 edid_size(fwdata, fwsize), (int)fwsize);
210 edid = ERR_PTR(-EINVAL);
214 edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
216 edid = ERR_PTR(-ENOMEM);
220 if (!drm_edid_block_valid(edid, 0, print_bad_edid,
221 &connector->edid_corrupt)) {
222 connector->bad_edid_counter++;
223 DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
226 edid = ERR_PTR(-EINVAL);
230 for (i = 1; i <= edid[0x7e]; i++) {
231 if (i != valid_extensions + 1)
232 memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
233 edid + i * EDID_LENGTH, EDID_LENGTH);
234 if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
240 if (valid_extensions != edid[0x7e]) {
243 edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
244 DRM_INFO("Found %d valid extensions instead of %d in EDID data "
245 "\"%s\" for connector \"%s\"\n", valid_extensions,
246 edid[0x7e], name, connector->name);
247 edid[0x7e] = valid_extensions;
249 new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
255 DRM_INFO("Got %s EDID base block and %d extension%s from "
256 "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
257 "external", valid_extensions, valid_extensions == 1 ? "" : "s",
258 name, connector->name);
261 release_firmware(fw);
265 struct edid *drm_load_edid_firmware(struct drm_connector *connector)
267 char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
270 if (edid_firmware[0] == '\0')
271 return ERR_PTR(-ENOENT);
274 * If there are multiple edid files specified and separated
275 * by commas, search through the list looking for one that
276 * matches the connector.
278 * If there's one or more that doesn't specify a connector, keep
279 * the last one found one as a fallback.
281 fwstr = kstrdup(edid_firmware, GFP_KERNEL);
283 return ERR_PTR(-ENOMEM);
286 while ((edidname = strsep(&edidstr, ","))) {
287 colon = strchr(edidname, ':');
289 if (strncmp(connector->name, edidname, colon - edidname))
291 edidname = colon + 1;
295 if (*edidname != '\0') /* corner case: multiple ',' */
302 return ERR_PTR(-ENOENT);
307 last = edidname + strlen(edidname) - 1;
311 edid = edid_load(connector, edidname);