Merge patch series "riscv,isa fixups"
[linux-2.6-block.git] / drivers / gpu / drm / drm_edid_load.c
CommitLineData
fd534e9b 1// SPDX-License-Identifier: GPL-2.0-or-later
da0df92b
CE
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
da0df92b
CE
8*/
9
da0df92b 10#include <linux/firmware.h>
9c79edec
JN
11#include <linux/module.h>
12#include <linux/platform_device.h>
13
5f2d0ed4 14#include <drm/drm_connector.h>
9c79edec 15#include <drm/drm_drv.h>
760285e7 16#include <drm/drm_edid.h>
9c79edec 17#include <drm/drm_print.h>
da0df92b 18
5f2d0ed4
JN
19#include "drm_crtc_internal.h"
20
da0df92b
CE
21static char edid_firmware[PATH_MAX];
22module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
23MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
24 "from built-in data or /lib/firmware instead. ");
25
ac6c35a4
JN
26/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
27int __drm_set_edid_firmware_path(const char *path)
28{
29 scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
30
31 return 0;
32}
33EXPORT_SYMBOL(__drm_set_edid_firmware_path);
34
35/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
36int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
37{
38 return scnprintf(buf, bufsize, "%s", edid_firmware);
39}
40EXPORT_SYMBOL(__drm_get_edid_firmware_path);
41
4cbe1bfa 42#define GENERIC_EDIDS 6
a5b62374 43static const char * const generic_edid_name[GENERIC_EDIDS] = {
4cbe1bfa 44 "edid/800x600.bin",
da0df92b
CE
45 "edid/1024x768.bin",
46 "edid/1280x1024.bin",
8091ee5c 47 "edid/1600x1200.bin",
da0df92b
CE
48 "edid/1680x1050.bin",
49 "edid/1920x1080.bin",
50};
51
9066f83c 52static const u8 generic_edid[GENERIC_EDIDS][128] = {
4cbe1bfa
DT
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 },
da0df92b
CE
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,
8091ee5c
CE
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,
da0df92b
CE
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
794aca0e 163static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)
da0df92b 164{
9066f83c
CW
165 const struct firmware *fw = NULL;
166 const u8 *fwdata;
794aca0e 167 const struct drm_edid *drm_edid;
9066f83c 168 int fwsize, builtin;
da0df92b 169
7a5cf52d
AS
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 {
9066f83c 175 int err;
da0df92b 176
80afdfa6 177 err = request_firmware(&fw, name, connector->dev->dev);
9066f83c 178 if (err) {
2ab6590c
JN
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);
9066f83c
CW
183 return ERR_PTR(err);
184 }
da0df92b 185
9066f83c 186 fwdata = fw->data;
da0df92b
CE
187 fwsize = fw->size;
188 }
189
794aca0e
JN
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);
9066f83c 193
794aca0e
JN
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);
da0df92b
CE
199 }
200
9084acf1 201 release_firmware(fw);
794aca0e
JN
202
203 return drm_edid;
da0df92b
CE
204}
205
794aca0e 206const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)
da0df92b 207{
96206e29 208 char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
794aca0e 209 const struct drm_edid *drm_edid;
da0df92b 210
96206e29 211 if (edid_firmware[0] == '\0')
07c2b84b 212 return ERR_PTR(-ENOENT);
da0df92b 213
96206e29
BP
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 *
c67f6957 219 * If there's one or more that doesn't specify a connector, keep
96206e29
BP
220 * the last one found one as a fallback.
221 */
222 fwstr = kstrdup(edid_firmware, GFP_KERNEL);
9f1f1a2d
GZ
223 if (!fwstr)
224 return ERR_PTR(-ENOMEM);
96206e29
BP
225 edidstr = fwstr;
226
227 while ((edidname = strsep(&edidstr, ","))) {
228 colon = strchr(edidname, ':');
229 if (colon != NULL) {
8319d26a 230 if (strncmp(connector->name, edidname, colon - edidname))
96206e29
BP
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);
07c2b84b 243 return ERR_PTR(-ENOENT);
96206e29
BP
244 }
245 edidname = fallback;
da0df92b
CE
246 }
247
248 last = edidname + strlen(edidname) - 1;
249 if (*last == '\n')
250 *last = '\0';
251
794aca0e
JN
252 drm_edid = edid_load(connector, edidname);
253
96206e29
BP
254 kfree(fwstr);
255
794aca0e 256 return drm_edid;
da0df92b 257}