drm/radeon/kms: fix hardcoded EDID handling

On some servers there is a hardcoded EDID provided
in the vbios so that the driver will always see a
display connected even if something like a KVM
prevents traditional means like DDC or load
detection from working properly.  Also most
server boards with DVI are not actually DVI, but
DVO connected to a virtual KVM service processor.
If we fail to detect a monitor via DDC or load
detection and a hardcoded EDID is available, use
it.

Additionally, when using the hardcoded EDID, use
a copy of it rather than the actual one stored
in the driver as the detect() and get_modes()
functions may free it if DDC is successful.

This fixes the virtual KVM on several internal
servers.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Cc: stable@kernel.org
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Alex Deucher
2011-03-23 08:10:10 +00:00
committed by Dave Airlie
parent 2d370f502a
commit fafcf94e2b
3 changed files with 45 additions and 7 deletions

View File

@@ -448,7 +448,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
{
int edid_info;
int edid_info, size;
struct edid *edid;
unsigned char *raw;
edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
@@ -456,11 +456,12 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
return false;
raw = rdev->bios + edid_info;
edid = kmalloc(EDID_LENGTH * (raw[0x7e] + 1), GFP_KERNEL);
size = EDID_LENGTH * (raw[0x7e] + 1);
edid = kmalloc(size, GFP_KERNEL);
if (edid == NULL)
return false;
memcpy((unsigned char *)edid, raw, EDID_LENGTH * (raw[0x7e] + 1));
memcpy((unsigned char *)edid, raw, size);
if (!drm_edid_is_valid(edid)) {
kfree(edid);
@@ -468,6 +469,7 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
}
rdev->mode_info.bios_hardcoded_edid = edid;
rdev->mode_info.bios_hardcoded_edid_size = size;
return true;
}
@@ -475,8 +477,17 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
struct edid *
radeon_bios_get_hardcoded_edid(struct radeon_device *rdev)
{
if (rdev->mode_info.bios_hardcoded_edid)
return rdev->mode_info.bios_hardcoded_edid;
struct edid *edid;
if (rdev->mode_info.bios_hardcoded_edid) {
edid = kmalloc(rdev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL);
if (edid) {
memcpy((unsigned char *)edid,
(unsigned char *)rdev->mode_info.bios_hardcoded_edid,
rdev->mode_info.bios_hardcoded_edid_size);
return edid;
}
}
return NULL;
}