cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_edid_load.c (10162B)


      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_enabled(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}