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