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/module.h>
11 #include <linux/firmware.h>
13 #include <drm/drm_crtc.h>
14 #include <drm/drm_crtc_helper.h>
15 #include <drm/drm_edid.h>
17 static char edid_firmware[PATH_MAX];
18 module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
19 MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
20 "from built-in data or /lib/firmware instead. ");
22 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
23 int __drm_set_edid_firmware_path(const char *path)
25 scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
29 EXPORT_SYMBOL(__drm_set_edid_firmware_path);
31 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
32 int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
34 return scnprintf(buf, bufsize, "%s", edid_firmware);
36 EXPORT_SYMBOL(__drm_get_edid_firmware_path);
38 #define GENERIC_EDIDS 6
39 static const char * const generic_edid_name[GENERIC_EDIDS] = {
48 static const u8 generic_edid[GENERIC_EDIDS][128] = {
50 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
51 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
53 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
54 0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
55 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
56 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
57 0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
58 0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
59 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
60 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
61 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
62 0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
63 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
64 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
65 0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
68 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
69 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
71 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
72 0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
73 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
74 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
75 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
76 0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
77 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
78 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
79 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
80 0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
81 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
82 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
83 0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
86 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
87 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88 0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
89 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
90 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
91 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
92 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
93 0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
94 0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
95 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
96 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
97 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
98 0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
99 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
100 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
101 0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
104 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
105 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
107 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
108 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
109 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
110 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
111 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
112 0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
113 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
114 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
115 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
116 0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
117 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
118 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
119 0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
122 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
123 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124 0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
125 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
126 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
127 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
128 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
129 0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
130 0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
131 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
132 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
133 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
134 0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
135 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
136 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
137 0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
140 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
141 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
143 0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
144 0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
145 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
146 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
147 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
148 0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
149 0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
150 0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
151 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
152 0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
153 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
154 0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
155 0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
159 static int edid_size(const u8 *edid, int data_size)
161 if (data_size < EDID_LENGTH)
164 return (edid[0x7e] + 1) * EDID_LENGTH;
167 static void *edid_load(struct drm_connector *connector, const char *name,
168 const char *connector_name)
170 const struct firmware *fw = NULL;
174 int i, valid_extensions = 0;
175 bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
177 builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
179 fwdata = generic_edid[builtin];
180 fwsize = sizeof(generic_edid[builtin]);
182 struct platform_device *pdev;
185 pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
187 DRM_ERROR("Failed to register EDID firmware platform device "
188 "for connector \"%s\"\n", connector_name);
189 return ERR_CAST(pdev);
192 err = request_firmware(&fw, name, &pdev->dev);
193 platform_device_unregister(pdev);
195 DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
204 if (edid_size(fwdata, fwsize) != fwsize) {
205 DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
206 "(expected %d, got %d\n", name,
207 edid_size(fwdata, fwsize), (int)fwsize);
208 edid = ERR_PTR(-EINVAL);
212 edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
214 edid = ERR_PTR(-ENOMEM);
218 if (!drm_edid_block_valid(edid, 0, print_bad_edid,
219 &connector->edid_corrupt)) {
220 connector->bad_edid_counter++;
221 DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
224 edid = ERR_PTR(-EINVAL);
228 for (i = 1; i <= edid[0x7e]; i++) {
229 if (i != valid_extensions + 1)
230 memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
231 edid + i * EDID_LENGTH, EDID_LENGTH);
232 if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
238 if (valid_extensions != edid[0x7e]) {
241 edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
242 DRM_INFO("Found %d valid extensions instead of %d in EDID data "
243 "\"%s\" for connector \"%s\"\n", valid_extensions,
244 edid[0x7e], name, connector_name);
245 edid[0x7e] = valid_extensions;
247 new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
253 DRM_INFO("Got %s EDID base block and %d extension%s from "
254 "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
255 "external", valid_extensions, valid_extensions == 1 ? "" : "s",
256 name, connector_name);
259 release_firmware(fw);
263 struct edid *drm_load_edid_firmware(struct drm_connector *connector)
265 const char *connector_name = connector->name;
266 char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
269 if (edid_firmware[0] == '\0')
270 return ERR_PTR(-ENOENT);
273 * If there are multiple edid files specified and separated
274 * by commas, search through the list looking for one that
275 * matches the connector.
277 * If there's one or more that doesn't specify a connector, keep
278 * the last one found one as a fallback.
280 fwstr = kstrdup(edid_firmware, GFP_KERNEL);
283 while ((edidname = strsep(&edidstr, ","))) {
284 colon = strchr(edidname, ':');
286 if (strncmp(connector_name, edidname, colon - edidname))
288 edidname = colon + 1;
292 if (*edidname != '\0') /* corner case: multiple ',' */
299 return ERR_PTR(-ENOENT);
304 last = edidname + strlen(edidname) - 1;
308 edid = edid_load(connector, edidname, connector_name);