18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
48c2ecf20Sopenharmony_ci		    interface
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci*/
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/firmware.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
158c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h>
168c2ecf20Sopenharmony_ci#include <drm/drm_drv.h>
178c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
188c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic char edid_firmware[PATH_MAX];
218c2ecf20Sopenharmony_cimodule_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
238c2ecf20Sopenharmony_ci	"from built-in data or /lib/firmware instead. ");
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
268c2ecf20Sopenharmony_ciint __drm_set_edid_firmware_path(const char *path)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	return 0;
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_set_edid_firmware_path);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Use only for backward compatibility with drm_kms_helper.edid_firmware */
358c2ecf20Sopenharmony_ciint __drm_get_edid_firmware_path(char *buf, size_t bufsize)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	return scnprintf(buf, bufsize, "%s", edid_firmware);
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__drm_get_edid_firmware_path);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define GENERIC_EDIDS 6
428c2ecf20Sopenharmony_cistatic const char * const generic_edid_name[GENERIC_EDIDS] = {
438c2ecf20Sopenharmony_ci	"edid/800x600.bin",
448c2ecf20Sopenharmony_ci	"edid/1024x768.bin",
458c2ecf20Sopenharmony_ci	"edid/1280x1024.bin",
468c2ecf20Sopenharmony_ci	"edid/1600x1200.bin",
478c2ecf20Sopenharmony_ci	"edid/1680x1050.bin",
488c2ecf20Sopenharmony_ci	"edid/1920x1080.bin",
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic const u8 generic_edid[GENERIC_EDIDS][128] = {
528c2ecf20Sopenharmony_ci	{
538c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
548c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
558c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
568c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
578c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
588c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
598c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
608c2ecf20Sopenharmony_ci	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
618c2ecf20Sopenharmony_ci	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
628c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
638c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
648c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
658c2ecf20Sopenharmony_ci	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
668c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
678c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
688c2ecf20Sopenharmony_ci	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
698c2ecf20Sopenharmony_ci	},
708c2ecf20Sopenharmony_ci	{
718c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
728c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
738c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
748c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
758c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
768c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
778c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
788c2ecf20Sopenharmony_ci	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
798c2ecf20Sopenharmony_ci	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
808c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
818c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
828c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
838c2ecf20Sopenharmony_ci	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
848c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
858c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
868c2ecf20Sopenharmony_ci	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
878c2ecf20Sopenharmony_ci	},
888c2ecf20Sopenharmony_ci	{
898c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
908c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
918c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
928c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
938c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
948c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
958c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
968c2ecf20Sopenharmony_ci	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
978c2ecf20Sopenharmony_ci	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
988c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
998c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
1008c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
1018c2ecf20Sopenharmony_ci	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
1028c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
1038c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
1048c2ecf20Sopenharmony_ci	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
1058c2ecf20Sopenharmony_ci	},
1068c2ecf20Sopenharmony_ci	{
1078c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
1088c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1098c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
1108c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
1118c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
1128c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1138c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
1148c2ecf20Sopenharmony_ci	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
1158c2ecf20Sopenharmony_ci	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
1168c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
1178c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
1188c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
1198c2ecf20Sopenharmony_ci	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
1208c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
1218c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
1228c2ecf20Sopenharmony_ci	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
1238c2ecf20Sopenharmony_ci	},
1248c2ecf20Sopenharmony_ci	{
1258c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
1268c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1278c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
1288c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
1298c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
1308c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1318c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
1328c2ecf20Sopenharmony_ci	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
1338c2ecf20Sopenharmony_ci	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
1348c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
1358c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
1368c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
1378c2ecf20Sopenharmony_ci	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
1388c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
1398c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
1408c2ecf20Sopenharmony_ci	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
1418c2ecf20Sopenharmony_ci	},
1428c2ecf20Sopenharmony_ci	{
1438c2ecf20Sopenharmony_ci	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
1448c2ecf20Sopenharmony_ci	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1458c2ecf20Sopenharmony_ci	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
1468c2ecf20Sopenharmony_ci	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
1478c2ecf20Sopenharmony_ci	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
1488c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
1498c2ecf20Sopenharmony_ci	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
1508c2ecf20Sopenharmony_ci	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
1518c2ecf20Sopenharmony_ci	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
1528c2ecf20Sopenharmony_ci	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
1538c2ecf20Sopenharmony_ci	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
1548c2ecf20Sopenharmony_ci	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
1558c2ecf20Sopenharmony_ci	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
1568c2ecf20Sopenharmony_ci	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
1578c2ecf20Sopenharmony_ci	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
1588c2ecf20Sopenharmony_ci	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
1598c2ecf20Sopenharmony_ci	},
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int edid_size(const u8 *edid, int data_size)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	if (data_size < EDID_LENGTH)
1658c2ecf20Sopenharmony_ci		return 0;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return (edid[0x7e] + 1) * EDID_LENGTH;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic void *edid_load(struct drm_connector *connector, const char *name,
1718c2ecf20Sopenharmony_ci			const char *connector_name)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	const struct firmware *fw = NULL;
1748c2ecf20Sopenharmony_ci	const u8 *fwdata;
1758c2ecf20Sopenharmony_ci	u8 *edid;
1768c2ecf20Sopenharmony_ci	int fwsize, builtin;
1778c2ecf20Sopenharmony_ci	int i, valid_extensions = 0;
1788c2ecf20Sopenharmony_ci	bool print_bad_edid = !connector->bad_edid_counter || drm_debug_enabled(DRM_UT_KMS);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
1818c2ecf20Sopenharmony_ci	if (builtin >= 0) {
1828c2ecf20Sopenharmony_ci		fwdata = generic_edid[builtin];
1838c2ecf20Sopenharmony_ci		fwsize = sizeof(generic_edid[builtin]);
1848c2ecf20Sopenharmony_ci	} else {
1858c2ecf20Sopenharmony_ci		struct platform_device *pdev;
1868c2ecf20Sopenharmony_ci		int err;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
1898c2ecf20Sopenharmony_ci		if (IS_ERR(pdev)) {
1908c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to register EDID firmware platform device "
1918c2ecf20Sopenharmony_ci				  "for connector \"%s\"\n", connector_name);
1928c2ecf20Sopenharmony_ci			return ERR_CAST(pdev);
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		err = request_firmware(&fw, name, &pdev->dev);
1968c2ecf20Sopenharmony_ci		platform_device_unregister(pdev);
1978c2ecf20Sopenharmony_ci		if (err) {
1988c2ecf20Sopenharmony_ci			DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
1998c2ecf20Sopenharmony_ci				  name, err);
2008c2ecf20Sopenharmony_ci			return ERR_PTR(err);
2018c2ecf20Sopenharmony_ci		}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		fwdata = fw->data;
2048c2ecf20Sopenharmony_ci		fwsize = fw->size;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (edid_size(fwdata, fwsize) != fwsize) {
2088c2ecf20Sopenharmony_ci		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
2098c2ecf20Sopenharmony_ci			  "(expected %d, got %d\n", name,
2108c2ecf20Sopenharmony_ci			  edid_size(fwdata, fwsize), (int)fwsize);
2118c2ecf20Sopenharmony_ci		edid = ERR_PTR(-EINVAL);
2128c2ecf20Sopenharmony_ci		goto out;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
2168c2ecf20Sopenharmony_ci	if (edid == NULL) {
2178c2ecf20Sopenharmony_ci		edid = ERR_PTR(-ENOMEM);
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!drm_edid_block_valid(edid, 0, print_bad_edid,
2228c2ecf20Sopenharmony_ci				  &connector->edid_corrupt)) {
2238c2ecf20Sopenharmony_ci		connector->bad_edid_counter++;
2248c2ecf20Sopenharmony_ci		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
2258c2ecf20Sopenharmony_ci		    name);
2268c2ecf20Sopenharmony_ci		kfree(edid);
2278c2ecf20Sopenharmony_ci		edid = ERR_PTR(-EINVAL);
2288c2ecf20Sopenharmony_ci		goto out;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	for (i = 1; i <= edid[0x7e]; i++) {
2328c2ecf20Sopenharmony_ci		if (i != valid_extensions + 1)
2338c2ecf20Sopenharmony_ci			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
2348c2ecf20Sopenharmony_ci			    edid + i * EDID_LENGTH, EDID_LENGTH);
2358c2ecf20Sopenharmony_ci		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
2368c2ecf20Sopenharmony_ci					 print_bad_edid,
2378c2ecf20Sopenharmony_ci					 NULL))
2388c2ecf20Sopenharmony_ci			valid_extensions++;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (valid_extensions != edid[0x7e]) {
2428c2ecf20Sopenharmony_ci		u8 *new_edid;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
2458c2ecf20Sopenharmony_ci		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
2468c2ecf20Sopenharmony_ci		    "\"%s\" for connector \"%s\"\n", valid_extensions,
2478c2ecf20Sopenharmony_ci		    edid[0x7e], name, connector_name);
2488c2ecf20Sopenharmony_ci		edid[0x7e] = valid_extensions;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
2518c2ecf20Sopenharmony_ci				    GFP_KERNEL);
2528c2ecf20Sopenharmony_ci		if (new_edid)
2538c2ecf20Sopenharmony_ci			edid = new_edid;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	DRM_INFO("Got %s EDID base block and %d extension%s from "
2578c2ecf20Sopenharmony_ci	    "\"%s\" for connector \"%s\"\n", (builtin >= 0) ? "built-in" :
2588c2ecf20Sopenharmony_ci	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
2598c2ecf20Sopenharmony_ci	    name, connector_name);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ciout:
2628c2ecf20Sopenharmony_ci	release_firmware(fw);
2638c2ecf20Sopenharmony_ci	return edid;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistruct edid *drm_load_edid_firmware(struct drm_connector *connector)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	const char *connector_name = connector->name;
2698c2ecf20Sopenharmony_ci	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
2708c2ecf20Sopenharmony_ci	struct edid *edid;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (edid_firmware[0] == '\0')
2738c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOENT);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * If there are multiple edid files specified and separated
2778c2ecf20Sopenharmony_ci	 * by commas, search through the list looking for one that
2788c2ecf20Sopenharmony_ci	 * matches the connector.
2798c2ecf20Sopenharmony_ci	 *
2808c2ecf20Sopenharmony_ci	 * If there's one or more that doesn't specify a connector, keep
2818c2ecf20Sopenharmony_ci	 * the last one found one as a fallback.
2828c2ecf20Sopenharmony_ci	 */
2838c2ecf20Sopenharmony_ci	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
2848c2ecf20Sopenharmony_ci	if (!fwstr)
2858c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2868c2ecf20Sopenharmony_ci	edidstr = fwstr;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	while ((edidname = strsep(&edidstr, ","))) {
2898c2ecf20Sopenharmony_ci		colon = strchr(edidname, ':');
2908c2ecf20Sopenharmony_ci		if (colon != NULL) {
2918c2ecf20Sopenharmony_ci			if (strncmp(connector_name, edidname, colon - edidname))
2928c2ecf20Sopenharmony_ci				continue;
2938c2ecf20Sopenharmony_ci			edidname = colon + 1;
2948c2ecf20Sopenharmony_ci			break;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (*edidname != '\0') /* corner case: multiple ',' */
2988c2ecf20Sopenharmony_ci			fallback = edidname;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (!edidname) {
3028c2ecf20Sopenharmony_ci		if (!fallback) {
3038c2ecf20Sopenharmony_ci			kfree(fwstr);
3048c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOENT);
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci		edidname = fallback;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	last = edidname + strlen(edidname) - 1;
3108c2ecf20Sopenharmony_ci	if (*last == '\n')
3118c2ecf20Sopenharmony_ci		*last = '\0';
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	edid = edid_load(connector, edidname, connector_name);
3148c2ecf20Sopenharmony_ci	kfree(fwstr);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return edid;
3178c2ecf20Sopenharmony_ci}
318