Skip to content

Commit d0c9469

Browse files
kleinermalexdeucher
authored andcommitted
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 <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent 89b9233 commit d0c9469

File tree

2 files changed

+113
-2
lines changed

2 files changed

+113
-2
lines changed

drivers/gpu/drm/drm_edid.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3422,17 +3422,117 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
34223422
}
34233423
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
34243424

3425+
/**
3426+
* drm_assign_hdmi_deep_color_info - detect whether monitor supports
3427+
* hdmi deep color modes and update drm_display_info if so.
3428+
*
3429+
* @edid: monitor EDID information
3430+
* @info: Updated with maximum supported deep color bpc and color format
3431+
* if deep color supported.
3432+
*
3433+
* Parse the CEA extension according to CEA-861-B.
3434+
* Return true if HDMI deep color supported, false if not or unknown.
3435+
*/
3436+
static bool drm_assign_hdmi_deep_color_info(struct edid *edid,
3437+
struct drm_display_info *info,
3438+
struct drm_connector *connector)
3439+
{
3440+
u8 *edid_ext, *hdmi;
3441+
int i;
3442+
int start_offset, end_offset;
3443+
unsigned int dc_bpc = 0;
3444+
3445+
edid_ext = drm_find_cea_extension(edid);
3446+
if (!edid_ext)
3447+
return false;
3448+
3449+
if (cea_db_offsets(edid_ext, &start_offset, &end_offset))
3450+
return false;
3451+
3452+
/*
3453+
* Because HDMI identifier is in Vendor Specific Block,
3454+
* search it from all data blocks of CEA extension.
3455+
*/
3456+
for_each_cea_db(edid_ext, i, start_offset, end_offset) {
3457+
if (cea_db_is_hdmi_vsdb(&edid_ext[i])) {
3458+
/* HDMI supports at least 8 bpc */
3459+
info->bpc = 8;
3460+
3461+
hdmi = &edid_ext[i];
3462+
if (cea_db_payload_len(hdmi) < 6)
3463+
return false;
3464+
3465+
if (hdmi[6] & DRM_EDID_HDMI_DC_30) {
3466+
dc_bpc = 10;
3467+
DRM_DEBUG("%s: HDMI sink does deep color 30.\n",
3468+
drm_get_connector_name(connector));
3469+
}
3470+
3471+
if (hdmi[6] & DRM_EDID_HDMI_DC_36) {
3472+
dc_bpc = 12;
3473+
DRM_DEBUG("%s: HDMI sink does deep color 36.\n",
3474+
drm_get_connector_name(connector));
3475+
}
3476+
3477+
if (hdmi[6] & DRM_EDID_HDMI_DC_48) {
3478+
dc_bpc = 16;
3479+
DRM_DEBUG("%s: HDMI sink does deep color 48.\n",
3480+
drm_get_connector_name(connector));
3481+
}
3482+
3483+
if (dc_bpc > 0) {
3484+
DRM_DEBUG("%s: Assigning HDMI sink color depth as %d bpc.\n",
3485+
drm_get_connector_name(connector), dc_bpc);
3486+
info->bpc = dc_bpc;
3487+
3488+
/*
3489+
* Deep color support mandates RGB444 support for all video
3490+
* modes and forbids YCRCB422 support for all video modes per
3491+
* HDMI 1.3 spec.
3492+
*/
3493+
info->color_formats = DRM_COLOR_FORMAT_RGB444;
3494+
3495+
/* YCRCB444 is optional according to spec. */
3496+
if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) {
3497+
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
3498+
DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n",
3499+
drm_get_connector_name(connector));
3500+
}
3501+
3502+
/*
3503+
* Spec says that if any deep color mode is supported at all,
3504+
* then deep color 36 bit must be supported.
3505+
*/
3506+
if (!(hdmi[6] & DRM_EDID_HDMI_DC_36)) {
3507+
DRM_DEBUG("%s: HDMI sink should do DC_36, but does not!\n",
3508+
drm_get_connector_name(connector));
3509+
}
3510+
3511+
return true;
3512+
}
3513+
else {
3514+
DRM_DEBUG("%s: No deep color support on this HDMI sink.\n",
3515+
drm_get_connector_name(connector));
3516+
}
3517+
}
3518+
}
3519+
3520+
return false;
3521+
}
3522+
34253523
/**
34263524
* drm_add_display_info - pull display info out if present
34273525
* @edid: EDID data
34283526
* @info: display info (attached to connector)
3527+
* @connector: connector whose edid is used to build display info
34293528
*
34303529
* Grab any available display info and stuff it into the drm_display_info
34313530
* structure that's part of the connector. Useful for tracking bpp and
34323531
* color spaces.
34333532
*/
34343533
static void drm_add_display_info(struct edid *edid,
3435-
struct drm_display_info *info)
3534+
struct drm_display_info *info,
3535+
struct drm_connector *connector)
34363536
{
34373537
u8 *edid_ext;
34383538

@@ -3462,6 +3562,9 @@ static void drm_add_display_info(struct edid *edid,
34623562
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
34633563
}
34643564

3565+
/* HDMI deep color modes supported? Assign to info, if so */
3566+
drm_assign_hdmi_deep_color_info(edid, info, connector);
3567+
34653568
/* Only defined for 1.4 with digital displays */
34663569
if (edid->revision < 4)
34673570
return;
@@ -3491,6 +3594,9 @@ static void drm_add_display_info(struct edid *edid,
34913594
break;
34923595
}
34933596

3597+
DRM_DEBUG("%s: Assigning EDID-1.4 digital sink color depth as %d bpc.\n",
3598+
drm_get_connector_name(connector), info->bpc);
3599+
34943600
info->color_formats |= DRM_COLOR_FORMAT_RGB444;
34953601
if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
34963602
info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
@@ -3549,7 +3655,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
35493655
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
35503656
edid_fixup_preferred(connector, quirks);
35513657

3552-
drm_add_display_info(edid, &connector->display_info);
3658+
drm_add_display_info(edid, &connector->display_info, connector);
35533659

35543660
if (quirks & EDID_QUIRK_FORCE_8BPC)
35553661
connector->display_info.bpc = 8;

include/drm/drm_edid.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ struct detailed_timing {
202202
#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6)
203203
#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7)
204204

205+
#define DRM_EDID_HDMI_DC_48 (1 << 6)
206+
#define DRM_EDID_HDMI_DC_36 (1 << 5)
207+
#define DRM_EDID_HDMI_DC_30 (1 << 4)
208+
#define DRM_EDID_HDMI_DC_Y444 (1 << 3)
209+
205210
struct edid {
206211
u8 header[8];
207212
/* Vendor & product info */

0 commit comments

Comments
 (0)