Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c537889 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon/kms: add support for hardcoded edids in rom (v2)



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: default avatarAlex Deucher <alexdeucher@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 2739d49c
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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
@@ -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++) {
@@ -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;
	}

@@ -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,
@@ -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,
@@ -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++) {
@@ -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;
+33 −0
Original line number Diff line number Diff line
@@ -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)
{
+13 −1
Original line number Diff line number Diff line
@@ -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) ||
@@ -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);
@@ -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;

@@ -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);
+5 −1
Original line number Diff line number Diff line
@@ -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
@@ -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 *
+2 −0
Original line number Diff line number Diff line
@@ -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__ */
Loading