1 // SPDX-License-Identifier: GPL-2.0-or-later
3 drm_edid_load.c: use a built-in EDID data set or load it via the firmware
6 Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
10 #include <linux/firmware.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
14 #include <drm/drm_connector.h>
15 #include <drm/drm_drv.h>
16 #include <drm/drm_edid.h>
17 #include <drm/drm_print.h>
19 #include "drm_crtc_internal.h"
21 static char edid_firmware
[PATH_MAX
];
22 module_param_string(edid_firmware
, edid_firmware
, sizeof(edid_firmware
), 0644);
23 MODULE_PARM_DESC(edid_firmware
,
24 "Do not probe monitor, use specified EDID blob from /lib/firmware instead.");
26 static const struct drm_edid
*edid_load(struct drm_connector
*connector
, const char *name
)
28 const struct firmware
*fw
= NULL
;
29 const struct drm_edid
*drm_edid
;
32 err
= request_firmware(&fw
, name
, connector
->dev
->dev
);
34 drm_err(connector
->dev
,
35 "[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",
36 connector
->base
.id
, connector
->name
,
41 drm_dbg_kms(connector
->dev
, "[CONNECTOR:%d:%s] Loaded external firmware EDID \"%s\"\n",
42 connector
->base
.id
, connector
->name
, name
);
44 drm_edid
= drm_edid_alloc(fw
->data
, fw
->size
);
45 if (!drm_edid_valid(drm_edid
)) {
46 drm_err(connector
->dev
, "Invalid firmware EDID \"%s\"\n", name
);
47 drm_edid_free(drm_edid
);
48 drm_edid
= ERR_PTR(-EINVAL
);
56 const struct drm_edid
*drm_edid_load_firmware(struct drm_connector
*connector
)
58 char *edidname
, *last
, *colon
, *fwstr
, *edidstr
, *fallback
= NULL
;
59 const struct drm_edid
*drm_edid
;
61 if (edid_firmware
[0] == '\0')
62 return ERR_PTR(-ENOENT
);
65 * If there are multiple edid files specified and separated
66 * by commas, search through the list looking for one that
67 * matches the connector.
69 * If there's one or more that doesn't specify a connector, keep
70 * the last one found one as a fallback.
72 fwstr
= kstrdup(edid_firmware
, GFP_KERNEL
);
74 return ERR_PTR(-ENOMEM
);
77 while ((edidname
= strsep(&edidstr
, ","))) {
78 colon
= strchr(edidname
, ':');
80 if (strncmp(connector
->name
, edidname
, colon
- edidname
))
86 if (*edidname
!= '\0') /* corner case: multiple ',' */
93 return ERR_PTR(-ENOENT
);
98 last
= edidname
+ strlen(edidname
) - 1;
102 drm_edid
= edid_load(connector
, edidname
);