Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / drm_edid_load.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3    drm_edid_load.c: use a built-in EDID data set or load it via the firmware
4                     interface
5
6    Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
7
8 */
9
10 #include <linux/firmware.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13
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>
19
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. ");
24
25 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
26 int __drm_set_edid_firmware_path(const char *path)
27 {
28         scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
29
30         return 0;
31 }
32 EXPORT_SYMBOL(__drm_set_edid_firmware_path);
33
34 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
35 int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
36 {
37         return scnprintf(buf, bufsize, "%s", edid_firmware);
38 }
39 EXPORT_SYMBOL(__drm_get_edid_firmware_path);
40
41 #define GENERIC_EDIDS 6
42 static const char * const generic_edid_name[GENERIC_EDIDS] = {
43         "edid/800x600.bin",
44         "edid/1024x768.bin",
45         "edid/1280x1024.bin",
46         "edid/1600x1200.bin",
47         "edid/1680x1050.bin",
48         "edid/1920x1080.bin",
49 };
50
51 static const u8 generic_edid[GENERIC_EDIDS][128] = {
52         {
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,
69         },
70         {
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,
87         },
88         {
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,
105         },
106         {
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,
123         },
124         {
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,
141         },
142         {
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,
159         },
160 };
161
162 static int edid_size(const u8 *edid, int data_size)
163 {
164         if (data_size < EDID_LENGTH)
165                 return 0;
166
167         return (edid[0x7e] + 1) * EDID_LENGTH;
168 }
169
170 static void *edid_load(struct drm_connector *connector, const char *name,
171                         const char *connector_name)
172 {
173         const struct firmware *fw = NULL;
174         const u8 *fwdata;
175         u8 *edid;
176         int fwsize, builtin;
177         int i, valid_extensions = 0;
178         bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
179
180         builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
181         if (builtin >= 0) {
182                 fwdata = generic_edid[builtin];
183                 fwsize = sizeof(generic_edid[builtin]);
184         } else {
185                 struct platform_device *pdev;
186                 int err;
187
188                 pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
189                 if (IS_ERR(pdev)) {
190                         DRM_ERROR("Failed to register EDID firmware platform device "
191                                   "for connector \"%s\"\n", connector_name);
192                         return ERR_CAST(pdev);
193                 }
194
195                 err = request_firmware(&fw, name, &pdev->dev);
196                 platform_device_unregister(pdev);
197                 if (err) {
198                         DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
199                                   name, err);
200                         return ERR_PTR(err);
201                 }
202
203                 fwdata = fw->data;
204                 fwsize = fw->size;
205         }
206
207         if (edid_size(fwdata, fwsize) != fwsize) {
208                 DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
209                           "(expected %d, got %d\n", name,
210                           edid_size(fwdata, fwsize), (int)fwsize);
211                 edid = ERR_PTR(-EINVAL);
212                 goto out;
213         }
214
215         edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
216         if (edid == NULL) {
217                 edid = ERR_PTR(-ENOMEM);
218                 goto out;
219         }
220
221         if (!drm_edid_block_valid(edid, 0, print_bad_edid,
222                                   &connector->edid_corrupt)) {
223                 connector->bad_edid_counter++;
224                 DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
225                     name);
226                 kfree(edid);
227                 edid = ERR_PTR(-EINVAL);
228                 goto out;
229         }
230
231         for (i = 1; i <= edid[0x7e]; i++) {
232                 if (i != valid_extensions + 1)
233                         memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
234                             edid + i * EDID_LENGTH, EDID_LENGTH);
235                 if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
236                                          print_bad_edid,
237                                          NULL))
238                         valid_extensions++;
239         }
240
241         if (valid_extensions != edid[0x7e]) {
242                 u8 *new_edid;
243
244                 edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
245                 DRM_INFO("Found %d valid extensions instead of %d in EDID data "
246                     "\"%s\" for connector \"%s\"\n", valid_extensions,
247                     edid[0x7e], name, connector_name);
248                 edid[0x7e] = valid_extensions;
249
250                 new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
251                                     GFP_KERNEL);
252                 if (new_edid)
253                         edid = new_edid;
254         }
255
256         DRM_INFO("Got %s EDID base block and %d extension%s from "
257             "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
258             "external", valid_extensions, valid_extensions == 1 ? "" : "s",
259             name, connector_name);
260
261 out:
262         release_firmware(fw);
263         return edid;
264 }
265
266 struct edid *drm_load_edid_firmware(struct drm_connector *connector)
267 {
268         const char *connector_name = connector->name;
269         char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
270         struct edid *edid;
271
272         if (edid_firmware[0] == '\0')
273                 return ERR_PTR(-ENOENT);
274
275         /*
276          * If there are multiple edid files specified and separated
277          * by commas, search through the list looking for one that
278          * matches the connector.
279          *
280          * If there's one or more that doesn't specify a connector, keep
281          * the last one found one as a fallback.
282          */
283         fwstr = kstrdup(edid_firmware, GFP_KERNEL);
284         if (!fwstr)
285                 return ERR_PTR(-ENOMEM);
286         edidstr = fwstr;
287
288         while ((edidname = strsep(&edidstr, ","))) {
289                 colon = strchr(edidname, ':');
290                 if (colon != NULL) {
291                         if (strncmp(connector_name, edidname, colon - edidname))
292                                 continue;
293                         edidname = colon + 1;
294                         break;
295                 }
296
297                 if (*edidname != '\0') /* corner case: multiple ',' */
298                         fallback = edidname;
299         }
300
301         if (!edidname) {
302                 if (!fallback) {
303                         kfree(fwstr);
304                         return ERR_PTR(-ENOENT);
305                 }
306                 edidname = fallback;
307         }
308
309         last = edidname + strlen(edidname) - 1;
310         if (*last == '\n')
311                 *last = '\0';
312
313         edid = edid_load(connector, edidname, connector_name);
314         kfree(fwstr);
315
316         return edid;
317 }