diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 104 |
1 files changed, 70 insertions, 34 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5dfe14763871..524eace3d460 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -3398,6 +3398,7 @@ static int | |||
3398 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, | 3398 | do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, |
3399 | const u8 *video_db, u8 video_len) | 3399 | const u8 *video_db, u8 video_len) |
3400 | { | 3400 | { |
3401 | struct drm_display_info *info = &connector->display_info; | ||
3401 | int modes = 0, offset = 0, i, multi_present = 0, multi_len; | 3402 | int modes = 0, offset = 0, i, multi_present = 0, multi_len; |
3402 | u8 vic_len, hdmi_3d_len = 0; | 3403 | u8 vic_len, hdmi_3d_len = 0; |
3403 | u16 mask; | 3404 | u16 mask; |
@@ -3525,6 +3526,8 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len, | |||
3525 | } | 3526 | } |
3526 | 3527 | ||
3527 | out: | 3528 | out: |
3529 | if (modes > 0) | ||
3530 | info->has_hdmi_infoframe = true; | ||
3528 | return modes; | 3531 | return modes; |
3529 | } | 3532 | } |
3530 | 3533 | ||
@@ -3761,8 +3764,8 @@ drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db) | |||
3761 | { | 3764 | { |
3762 | u8 len = cea_db_payload_len(db); | 3765 | u8 len = cea_db_payload_len(db); |
3763 | 3766 | ||
3764 | if (len >= 6) | 3767 | if (len >= 6 && (db[6] & (1 << 7))) |
3765 | connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ | 3768 | connector->eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_SUPPORTS_AI; |
3766 | if (len >= 8) { | 3769 | if (len >= 8) { |
3767 | connector->latency_present[0] = db[8] >> 7; | 3770 | connector->latency_present[0] = db[8] >> 7; |
3768 | connector->latency_present[1] = (db[8] >> 6) & 1; | 3771 | connector->latency_present[1] = (db[8] >> 6) & 1; |
@@ -3834,16 +3837,27 @@ void drm_edid_get_monitor_name(struct edid *edid, char *name, int bufsize) | |||
3834 | } | 3837 | } |
3835 | EXPORT_SYMBOL(drm_edid_get_monitor_name); | 3838 | EXPORT_SYMBOL(drm_edid_get_monitor_name); |
3836 | 3839 | ||
3837 | /** | 3840 | static void clear_eld(struct drm_connector *connector) |
3841 | { | ||
3842 | memset(connector->eld, 0, sizeof(connector->eld)); | ||
3843 | |||
3844 | connector->latency_present[0] = false; | ||
3845 | connector->latency_present[1] = false; | ||
3846 | connector->video_latency[0] = 0; | ||
3847 | connector->audio_latency[0] = 0; | ||
3848 | connector->video_latency[1] = 0; | ||
3849 | connector->audio_latency[1] = 0; | ||
3850 | } | ||
3851 | |||
3852 | /* | ||
3838 | * drm_edid_to_eld - build ELD from EDID | 3853 | * drm_edid_to_eld - build ELD from EDID |
3839 | * @connector: connector corresponding to the HDMI/DP sink | 3854 | * @connector: connector corresponding to the HDMI/DP sink |
3840 | * @edid: EDID to parse | 3855 | * @edid: EDID to parse |
3841 | * | 3856 | * |
3842 | * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The | 3857 | * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The |
3843 | * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to | 3858 | * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. |
3844 | * fill in. | ||
3845 | */ | 3859 | */ |
3846 | void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | 3860 | static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) |
3847 | { | 3861 | { |
3848 | uint8_t *eld = connector->eld; | 3862 | uint8_t *eld = connector->eld; |
3849 | u8 *cea; | 3863 | u8 *cea; |
@@ -3852,14 +3866,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3852 | int mnl; | 3866 | int mnl; |
3853 | int dbl; | 3867 | int dbl; |
3854 | 3868 | ||
3855 | memset(eld, 0, sizeof(connector->eld)); | 3869 | clear_eld(connector); |
3856 | |||
3857 | connector->latency_present[0] = false; | ||
3858 | connector->latency_present[1] = false; | ||
3859 | connector->video_latency[0] = 0; | ||
3860 | connector->audio_latency[0] = 0; | ||
3861 | connector->video_latency[1] = 0; | ||
3862 | connector->audio_latency[1] = 0; | ||
3863 | 3870 | ||
3864 | if (!edid) | 3871 | if (!edid) |
3865 | return; | 3872 | return; |
@@ -3870,17 +3877,18 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3870 | return; | 3877 | return; |
3871 | } | 3878 | } |
3872 | 3879 | ||
3873 | mnl = get_monitor_name(edid, eld + 20); | 3880 | mnl = get_monitor_name(edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); |
3881 | DRM_DEBUG_KMS("ELD monitor %s\n", &eld[DRM_ELD_MONITOR_NAME_STRING]); | ||
3874 | 3882 | ||
3875 | eld[4] = (cea[1] << 5) | mnl; | 3883 | eld[DRM_ELD_CEA_EDID_VER_MNL] = cea[1] << DRM_ELD_CEA_EDID_VER_SHIFT; |
3876 | DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20); | 3884 | eld[DRM_ELD_CEA_EDID_VER_MNL] |= mnl; |
3877 | 3885 | ||
3878 | eld[0] = 2 << 3; /* ELD version: 2 */ | 3886 | eld[DRM_ELD_VER] = DRM_ELD_VER_CEA861D; |
3879 | 3887 | ||
3880 | eld[16] = edid->mfg_id[0]; | 3888 | eld[DRM_ELD_MANUFACTURER_NAME0] = edid->mfg_id[0]; |
3881 | eld[17] = edid->mfg_id[1]; | 3889 | eld[DRM_ELD_MANUFACTURER_NAME1] = edid->mfg_id[1]; |
3882 | eld[18] = edid->prod_code[0]; | 3890 | eld[DRM_ELD_PRODUCT_CODE0] = edid->prod_code[0]; |
3883 | eld[19] = edid->prod_code[1]; | 3891 | eld[DRM_ELD_PRODUCT_CODE1] = edid->prod_code[1]; |
3884 | 3892 | ||
3885 | if (cea_revision(cea) >= 3) { | 3893 | if (cea_revision(cea) >= 3) { |
3886 | int i, start, end; | 3894 | int i, start, end; |
@@ -3901,14 +3909,14 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3901 | /* Audio Data Block, contains SADs */ | 3909 | /* Audio Data Block, contains SADs */ |
3902 | sad_count = min(dbl / 3, 15 - total_sad_count); | 3910 | sad_count = min(dbl / 3, 15 - total_sad_count); |
3903 | if (sad_count >= 1) | 3911 | if (sad_count >= 1) |
3904 | memcpy(eld + 20 + mnl + total_sad_count * 3, | 3912 | memcpy(&eld[DRM_ELD_CEA_SAD(mnl, total_sad_count)], |
3905 | &db[1], sad_count * 3); | 3913 | &db[1], sad_count * 3); |
3906 | total_sad_count += sad_count; | 3914 | total_sad_count += sad_count; |
3907 | break; | 3915 | break; |
3908 | case SPEAKER_BLOCK: | 3916 | case SPEAKER_BLOCK: |
3909 | /* Speaker Allocation Data Block */ | 3917 | /* Speaker Allocation Data Block */ |
3910 | if (dbl >= 1) | 3918 | if (dbl >= 1) |
3911 | eld[7] = db[1]; | 3919 | eld[DRM_ELD_SPEAKER] = db[1]; |
3912 | break; | 3920 | break; |
3913 | case VENDOR_BLOCK: | 3921 | case VENDOR_BLOCK: |
3914 | /* HDMI Vendor-Specific Data Block */ | 3922 | /* HDMI Vendor-Specific Data Block */ |
@@ -3920,7 +3928,13 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3920 | } | 3928 | } |
3921 | } | 3929 | } |
3922 | } | 3930 | } |
3923 | eld[5] |= total_sad_count << 4; | 3931 | eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= total_sad_count << DRM_ELD_SAD_COUNT_SHIFT; |
3932 | |||
3933 | if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || | ||
3934 | connector->connector_type == DRM_MODE_CONNECTOR_eDP) | ||
3935 | eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP; | ||
3936 | else | ||
3937 | eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI; | ||
3924 | 3938 | ||
3925 | eld[DRM_ELD_BASELINE_ELD_LEN] = | 3939 | eld[DRM_ELD_BASELINE_ELD_LEN] = |
3926 | DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); | 3940 | DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); |
@@ -3928,7 +3942,6 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) | |||
3928 | DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", | 3942 | DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", |
3929 | drm_eld_size(eld), total_sad_count); | 3943 | drm_eld_size(eld), total_sad_count); |
3930 | } | 3944 | } |
3931 | EXPORT_SYMBOL(drm_edid_to_eld); | ||
3932 | 3945 | ||
3933 | /** | 3946 | /** |
3934 | * drm_edid_to_sad - extracts SADs from EDID | 3947 | * drm_edid_to_sad - extracts SADs from EDID |
@@ -4238,6 +4251,8 @@ static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector, | |||
4238 | struct drm_display_info *display = &connector->display_info; | 4251 | struct drm_display_info *display = &connector->display_info; |
4239 | struct drm_hdmi_info *hdmi = &display->hdmi; | 4252 | struct drm_hdmi_info *hdmi = &display->hdmi; |
4240 | 4253 | ||
4254 | display->has_hdmi_infoframe = true; | ||
4255 | |||
4241 | if (hf_vsdb[6] & 0x80) { | 4256 | if (hf_vsdb[6] & 0x80) { |
4242 | hdmi->scdc.supported = true; | 4257 | hdmi->scdc.supported = true; |
4243 | if (hf_vsdb[6] & 0x40) | 4258 | if (hf_vsdb[6] & 0x40) |
@@ -4411,6 +4426,7 @@ static void drm_add_display_info(struct drm_connector *connector, | |||
4411 | info->cea_rev = 0; | 4426 | info->cea_rev = 0; |
4412 | info->max_tmds_clock = 0; | 4427 | info->max_tmds_clock = 0; |
4413 | info->dvi_dual = false; | 4428 | info->dvi_dual = false; |
4429 | info->has_hdmi_infoframe = false; | ||
4414 | 4430 | ||
4415 | info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); | 4431 | info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); |
4416 | 4432 | ||
@@ -4608,8 +4624,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, | |||
4608 | * @edid: EDID data | 4624 | * @edid: EDID data |
4609 | * | 4625 | * |
4610 | * Add the specified modes to the connector's mode list. Also fills out the | 4626 | * Add the specified modes to the connector's mode list. Also fills out the |
4611 | * &drm_display_info structure in @connector with any information which can be | 4627 | * &drm_display_info structure and ELD in @connector with any information which |
4612 | * derived from the edid. | 4628 | * can be derived from the edid. |
4613 | * | 4629 | * |
4614 | * Return: The number of modes added or 0 if we couldn't find any. | 4630 | * Return: The number of modes added or 0 if we couldn't find any. |
4615 | */ | 4631 | */ |
@@ -4619,9 +4635,11 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
4619 | u32 quirks; | 4635 | u32 quirks; |
4620 | 4636 | ||
4621 | if (edid == NULL) { | 4637 | if (edid == NULL) { |
4638 | clear_eld(connector); | ||
4622 | return 0; | 4639 | return 0; |
4623 | } | 4640 | } |
4624 | if (!drm_edid_is_valid(edid)) { | 4641 | if (!drm_edid_is_valid(edid)) { |
4642 | clear_eld(connector); | ||
4625 | dev_warn(connector->dev->dev, "%s: EDID invalid.\n", | 4643 | dev_warn(connector->dev->dev, "%s: EDID invalid.\n", |
4626 | connector->name); | 4644 | connector->name); |
4627 | return 0; | 4645 | return 0; |
@@ -4629,6 +4647,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
4629 | 4647 | ||
4630 | quirks = edid_get_quirks(edid); | 4648 | quirks = edid_get_quirks(edid); |
4631 | 4649 | ||
4650 | drm_edid_to_eld(connector, edid); | ||
4651 | |||
4632 | /* | 4652 | /* |
4633 | * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. | 4653 | * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks. |
4634 | * To avoid multiple parsing of same block, lets parse that map | 4654 | * To avoid multiple parsing of same block, lets parse that map |
@@ -4904,6 +4924,7 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) | |||
4904 | * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with | 4924 | * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with |
4905 | * data from a DRM display mode | 4925 | * data from a DRM display mode |
4906 | * @frame: HDMI vendor infoframe | 4926 | * @frame: HDMI vendor infoframe |
4927 | * @connector: the connector | ||
4907 | * @mode: DRM display mode | 4928 | * @mode: DRM display mode |
4908 | * | 4929 | * |
4909 | * Note that there's is a need to send HDMI vendor infoframes only when using a | 4930 | * Note that there's is a need to send HDMI vendor infoframes only when using a |
@@ -4914,8 +4935,15 @@ s3d_structure_from_display_mode(const struct drm_display_mode *mode) | |||
4914 | */ | 4935 | */ |
4915 | int | 4936 | int |
4916 | drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | 4937 | drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, |
4938 | struct drm_connector *connector, | ||
4917 | const struct drm_display_mode *mode) | 4939 | const struct drm_display_mode *mode) |
4918 | { | 4940 | { |
4941 | /* | ||
4942 | * FIXME: sil-sii8620 doesn't have a connector around when | ||
4943 | * we need one, so we have to be prepared for a NULL connector. | ||
4944 | */ | ||
4945 | bool has_hdmi_infoframe = connector ? | ||
4946 | connector->display_info.has_hdmi_infoframe : false; | ||
4919 | int err; | 4947 | int err; |
4920 | u32 s3d_flags; | 4948 | u32 s3d_flags; |
4921 | u8 vic; | 4949 | u8 vic; |
@@ -4923,11 +4951,21 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | |||
4923 | if (!frame || !mode) | 4951 | if (!frame || !mode) |
4924 | return -EINVAL; | 4952 | return -EINVAL; |
4925 | 4953 | ||
4954 | if (!has_hdmi_infoframe) | ||
4955 | return -EINVAL; | ||
4956 | |||
4926 | vic = drm_match_hdmi_mode(mode); | 4957 | vic = drm_match_hdmi_mode(mode); |
4927 | s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; | 4958 | s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; |
4928 | 4959 | ||
4929 | if (!vic && !s3d_flags) | 4960 | /* |
4930 | return -EINVAL; | 4961 | * Even if it's not absolutely necessary to send the infoframe |
4962 | * (ie.vic==0 and s3d_struct==0) we will still send it if we | ||
4963 | * know that the sink can handle it. This is based on a | ||
4964 | * suggestion in HDMI 2.0 Appendix F. Apparently some sinks | ||
4965 | * have trouble realizing that they shuld switch from 3D to 2D | ||
4966 | * mode if the source simply stops sending the infoframe when | ||
4967 | * it wants to switch from 3D to 2D. | ||
4968 | */ | ||
4931 | 4969 | ||
4932 | if (vic && s3d_flags) | 4970 | if (vic && s3d_flags) |
4933 | return -EINVAL; | 4971 | return -EINVAL; |
@@ -4936,10 +4974,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | |||
4936 | if (err < 0) | 4974 | if (err < 0) |
4937 | return err; | 4975 | return err; |
4938 | 4976 | ||
4939 | if (vic) | 4977 | frame->vic = vic; |
4940 | frame->vic = vic; | 4978 | frame->s3d_struct = s3d_structure_from_display_mode(mode); |
4941 | else | ||
4942 | frame->s3d_struct = s3d_structure_from_display_mode(mode); | ||
4943 | 4979 | ||
4944 | return 0; | 4980 | return 0; |
4945 | } | 4981 | } |