2 * Copyright (c) 2015 Rimvydas Jasinskas
4 * Simple EDID firmware handling routines derived from
5 * drm_edid.c:drm_do_get_edid()
7 * Copyright (c) 2007-2008 Intel Corporation
8 * Jesse Barnes <jesse.barnes@intel.com>
9 * Copyright 2010 Red Hat, Inc.
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sub license,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice (including the
19 * next paragraph) shall be included in all copies or substantial portions
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
32 #include <drm/drm_edid.h>
34 #include <sys/firmware.h>
36 #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE
37 static u8
*do_edid_fw_load(struct drm_connector
*connector
, const char *fwname
,
38 const char *connector_name
);
40 static char edidfw_tun
[256];
41 TUNABLE_STR("drm.edid_firmware", edidfw_tun
, sizeof(edidfw_tun
));
43 struct edid
*drm_load_edid_firmware(struct drm_connector
*connector
)
45 const char *connector_name
= connector
->name
;
46 char *cp
, *fwname
= edidfw_tun
;
50 return ERR_PTR(-ENOENT
);
52 /* Check for connector specifier presence */
53 if ((cp
= strchr(fwname
, ':')) != NULL
) {
54 /* if connector name doesn't match, we're done */
55 if (strncmp(connector_name
, fwname
, cp
- fwname
))
56 return ERR_PTR(-ENOENT
);
59 return ERR_PTR(-ENOENT
);
62 fwedid
= (struct edid
*)do_edid_fw_load(connector
, fwname
, connector_name
);
68 do_edid_fw_load(struct drm_connector
*connector
, const char *fwname
,
69 const char *connector_name
)
71 const struct firmware
*fw
= NULL
;
73 u8
*block
= NULL
, *new = NULL
;
75 int j
, valid_extensions
= 0;
76 bool print_bad_edid
= !connector
->bad_edid_counter
|| (drm_debug
& DRM_UT_KMS
);
78 fw
= firmware_get(fwname
);
81 DRM_ERROR("Requesting EDID firmware %s failed\n", fwname
);
86 fwsize
= fw
->datasize
;
88 if (fwsize
< EDID_LENGTH
)
91 expected
= (fwdata
[0x7e] + 1) * EDID_LENGTH
;
92 if (expected
!= fwsize
) {
93 DRM_ERROR("Size of EDID firmware %s is invalid: %d vs %d(got)\n",
94 fwname
, expected
, fwsize
);
98 block
= kmalloc(fwsize
, M_DRM
, GFP_KERNEL
);
102 memcpy(block
, fwdata
, fwsize
);
104 /* now it is safe to release the firmware */
109 * Don't release edid fw right away, useful if / is
110 * still not mounted and/or we performing early kms
118 /* first check the base block */
119 if (!drm_edid_block_valid(block
, 0, print_bad_edid
, NULL
)) {
120 connector
->bad_edid_counter
++;
121 DRM_ERROR("EDID firmware %s base block is invalid ", fwname
);
125 DRM_INFO("Got EDID base block from %s for connector %s\n", fwname
, connector_name
);
127 /* if there's no extensions, we're done */
128 if (block
[0x7e] == 0)
131 /* XXX then extension blocks */
132 WARN(1, "Loading EDID firmware with extensions is untested!\n");
134 for (j
= 1; j
<= block
[0x7e]; j
++) {
135 /* if we skiped any extension block we have to shuffle good ones */
136 if (j
!= valid_extensions
+ 1) {
137 memcpy(block
+ (valid_extensions
+ 1) * EDID_LENGTH
,
138 block
+ (j
* EDID_LENGTH
), EDID_LENGTH
);
140 if (drm_edid_block_valid(block
+ j
* EDID_LENGTH
, j
, print_bad_edid
, NULL
)) {
145 if (valid_extensions
!= block
[0x7e]) {
146 block
[EDID_LENGTH
-1] += block
[0x7e] - valid_extensions
;
147 block
[0x7e] = valid_extensions
;
148 new = krealloc(block
, (valid_extensions
+ 1) * EDID_LENGTH
, M_DRM
, M_WAITOK
);
154 if (valid_extensions
> 0) {
155 DRM_INFO("Got %d extensions in EDID firmware from %s for connector %s\n",
156 valid_extensions
, fwname
, connector_name
);
159 /* if got to here return edid block */
167 #endif /* CONFIG_DRM_LOAD_EDID_FIRMWARE */