Linux Audio

Check our new training course

Loading...
v3.5.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 "drmP.h"
 25#include "drm_crtc.h"
 26#include "drm_crtc_helper.h"
 27#include "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 4
 35static char *generic_edid_name[GENERIC_EDIDS] = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 36	"edid/1024x768.bin",
 37	"edid/1280x1024.bin",
 
 38	"edid/1680x1050.bin",
 39	"edid/1920x1080.bin",
 40};
 41
 42static u8 generic_edid[GENERIC_EDIDS][128] = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 43	{
 44	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 45	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 46	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
 47	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 48	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
 49	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 50	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
 51	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
 52	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
 53	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 54	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 55	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 56	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
 57	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 58	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
 59	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
 60	},
 61	{
 62	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 63	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 64	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
 65	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 66	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
 67	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 68	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
 69	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
 70	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
 71	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 72	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 73	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 74	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
 75	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 76	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 77	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
 78	},
 79	{
 80	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 81	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 82	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
 83	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 84	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
 85	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 86	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
 87	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
 88	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
 89	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 90	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 91	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 92	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
 93	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 94	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
 95	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
 96	},
 97	{
 98	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 99	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
101	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
102	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
103	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
104	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
105	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
106	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
107	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
108	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
109	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
110	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
111	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
112	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
113	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
114	},
115};
116
117static int edid_load(struct drm_connector *connector, char *name,
118		     char *connector_name)
119{
120	const struct firmware *fw;
121	struct platform_device *pdev;
122	u8 *fwdata = NULL, *edid;
123	int fwsize, expected;
124	int builtin = 0, err = 0;
125	int i, valid_extensions = 0;
126
127	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
128	if (IS_ERR(pdev)) {
129		DRM_ERROR("Failed to register EDID firmware platform device "
130		    "for connector \"%s\"\n", connector_name);
131		err = -EINVAL;
132		goto out;
133	}
134
135	err = request_firmware(&fw, name, &pdev->dev);
136	platform_device_unregister(pdev);
 
 
 
 
 
 
 
137
138	if (err) {
139		i = 0;
140		while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
141			i++;
142		if (i < GENERIC_EDIDS) {
143			err = 0;
144			builtin = 1;
145			fwdata = generic_edid[i];
146			fwsize = sizeof(generic_edid[i]);
 
 
 
 
147		}
148	}
149
150	if (err) {
151		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
152		    name, err);
153		goto out;
154	}
 
 
155
156	if (fwdata == NULL) {
157		fwdata = (u8 *) fw->data;
158		fwsize = fw->size;
159	}
160
161	expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
162	if (expected != fwsize) {
163		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
164		    "(expected %d, got %d)\n", name, expected, (int) fwsize);
165		err = -EINVAL;
166		goto relfw_out;
 
167	}
168
169	edid = kmalloc(fwsize, GFP_KERNEL);
170	if (edid == NULL) {
171		err = -ENOMEM;
172		goto relfw_out;
173	}
174	memcpy(edid, fwdata, fwsize);
175
176	if (!drm_edid_block_valid(edid, 0)) {
 
 
177		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
178		    name);
179		kfree(edid);
180		err = -EINVAL;
181		goto relfw_out;
182	}
183
184	for (i = 1; i <= edid[0x7e]; i++) {
185		if (i != valid_extensions + 1)
186			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
187			    edid + i * EDID_LENGTH, EDID_LENGTH);
188		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
 
 
189			valid_extensions++;
190	}
191
192	if (valid_extensions != edid[0x7e]) {
 
 
193		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
194		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
195		    "\"%s\" for connector \"%s\"\n", valid_extensions,
196		    edid[0x7e], name, connector_name);
197		edid[0x7e] = valid_extensions;
198		edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
199		    GFP_KERNEL);
200		if (edid == NULL) {
201			err = -ENOMEM;
202			goto relfw_out;
203		}
204	}
205
206	connector->display_info.raw_edid = edid;
207	DRM_INFO("Got %s EDID base block and %d extension%s from "
208	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
209	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
210	    name, connector_name);
211
212relfw_out:
213	release_firmware(fw);
214
215out:
216	return err;
 
217}
218
219int drm_load_edid_firmware(struct drm_connector *connector)
220{
221	char *connector_name = drm_get_connector_name(connector);
222	char *edidname = edid_firmware, *last, *colon;
223	int ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
225	if (*edidname == '\0')
226		return 0;
 
227
228	colon = strchr(edidname, ':');
229	if (colon != NULL) {
230		if (strncmp(connector_name, edidname, colon - edidname))
231			return 0;
232		edidname = colon + 1;
233		if (*edidname == '\0')
234			return 0;
235	}
236
237	last = edidname + strlen(edidname) - 1;
238	if (*last == '\n')
239		*last = '\0';
240
241	ret = edid_load(connector, edidname, connector_name);
242	if (ret)
243		return 0;
244
245	drm_mode_connector_update_edid_property(connector,
246	    (struct edid *) connector->display_info.raw_edid);
247
248	return drm_add_edid_modes(connector, (struct edid *)
249	    connector->display_info.raw_edid);
250}
v4.17
  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/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
 35int __drm_set_edid_firmware_path(const char *path)
 36{
 37	scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
 38
 39	return 0;
 40}
 41EXPORT_SYMBOL(__drm_set_edid_firmware_path);
 42
 43/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
 44int __drm_get_edid_firmware_path(char *buf, size_t bufsize)
 45{
 46	return scnprintf(buf, bufsize, "%s", edid_firmware);
 47}
 48EXPORT_SYMBOL(__drm_get_edid_firmware_path);
 49
 50#define GENERIC_EDIDS 6
 51static const char * const generic_edid_name[GENERIC_EDIDS] = {
 52	"edid/800x600.bin",
 53	"edid/1024x768.bin",
 54	"edid/1280x1024.bin",
 55	"edid/1600x1200.bin",
 56	"edid/1680x1050.bin",
 57	"edid/1920x1080.bin",
 58};
 59
 60static const u8 generic_edid[GENERIC_EDIDS][128] = {
 61	{
 62	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 63	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 64	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
 65	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 66	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
 67	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 68	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
 69	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
 70	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
 71	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 72	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 73	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 74	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
 75	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 76	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 77	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
 78	},
 79	{
 80	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 81	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 82	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
 83	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 84	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
 85	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 86	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
 87	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
 88	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
 89	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 90	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 91	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 92	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
 93	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 94	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
 95	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
 96	},
 97	{
 98	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 99	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
101	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
102	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
103	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
104	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
105	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
106	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
107	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
108	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
109	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
110	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
111	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
112	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
113	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
114	},
115	{
116	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
117	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
119	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
120	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
121	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
122	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
123	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
124	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
125	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
126	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
127	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
128	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
129	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
130	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
131	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
132	},
133	{
134	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
135	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
137	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
138	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
139	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
140	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
141	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
142	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
143	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
144	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
145	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
146	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
147	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
148	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
149	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
150	},
151	{
152	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
153	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
155	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
156	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
157	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
158	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
159	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
160	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
161	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
162	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
163	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
164	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
165	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
166	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
167	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
168	},
169};
170
171static int edid_size(const u8 *edid, int data_size)
 
172{
173	if (data_size < EDID_LENGTH)
174		return 0;
 
 
 
 
175
176	return (edid[0x7e] + 1) * EDID_LENGTH;
177}
 
 
 
 
 
178
179static void *edid_load(struct drm_connector *connector, const char *name,
180			const char *connector_name)
181{
182	const struct firmware *fw = NULL;
183	const u8 *fwdata;
184	u8 *edid;
185	int fwsize, builtin;
186	int i, valid_extensions = 0;
187	bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
188
189	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
190	if (builtin >= 0) {
191		fwdata = generic_edid[builtin];
192		fwsize = sizeof(generic_edid[builtin]);
193	} else {
194		struct platform_device *pdev;
195		int err;
196
197		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
198		if (IS_ERR(pdev)) {
199			DRM_ERROR("Failed to register EDID firmware platform device "
200				  "for connector \"%s\"\n", connector_name);
201			return ERR_CAST(pdev);
202		}
 
203
204		err = request_firmware(&fw, name, &pdev->dev);
205		platform_device_unregister(pdev);
206		if (err) {
207			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
208				  name, err);
209			return ERR_PTR(err);
210		}
211
212		fwdata = fw->data;
 
213		fwsize = fw->size;
214	}
215
216	if (edid_size(fwdata, fwsize) != fwsize) {
 
217		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
218			  "(expected %d, got %d\n", name,
219			  edid_size(fwdata, fwsize), (int)fwsize);
220		edid = ERR_PTR(-EINVAL);
221		goto out;
222	}
223
224	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
225	if (edid == NULL) {
226		edid = ERR_PTR(-ENOMEM);
227		goto out;
228	}
 
229
230	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
231				  &connector->edid_corrupt)) {
232		connector->bad_edid_counter++;
233		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
234		    name);
235		kfree(edid);
236		edid = ERR_PTR(-EINVAL);
237		goto out;
238	}
239
240	for (i = 1; i <= edid[0x7e]; i++) {
241		if (i != valid_extensions + 1)
242			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
243			    edid + i * EDID_LENGTH, EDID_LENGTH);
244		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
245					 print_bad_edid,
246					 NULL))
247			valid_extensions++;
248	}
249
250	if (valid_extensions != edid[0x7e]) {
251		u8 *new_edid;
252
253		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
254		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
255		    "\"%s\" for connector \"%s\"\n", valid_extensions,
256		    edid[0x7e], name, connector_name);
257		edid[0x7e] = valid_extensions;
258
259		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
260				    GFP_KERNEL);
261		if (new_edid)
262			edid = new_edid;
 
263	}
264
 
265	DRM_INFO("Got %s EDID base block and %d extension%s from "
266	    "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
267	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
268	    name, connector_name);
269
 
 
 
270out:
271	release_firmware(fw);
272	return edid;
273}
274
275struct edid *drm_load_edid_firmware(struct drm_connector *connector)
276{
277	const char *connector_name = connector->name;
278	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
279	struct edid *edid;
280
281	if (edid_firmware[0] == '\0')
282		return ERR_PTR(-ENOENT);
283
284	/*
285	 * If there are multiple edid files specified and separated
286	 * by commas, search through the list looking for one that
287	 * matches the connector.
288	 *
289	 * If there's one or more that doesn't specify a connector, keep
290	 * the last one found one as a fallback.
291	 */
292	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
293	edidstr = fwstr;
294
295	while ((edidname = strsep(&edidstr, ","))) {
296		colon = strchr(edidname, ':');
297		if (colon != NULL) {
298			if (strncmp(connector_name, edidname, colon - edidname))
299				continue;
300			edidname = colon + 1;
301			break;
302		}
303
304		if (*edidname != '\0') /* corner case: multiple ',' */
305			fallback = edidname;
306	}
307
308	if (!edidname) {
309		if (!fallback) {
310			kfree(fwstr);
311			return ERR_PTR(-ENOENT);
312		}
313		edidname = fallback;
 
314	}
315
316	last = edidname + strlen(edidname) - 1;
317	if (*last == '\n')
318		*last = '\0';
319
320	edid = edid_load(connector, edidname, connector_name);
321	kfree(fwstr);
 
 
 
 
322
323	return edid;
 
324}