Linux Audio

Check our new training course

Loading...
v4.6
 
  1/*
  2   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
  3		    interface
  4
  5   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
  6
  7   This program is free software; you can redistribute it and/or
  8   modify it under the terms of the GNU General Public License
  9   as published by the Free Software Foundation; either version 2
 10   of the License, or (at your option) any later version.
 11
 12   This program is distributed in the hope that it will be useful,
 13   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15   GNU General Public License for more details.
 16
 17   You should have received a copy of the GNU General Public License
 18   along with this program; if not, write to the Free Software
 19   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
 20*/
 21
 22#include <linux/module.h>
 23#include <linux/firmware.h>
 24#include <drm/drmP.h>
 25#include <drm/drm_crtc.h>
 26#include <drm/drm_crtc_helper.h>
 
 
 27#include <drm/drm_edid.h>
 
 
 
 28
 29static char edid_firmware[PATH_MAX];
 30module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
 31MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
 32	"from built-in data or /lib/firmware instead. ");
 33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 34#define GENERIC_EDIDS 6
 35static const char * const generic_edid_name[GENERIC_EDIDS] = {
 36	"edid/800x600.bin",
 37	"edid/1024x768.bin",
 38	"edid/1280x1024.bin",
 39	"edid/1600x1200.bin",
 40	"edid/1680x1050.bin",
 41	"edid/1920x1080.bin",
 42};
 43
 44static const u8 generic_edid[GENERIC_EDIDS][128] = {
 45	{
 46	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 47	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 48	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
 49	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 50	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
 51	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 52	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
 53	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
 54	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
 55	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 56	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 57	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 58	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
 59	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 60	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 61	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
 62	},
 63	{
 64	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 65	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 66	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
 67	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 68	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
 69	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 70	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
 71	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
 72	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
 73	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 74	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 75	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 76	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
 77	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 78	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
 79	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
 80	},
 81	{
 82	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 83	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 84	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
 85	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 86	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
 87	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 88	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
 89	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
 90	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
 91	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 92	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 93	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 94	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
 95	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 96	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 97	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
 98	},
 99	{
100	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
101	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
103	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
104	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
105	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
106	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
107	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
108	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
109	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
110	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
111	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
112	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
113	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
114	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
115	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
116	},
117	{
118	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
119	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
121	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
122	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
123	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
124	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
125	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
126	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
127	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
128	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
129	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
130	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
131	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
132	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
133	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
134	},
135	{
136	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
137	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
139	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
140	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
141	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
142	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
143	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
144	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
145	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
146	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
147	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
148	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
149	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
150	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
151	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
152	},
153};
154
155static int edid_size(const u8 *edid, int data_size)
156{
157	if (data_size < EDID_LENGTH)
158		return 0;
159
160	return (edid[0x7e] + 1) * EDID_LENGTH;
161}
162
163static void *edid_load(struct drm_connector *connector, const char *name,
164			const char *connector_name)
165{
166	const struct firmware *fw = NULL;
167	const u8 *fwdata;
168	u8 *edid;
169	int fwsize, builtin;
170	int i, valid_extensions = 0;
171	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
172
173	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
174	if (builtin >= 0) {
175		fwdata = generic_edid[builtin];
176		fwsize = sizeof(generic_edid[builtin]);
177	} else {
178		struct platform_device *pdev;
179		int err;
180
181		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
182		if (IS_ERR(pdev)) {
183			DRM_ERROR("Failed to register EDID firmware platform device "
184				  "for connector \"%s\"\n", connector_name);
185			return ERR_CAST(pdev);
186		}
187
188		err = request_firmware(&fw, name, &pdev->dev);
189		platform_device_unregister(pdev);
190		if (err) {
191			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
192				  name, err);
 
 
193			return ERR_PTR(err);
194		}
195
196		fwdata = fw->data;
197		fwsize = fw->size;
198	}
199
200	if (edid_size(fwdata, fwsize) != fwsize) {
201		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
202			  "(expected %d, got %d\n", name,
203			  edid_size(fwdata, fwsize), (int)fwsize);
204		edid = ERR_PTR(-EINVAL);
205		goto out;
206	}
207
208	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
209	if (edid == NULL) {
210		edid = ERR_PTR(-ENOMEM);
211		goto out;
212	}
213
214	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
215				  &connector->edid_corrupt)) {
216		connector->bad_edid_counter++;
217		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
218		    name);
219		kfree(edid);
220		edid = ERR_PTR(-EINVAL);
221		goto out;
222	}
223
224	for (i = 1; i <= edid[0x7e]; i++) {
225		if (i != valid_extensions + 1)
226			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
227			    edid + i * EDID_LENGTH, EDID_LENGTH);
228		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
229					 print_bad_edid,
230					 NULL))
231			valid_extensions++;
232	}
233
234	if (valid_extensions != edid[0x7e]) {
235		u8 *new_edid;
236
237		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
238		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
239		    "\"%s\" for connector \"%s\"\n", valid_extensions,
240		    edid[0x7e], name, connector_name);
241		edid[0x7e] = valid_extensions;
242
243		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
244				    GFP_KERNEL);
245		if (new_edid)
246			edid = new_edid;
247	}
248
249	DRM_INFO("Got %s EDID base block and %d extension%s from "
250	    "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
251	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
252	    name, connector_name);
253
254out:
255	release_firmware(fw);
256	return edid;
 
257}
258
259int drm_load_edid_firmware(struct drm_connector *connector)
260{
261	const char *connector_name = connector->name;
262	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
263	int ret;
264	struct edid *edid;
265
266	if (edid_firmware[0] == '\0')
267		return 0;
268
269	/*
270	 * If there are multiple edid files specified and separated
271	 * by commas, search through the list looking for one that
272	 * matches the connector.
273	 *
274	 * If there's one or more that don't't specify a connector, keep
275	 * the last one found one as a fallback.
276	 */
277	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
 
 
278	edidstr = fwstr;
279
280	while ((edidname = strsep(&edidstr, ","))) {
281		colon = strchr(edidname, ':');
282		if (colon != NULL) {
283			if (strncmp(connector_name, edidname, colon - edidname))
284				continue;
285			edidname = colon + 1;
286			break;
287		}
288
289		if (*edidname != '\0') /* corner case: multiple ',' */
290			fallback = edidname;
291	}
292
293	if (!edidname) {
294		if (!fallback) {
295			kfree(fwstr);
296			return 0;
297		}
298		edidname = fallback;
299	}
300
301	last = edidname + strlen(edidname) - 1;
302	if (*last == '\n')
303		*last = '\0';
304
305	edid = edid_load(connector, edidname, connector_name);
306	kfree(fwstr);
307
308	if (IS_ERR_OR_NULL(edid))
309		return 0;
310
311	drm_mode_connector_update_edid_property(connector, edid);
312	ret = drm_add_edid_modes(connector, edid);
313	drm_edid_to_eld(connector, edid);
314	kfree(edid);
315
316	return ret;
317}
v6.2
  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/* 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
 42#define GENERIC_EDIDS 6
 43static 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
 52static 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
163static 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
206const 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}