Merge tag 'sound-6.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-2.6-microblaze.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_connector.h>
15 #include <drm/drm_drv.h>
16 #include <drm/drm_edid.h>
17 #include <drm/drm_print.h>
18
19 #include "drm_crtc_internal.h"
20
21 static char edid_firmware[PATH_MAX];
22 module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
23 MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
24         "from built-in data or /lib/firmware instead. ");
25
26 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
27 int __drm_set_edid_firmware_path(const char *path)
28 {
29         scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
30
31         return 0;
32 }
33 EXPORT_SYMBOL(__drm_set_edid_firmware_path);
34
35 /* Use only for backward compatibility with drm_kms_helper.edid_firmware */
36 int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
37 {
38         return scnprintf(buf, bufsize, "%s", edid_firmware);
39 }
40 EXPORT_SYMBOL(__drm_get_edid_firmware_path);
41
42 #define GENERIC_EDIDS 6
43 static const char * const generic_edid_name[GENERIC_EDIDS] = {
44         "edid/800x600.bin",
45         "edid/1024x768.bin",
46         "edid/1280x1024.bin",
47         "edid/1600x1200.bin",
48         "edid/1680x1050.bin",
49         "edid/1920x1080.bin",
50 };
51
52 static const u8 generic_edid[GENERIC_EDIDS][128] = {
53         {
54         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
55         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56         0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
57         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
58         0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
59         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
60         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
61         0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
62         0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
63         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
64         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
65         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
66         0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
67         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
68         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
69         0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
70         },
71         {
72         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
73         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74         0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
75         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
76         0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
77         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
78         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
79         0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
80         0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
81         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
82         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
83         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
84         0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
85         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
86         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
87         0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
88         },
89         {
90         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
91         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92         0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
93         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
94         0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
95         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
96         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
97         0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
98         0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
99         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
100         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
101         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
102         0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
103         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
104         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
105         0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
106         },
107         {
108         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
109         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110         0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
111         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
112         0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
113         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
114         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
115         0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
116         0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
117         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
118         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
119         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
120         0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
121         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
122         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
123         0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
124         },
125         {
126         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
127         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128         0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
129         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
130         0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
131         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
132         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
133         0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
134         0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
135         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
136         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
137         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
138         0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
139         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
140         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
141         0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
142         },
143         {
144         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
145         0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146         0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
147         0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
148         0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
149         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
150         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
151         0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
152         0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
153         0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
154         0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
155         0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
156         0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
157         0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
158         0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
159         0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
160         },
161 };
162
163 static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)
164 {
165         const struct firmware *fw = NULL;
166         const u8 *fwdata;
167         const struct drm_edid *drm_edid;
168         int fwsize, builtin;
169
170         builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
171         if (builtin >= 0) {
172                 fwdata = generic_edid[builtin];
173                 fwsize = sizeof(generic_edid[builtin]);
174         } else {
175                 int err;
176
177                 err = request_firmware(&fw, name, connector->dev->dev);
178                 if (err) {
179                         drm_err(connector->dev,
180                                 "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",
181                                 connector->base.id, connector->name,
182                                 name, err);
183                         return ERR_PTR(err);
184                 }
185
186                 fwdata = fw->data;
187                 fwsize = fw->size;
188         }
189
190         drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n",
191                     connector->base.id, connector->name,
192                     builtin >= 0 ? "built-in" : "external", name);
193
194         drm_edid = drm_edid_alloc(fwdata, fwsize);
195         if (!drm_edid_valid(drm_edid)) {
196                 drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name);
197                 drm_edid_free(drm_edid);
198                 drm_edid = ERR_PTR(-EINVAL);
199         }
200
201         release_firmware(fw);
202
203         return drm_edid;
204 }
205
206 const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)
207 {
208         char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
209         const struct drm_edid *drm_edid;
210
211         if (edid_firmware[0] == '\0')
212                 return ERR_PTR(-ENOENT);
213
214         /*
215          * If there are multiple edid files specified and separated
216          * by commas, search through the list looking for one that
217          * matches the connector.
218          *
219          * If there's one or more that doesn't specify a connector, keep
220          * the last one found one as a fallback.
221          */
222         fwstr = kstrdup(edid_firmware, GFP_KERNEL);
223         if (!fwstr)
224                 return ERR_PTR(-ENOMEM);
225         edidstr = fwstr;
226
227         while ((edidname = strsep(&edidstr, ","))) {
228                 colon = strchr(edidname, ':');
229                 if (colon != NULL) {
230                         if (strncmp(connector->name, edidname, colon - edidname))
231                                 continue;
232                         edidname = colon + 1;
233                         break;
234                 }
235
236                 if (*edidname != '\0') /* corner case: multiple ',' */
237                         fallback = edidname;
238         }
239
240         if (!edidname) {
241                 if (!fallback) {
242                         kfree(fwstr);
243                         return ERR_PTR(-ENOENT);
244                 }
245                 edidname = fallback;
246         }
247
248         last = edidname + strlen(edidname) - 1;
249         if (*last == '\n')
250                 *last = '\0';
251
252         drm_edid = edid_load(connector, edidname);
253
254         kfree(fwstr);
255
256         return drm_edid;
257 }