diff options
author | Mario Kleiner <mario.kleiner.de@gmail.com> | 2014-03-27 14:59:39 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2014-06-02 18:37:34 -0400 |
commit | d0c94692e0a360828745a469bcf90b5c4f9273d0 (patch) | |
tree | 80cf5a1317b3318b1dfdac117fca60ee28245947 /drivers/gpu/drm/drm_edid.c | |
parent | 89b92339c1362ee910b0c73c2db32af11246c250 (diff) |
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>
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 110 |
1 files changed, 108 insertions, 2 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d74239fec291..3989c185579f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -3423,16 +3423,116 @@ bool drm_rgb_quant_range_selectable(struct edid *edid) | |||
3423 | EXPORT_SYMBOL(drm_rgb_quant_range_selectable); | 3423 | EXPORT_SYMBOL(drm_rgb_quant_range_selectable); |
3424 | 3424 | ||
3425 | /** | 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 | |||
3523 | /** | ||
3426 | * drm_add_display_info - pull display info out if present | 3524 | * drm_add_display_info - pull display info out if present |
3427 | * @edid: EDID data | 3525 | * @edid: EDID data |
3428 | * @info: display info (attached to connector) | 3526 | * @info: display info (attached to connector) |
3527 | * @connector: connector whose edid is used to build display info | ||
3429 | * | 3528 | * |
3430 | * Grab any available display info and stuff it into the drm_display_info | 3529 | * Grab any available display info and stuff it into the drm_display_info |
3431 | * structure that's part of the connector. Useful for tracking bpp and | 3530 | * structure that's part of the connector. Useful for tracking bpp and |
3432 | * color spaces. | 3531 | * color spaces. |
3433 | */ | 3532 | */ |
3434 | static void drm_add_display_info(struct edid *edid, | 3533 | 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) | ||
3436 | { | 3536 | { |
3437 | u8 *edid_ext; | 3537 | u8 *edid_ext; |
3438 | 3538 | ||
@@ -3462,6 +3562,9 @@ static void drm_add_display_info(struct edid *edid, | |||
3462 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | 3562 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; |
3463 | } | 3563 | } |
3464 | 3564 | ||
3565 | /* HDMI deep color modes supported? Assign to info, if so */ | ||
3566 | drm_assign_hdmi_deep_color_info(edid, info, connector); | ||
3567 | |||
3465 | /* Only defined for 1.4 with digital displays */ | 3568 | /* Only defined for 1.4 with digital displays */ |
3466 | if (edid->revision < 4) | 3569 | if (edid->revision < 4) |
3467 | return; | 3570 | return; |
@@ -3491,6 +3594,9 @@ static void drm_add_display_info(struct edid *edid, | |||
3491 | break; | 3594 | break; |
3492 | } | 3595 | } |
3493 | 3596 | ||
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 | |||
3494 | info->color_formats |= DRM_COLOR_FORMAT_RGB444; | 3600 | info->color_formats |= DRM_COLOR_FORMAT_RGB444; |
3495 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) | 3601 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) |
3496 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | 3602 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; |
@@ -3549,7 +3655,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
3549 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | 3655 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
3550 | edid_fixup_preferred(connector, quirks); | 3656 | edid_fixup_preferred(connector, quirks); |
3551 | 3657 | ||
3552 | drm_add_display_info(edid, &connector->display_info); | 3658 | drm_add_display_info(edid, &connector->display_info, connector); |
3553 | 3659 | ||
3554 | if (quirks & EDID_QUIRK_FORCE_8BPC) | 3660 | if (quirks & EDID_QUIRK_FORCE_8BPC) |
3555 | connector->display_info.bpc = 8; | 3661 | connector->display_info.bpc = 8; |