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: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
6d139a87b7
commit
8fe9790d16
|
@ -1267,7 +1267,35 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HDMI_IDENTIFIER 0x000C03
|
#define HDMI_IDENTIFIER 0x000C03
|
||||||
|
#define AUDIO_BLOCK 0x01
|
||||||
#define VENDOR_BLOCK 0x03
|
#define VENDOR_BLOCK 0x03
|
||||||
|
#define EDID_BASIC_AUDIO (1 << 6)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search EDID for CEA extension block.
|
||||||
|
*/
|
||||||
|
static u8 *drm_find_cea_extension(struct edid *edid)
|
||||||
|
{
|
||||||
|
u8 *edid_ext = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* No EDID or EDID extensions */
|
||||||
|
if (edid == NULL || edid->extensions == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Find CEA extension */
|
||||||
|
for (i = 0; i < edid->extensions; i++) {
|
||||||
|
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.
|
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
|
||||||
* @edid: monitor EDID information
|
* @edid: monitor EDID information
|
||||||
|
@ -1277,24 +1305,13 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||||
*/
|
*/
|
||||||
bool drm_detect_hdmi_monitor(struct edid *edid)
|
bool drm_detect_hdmi_monitor(struct edid *edid)
|
||||||
{
|
{
|
||||||
char *edid_ext = NULL;
|
u8 *edid_ext;
|
||||||
int i, hdmi_id;
|
int i, hdmi_id;
|
||||||
int start_offset, end_offset;
|
int start_offset, end_offset;
|
||||||
bool is_hdmi = false;
|
bool is_hdmi = false;
|
||||||
|
|
||||||
/* No EDID or EDID extensions */
|
edid_ext = drm_find_cea_extension(edid);
|
||||||
if (edid == NULL || edid->extensions == 0)
|
if (!edid_ext)
|
||||||
goto end;
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == edid->extensions)
|
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
/* Data block offset in CEA extension block */
|
/* Data block offset in CEA extension block */
|
||||||
|
@ -1324,6 +1341,53 @@ end:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_detect_hdmi_monitor);
|
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
|
* drm_add_edid_modes - add modes from EDID data, if available
|
||||||
* @connector: connector we're probing
|
* @connector: connector we're probing
|
||||||
|
|
|
@ -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,
|
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
||||||
void *data, struct drm_file *file_priv);
|
void *data, struct drm_file *file_priv);
|
||||||
extern bool drm_detect_hdmi_monitor(struct edid *edid);
|
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,
|
extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||||
void *data, struct drm_file *file_priv);
|
void *data, struct drm_file *file_priv);
|
||||||
extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
|
extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
|
||||||
|
|
Loading…
Reference in New Issue