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

Commit 8fe9790d authored by Zhenyu Wang's avatar Zhenyu Wang Committed by Chris Wilson
Browse files

drm/edid: add helper function to detect monitor audio capability



To help to determine if digital display port needs to enable
audio output or not. This one adds a helper to get monitor's
audio capability via EDID CEA extension block.

Tested-by: default avatarWu Fengguang <fengguang.wu@intel.com>
Signed-off-by: default avatarZhenyu Wang <zhenyuw@linux.intel.com>
Reviewed-by: default avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 6d139a87
Loading
Loading
Loading
Loading
+78 −14
Original line number Diff line number Diff line
@@ -1267,34 +1267,51 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
}

#define HDMI_IDENTIFIER 0x000C03
#define AUDIO_BLOCK	0x01
#define VENDOR_BLOCK    0x03
#define EDID_BASIC_AUDIO	(1 << 6)

/**
 * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
 * @edid: monitor EDID information
 *
 * Parse the CEA extension according to CEA-861-B.
 * Return true if HDMI, false if not or unknown.
 * Search EDID for CEA extension block.
 */
bool drm_detect_hdmi_monitor(struct edid *edid)
static u8 *drm_find_cea_extension(struct edid *edid)
{
	char *edid_ext = NULL;
	int i, hdmi_id;
	int start_offset, end_offset;
	bool is_hdmi = false;
	u8 *edid_ext = NULL;
	int i;

	/* No EDID or EDID extensions */
	if (edid == NULL || edid->extensions == 0)
		goto end;
		return NULL;

	/* Find CEA extension */
	for (i = 0; i < edid->extensions; i++) {
		edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
		/* This block is CEA extension */
		if (edid_ext[0] == 0x02)
		edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
		if (edid_ext[0] == CEA_EXT)
			break;
	}

	if (i == edid->extensions)
		return NULL;

	return edid_ext;
}

/**
 * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
 * @edid: monitor EDID information
 *
 * Parse the CEA extension according to CEA-861-B.
 * Return true if HDMI, false if not or unknown.
 */
bool drm_detect_hdmi_monitor(struct edid *edid)
{
	u8 *edid_ext;
	int i, hdmi_id;
	int start_offset, end_offset;
	bool is_hdmi = false;

	edid_ext = drm_find_cea_extension(edid);
	if (!edid_ext)
		goto end;

	/* Data block offset in CEA extension block */
@@ -1324,6 +1341,53 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
}
EXPORT_SYMBOL(drm_detect_hdmi_monitor);

/**
 * drm_detect_monitor_audio - check monitor audio capability
 *
 * Monitor should have CEA extension block.
 * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
 * audio' only. If there is any audio extension block and supported
 * audio format, assume at least 'basic audio' support, even if 'basic
 * audio' is not defined in EDID.
 *
 */
bool drm_detect_monitor_audio(struct edid *edid)
{
	u8 *edid_ext;
	int i, j;
	bool has_audio = false;
	int start_offset, end_offset;

	edid_ext = drm_find_cea_extension(edid);
	if (!edid_ext)
		goto end;

	has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0);

	if (has_audio) {
		DRM_DEBUG_KMS("Monitor has basic audio support\n");
		goto end;
	}

	/* Data block offset in CEA extension block */
	start_offset = 4;
	end_offset = edid_ext[2];

	for (i = start_offset; i < end_offset;
			i += ((edid_ext[i] & 0x1f) + 1)) {
		if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
			has_audio = true;
			for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
				DRM_DEBUG_KMS("CEA audio format %d\n",
					      (edid_ext[i + j] >> 3) & 0xf);
			goto end;
		}
	}
end:
	return has_audio;
}
EXPORT_SYMBOL(drm_detect_monitor_audio);

/**
 * drm_add_edid_modes - add modes from EDID data, if available
 * @connector: connector we're probing
+1 −0
Original line number Diff line number Diff line
@@ -763,6 +763,7 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
				    void *data, struct drm_file *file_priv);
extern bool drm_detect_hdmi_monitor(struct edid *edid);
extern bool drm_detect_monitor_audio(struct edid *edid);
extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
				    void *data, struct drm_file *file_priv);
extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,