Skip to content

Commit

Permalink
drm/radeon/kms: add support for hardcoded edids in rom (v2)
Browse files Browse the repository at this point in the history
Some servers hardcode an edid in rom so that they will
work properly with KVMs.  This is a port of the relevant
code from the ddx.

[airlied: reworked to validate edid at boot stage - and
remove special quirk, if there is a valid EDID in the BIOS rom
we'll just try and use it.]

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed Feb 8, 2010
1 parent 2739d49 commit 3c53788
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 17 deletions.
30 changes: 15 additions & 15 deletions drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5)
/* use +hsync +vsync for detailed mode */
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
/* define the number of Extension EDID block */
#define MAX_EDID_EXT_NUM 4


#define LEVEL_DMT 0
#define LEVEL_GTF 1
Expand Down Expand Up @@ -114,14 +113,14 @@ static const u8 edid_header[] = {
};

/**
* edid_is_valid - sanity check EDID data
* drm_edid_is_valid - sanity check EDID data
* @edid: EDID data
*
* Sanity check the EDID block by looking at the header, the version number
* and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
* valid.
*/
static bool edid_is_valid(struct edid *edid)
bool drm_edid_is_valid(struct edid *edid)
{
int i, score = 0;
u8 csum = 0;
Expand Down Expand Up @@ -163,6 +162,7 @@ static bool edid_is_valid(struct edid *edid)
}
return 0;
}
EXPORT_SYMBOL(drm_edid_is_valid);

/**
* edid_vendor - match a string against EDID's obfuscated vendor field
Expand Down Expand Up @@ -1069,8 +1069,8 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
}

/* Chose real EDID extension number */
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
MAX_EDID_EXT_NUM : edid->extensions;
edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
DRM_MAX_EDID_EXT_NUM : edid->extensions;

/* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) {
Expand Down Expand Up @@ -1152,7 +1152,7 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, buf, len))
return -1;
if (edid_is_valid((struct edid *)buf))
if (drm_edid_is_valid((struct edid *)buf))
return 0;
}

Expand All @@ -1177,7 +1177,7 @@ struct edid *drm_get_edid(struct drm_connector *connector,
int ret;
struct edid *edid;

edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL) {
dev_warn(&connector->dev->pdev->dev,
Expand All @@ -1195,14 +1195,14 @@ struct edid *drm_get_edid(struct drm_connector *connector,
if (edid->extensions != 0) {
int edid_ext_num = edid->extensions;

if (edid_ext_num > MAX_EDID_EXT_NUM) {
if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
dev_warn(&connector->dev->pdev->dev,
"The number of extension(%d) is "
"over max (%d), actually read number (%d)\n",
edid_ext_num, MAX_EDID_EXT_NUM,
MAX_EDID_EXT_NUM);
edid_ext_num, DRM_MAX_EDID_EXT_NUM,
DRM_MAX_EDID_EXT_NUM);
/* Reset EDID extension number to be read */
edid_ext_num = MAX_EDID_EXT_NUM;
edid_ext_num = DRM_MAX_EDID_EXT_NUM;
}
/* Read EDID including extensions too */
ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
Expand Down Expand Up @@ -1245,8 +1245,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
goto end;

/* Chose real EDID extension number */
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
MAX_EDID_EXT_NUM : edid->extensions;
edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
DRM_MAX_EDID_EXT_NUM : edid->extensions;

/* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) {
Expand Down Expand Up @@ -1303,7 +1303,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (edid == NULL) {
return 0;
}
if (!edid_is_valid(edid)) {
if (!drm_edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
return 0;
Expand Down
33 changes: 33 additions & 0 deletions drivers/gpu/drm/radeon/radeon_combios.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,39 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,

}

bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
{
int edid_info;
struct edid *edid;
edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
if (!edid_info)
return false;

edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL)
return false;

memcpy((unsigned char *)edid,
(unsigned char *)(rdev->bios + edid_info), EDID_LENGTH);

if (!drm_edid_is_valid(edid)) {
kfree(edid);
return false;
}

rdev->mode_info.bios_hardcoded_edid = edid;
return true;
}

struct edid *
radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
{
if (rdev->mode_info.bios_hardcoded_edid)
return rdev->mode_info.bios_hardcoded_edid;
return NULL;
}

static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
int ddc_line)
{
Expand Down
14 changes: 13 additions & 1 deletion drivers/gpu/drm/radeon/radeon_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)

int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
{
struct drm_device *dev = radeon_connector->base.dev;
struct radeon_device *rdev = dev->dev_private;
int ret = 0;

if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
Expand All @@ -366,7 +368,9 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
if (!radeon_connector->edid) {
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
}

/* some servers provide a hardcoded edid in rom for KVMs */
if (!radeon_connector->edid)
radeon_connector->edid = radeon_combios_get_hardcoded_edid(rdev);
if (radeon_connector->edid) {
drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
Expand Down Expand Up @@ -829,6 +833,12 @@ int radeon_modeset_init(struct radeon_device *rdev)
return ret;
}

/* check combios for a valid hardcoded EDID - Sun servers */
if (!rdev->is_atom_bios) {
/* check for hardcoded EDID in BIOS */
radeon_combios_check_hardcoded_edid(rdev);
}

if (rdev->flags & RADEON_SINGLE_CRTC)
num_crtc = 1;

Expand All @@ -850,6 +860,8 @@ int radeon_modeset_init(struct radeon_device *rdev)

void radeon_modeset_fini(struct radeon_device *rdev)
{
kfree(rdev->mode_info.bios_hardcoded_edid);

if (rdev->mode_info.mode_config_initialized) {
radeon_hpd_fini(rdev);
drm_mode_config_cleanup(rdev->ddev);
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpu/drm/radeon/radeon_mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ struct radeon_mode_info {
struct drm_property *tv_std_property;
/* legacy TMDS PLL detect */
struct drm_property *tmds_pll_property;

/* hardcoded DFP edid from BIOS */
struct edid *bios_hardcoded_edid;
};

#define MAX_H_CODE_TIMING_LEN 32
Expand Down Expand Up @@ -479,6 +480,9 @@ extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
int x, int y);

extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
extern struct edid *
radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
extern bool radeon_atom_get_clock_info(struct drm_device *dev);
extern bool radeon_combios_get_clock_info(struct drm_device *dev);
extern struct radeon_encoder_atom_dig *
Expand Down
2 changes: 2 additions & 0 deletions include/drm/drm_crtc.h
Original file line number Diff line number Diff line change
Expand Up @@ -801,4 +801,6 @@ extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
bool interlaced, int margins);
extern int drm_add_modes_noedid(struct drm_connector *connector,
int hdisplay, int vdisplay);

extern bool drm_edid_is_valid(struct edid *edid);
#endif /* __DRM_CRTC_H__ */
3 changes: 3 additions & 0 deletions include/drm/drm_edid.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,7 @@ struct edid {

#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))

/* define the number of Extension EDID block */
#define DRM_MAX_EDID_EXT_NUM 4

#endif /* __DRM_EDID_H__ */

0 comments on commit 3c53788

Please sign in to comment.