drm/edid: Parse and handle HDMI deep color modes.
Check the HDMI cea block for deep color mode bits. If available, assign the highest supported bpc for a hdmi display, corresponding to the given deep color modes. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
89b92339c1
commit
d0c94692e0
2 changed files with 113 additions and 2 deletions
|
@ -3422,17 +3422,117 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_assign_hdmi_deep_color_info - detect whether monitor supports
|
||||||
|
* hdmi deep color modes and update drm_display_info if so.
|
||||||
|
*
|
||||||
|
* @edid: monitor EDID information
|
||||||
|
* @info: Updated with maximum supported deep color bpc and color format
|
||||||
|
* if deep color supported.
|
||||||
|
*
|
||||||
|
* Parse the CEA extension according to CEA-861-B.
|
||||||
|
* Return true if HDMI deep color supported, false if not or unknown.
|
||||||
|
*/
|
||||||
|
static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
|
||||||
|
struct drm_display_info *info,
|
||||||
|
struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
u8 *edid_ext, *hdmi;
|
||||||
|
int i;
|
||||||
|
int start_offset, end_offset;
|
||||||
|
unsigned int dc_bpc = 0;
|
||||||
|
|
||||||
|
edid_ext = drm_find_cea_extension(edid);
|
||||||
|
if (!edid_ext)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because HDMI identifier is in Vendor Specific Block,
|
||||||
|
* search it from all data blocks of CEA extension.
|
||||||
|
*/
|
||||||
|
for_each_cea_db(edid_ext, i, start_offset, end_offset) {
|
||||||
|
if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
|
||||||
|
/* HDMI supports at least 8 bpc */
|
||||||
|
info->bpc = 8;
|
||||||
|
|
||||||
|
hdmi = &edid_ext[i];
|
||||||
|
if (cea_db_payload_len(hdmi) < 6)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
|
||||||
|
dc_bpc = 10;
|
||||||
|
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
|
||||||
|
dc_bpc = 12;
|
||||||
|
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
|
||||||
|
dc_bpc = 16;
|
||||||
|
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dc_bpc > 0) {
|
||||||
|
DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
|
||||||
|
drm_get_connector_name(connector), dc_bpc);
|
||||||
|
info->bpc = dc_bpc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deep color support mandates RGB444 support for all video
|
||||||
|
* modes and forbids YCRCB422 support for all video modes per
|
||||||
|
* HDMI 1.3 spec.
|
||||||
|
*/
|
||||||
|
info->color_formats = DRM_COLOR_FORMAT_RGB444;
|
||||||
|
|
||||||
|
/* YCRCB444 is optional according to spec. */
|
||||||
|
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
|
||||||
|
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
||||||
|
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spec says that if any deep color mode is supported at all,
|
||||||
|
* then deep color 36 bit must be supported.
|
||||||
|
*/
|
||||||
|
if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
|
||||||
|
DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
|
||||||
|
drm_get_connector_name(connector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_add_display_info - pull display info out if present
|
* drm_add_display_info - pull display info out if present
|
||||||
* @edid: EDID data
|
* @edid: EDID data
|
||||||
* @info: display info (attached to connector)
|
* @info: display info (attached to connector)
|
||||||
|
* @connector: connector whose edid is used to build display info
|
||||||
*
|
*
|
||||||
* Grab any available display info and stuff it into the drm_display_info
|
* Grab any available display info and stuff it into the drm_display_info
|
||||||
* structure that's part of the connector. Useful for tracking bpp and
|
* structure that's part of the connector. Useful for tracking bpp and
|
||||||
* color spaces.
|
* color spaces.
|
||||||
*/
|
*/
|
||||||
static void drm_add_display_info(struct edid *edid,
|
static void drm_add_display_info(struct edid *edid,
|
||||||
struct drm_display_info *info)
|
struct drm_display_info *info,
|
||||||
|
struct drm_connector *connector)
|
||||||
{
|
{
|
||||||
u8 *edid_ext;
|
u8 *edid_ext;
|
||||||
|
|
||||||
|
@ -3462,6 +3562,9 @@ static void drm_add_display_info(struct edid *edid,
|
||||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* HDMI deep color modes supported? Assign to info, if so */
|
||||||
|
drm_assign_hdmi_deep_color_info(edid, info, connector);
|
||||||
|
|
||||||
/* Only defined for 1.4 with digital displays */
|
/* Only defined for 1.4 with digital displays */
|
||||||
if (edid->revision < 4)
|
if (edid->revision < 4)
|
||||||
return;
|
return;
|
||||||
|
@ -3491,6 +3594,9 @@ static void drm_add_display_info(struct edid *edid,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
|
||||||
|
drm_get_connector_name(connector), info->bpc);
|
||||||
|
|
||||||
info->color_formats |= DRM_COLOR_FORMAT_RGB444;
|
info->color_formats |= DRM_COLOR_FORMAT_RGB444;
|
||||||
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
|
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
|
||||||
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
|
||||||
|
@ -3549,7 +3655,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||||
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
||||||
edid_fixup_preferred(connector, quirks);
|
edid_fixup_preferred(connector, quirks);
|
||||||
|
|
||||||
drm_add_display_info(edid, &connector->display_info);
|
drm_add_display_info(edid, &connector->display_info, connector);
|
||||||
|
|
||||||
if (quirks & EDID_QUIRK_FORCE_8BPC)
|
if (quirks & EDID_QUIRK_FORCE_8BPC)
|
||||||
connector->display_info.bpc = 8;
|
connector->display_info.bpc = 8;
|
||||||
|
|
|
@ -202,6 +202,11 @@ struct detailed_timing {
|
||||||
#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6)
|
#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6)
|
||||||
#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7)
|
#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7)
|
||||||
|
|
||||||
|
#define DRM_EDID_HDMI_DC_48 (1 << 6)
|
||||||
|
#define DRM_EDID_HDMI_DC_36 (1 << 5)
|
||||||
|
#define DRM_EDID_HDMI_DC_30 (1 << 4)
|
||||||
|
#define DRM_EDID_HDMI_DC_Y444 (1 << 3)
|
||||||
|
|
||||||
struct edid {
|
struct edid {
|
||||||
u8 header[8];
|
u8 header[8];
|
||||||
/* Vendor & product info */
|
/* Vendor & product info */
|
||||||
|
|
Loading…
Add table
Reference in a new issue