Linux Audio

Check our new training course

Loading...
v5.4
  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
 
 
 20static char edid_firmware[PATH_MAX];
 21module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
 22MODULE_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 */
 26int __drm_set_edid_firmware_path(const char *path)
 27{
 28	scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
 29
 30	return 0;
 31}
 32EXPORT_SYMBOL(__drm_set_edid_firmware_path);
 33
 34/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
 35int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
 36{
 37	return scnprintf(buf, bufsize, "%s", edid_firmware);
 38}
 39EXPORT_SYMBOL(__drm_get_edid_firmware_path);
 40
 41#define GENERIC_EDIDS 6
 42static 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
 51static 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
162static 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
170static 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
261out:
262	release_firmware(fw);
263	return edid;
 
264}
265
266struct 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}
v6.8
  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
 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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 26#define GENERIC_EDIDS 6
 27static 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
 36static 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
147static 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
190const 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}