diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sdvo.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 219 |
1 files changed, 90 insertions, 129 deletions
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a84224f3760..de158b76bcd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -107,6 +107,7 @@ struct intel_sdvo { | |||
107 | * This is set if we treat the device as HDMI, instead of DVI. | 107 | * This is set if we treat the device as HDMI, instead of DVI. |
108 | */ | 108 | */ |
109 | bool is_hdmi; | 109 | bool is_hdmi; |
110 | bool has_audio; | ||
110 | 111 | ||
111 | /** | 112 | /** |
112 | * This is set if we detect output of sdvo device as LVDS and | 113 | * This is set if we detect output of sdvo device as LVDS and |
@@ -119,12 +120,6 @@ struct intel_sdvo { | |||
119 | */ | 120 | */ |
120 | struct drm_display_mode *sdvo_lvds_fixed_mode; | 121 | struct drm_display_mode *sdvo_lvds_fixed_mode; |
121 | 122 | ||
122 | /* | ||
123 | * supported encoding mode, used to determine whether HDMI is | ||
124 | * supported | ||
125 | */ | ||
126 | struct intel_sdvo_encode encode; | ||
127 | |||
128 | /* DDC bus used by this SDVO encoder */ | 123 | /* DDC bus used by this SDVO encoder */ |
129 | uint8_t ddc_bus; | 124 | uint8_t ddc_bus; |
130 | 125 | ||
@@ -138,11 +133,15 @@ struct intel_sdvo_connector { | |||
138 | /* Mark the type of connector */ | 133 | /* Mark the type of connector */ |
139 | uint16_t output_flag; | 134 | uint16_t output_flag; |
140 | 135 | ||
136 | int force_audio; | ||
137 | |||
141 | /* This contains all current supported TV format */ | 138 | /* This contains all current supported TV format */ |
142 | u8 tv_format_supported[TV_FORMAT_NUM]; | 139 | u8 tv_format_supported[TV_FORMAT_NUM]; |
143 | int format_supported_num; | 140 | int format_supported_num; |
144 | struct drm_property *tv_format; | 141 | struct drm_property *tv_format; |
145 | 142 | ||
143 | struct drm_property *force_audio_property; | ||
144 | |||
146 | /* add the property for the SDVO-TV */ | 145 | /* add the property for the SDVO-TV */ |
147 | struct drm_property *left; | 146 | struct drm_property *left; |
148 | struct drm_property *right; | 147 | struct drm_property *right; |
@@ -794,17 +793,13 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, | |||
794 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | 793 | mode->flags |= DRM_MODE_FLAG_PVSYNC; |
795 | } | 794 | } |
796 | 795 | ||
797 | static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo, | 796 | static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo) |
798 | struct intel_sdvo_encode *encode) | ||
799 | { | 797 | { |
800 | if (intel_sdvo_get_value(intel_sdvo, | 798 | struct intel_sdvo_encode encode; |
801 | SDVO_CMD_GET_SUPP_ENCODE, | ||
802 | encode, sizeof(*encode))) | ||
803 | return true; | ||
804 | 799 | ||
805 | /* non-support means DVI */ | 800 | return intel_sdvo_get_value(intel_sdvo, |
806 | memset(encode, 0, sizeof(*encode)); | 801 | SDVO_CMD_GET_SUPP_ENCODE, |
807 | return false; | 802 | &encode, sizeof(encode)); |
808 | } | 803 | } |
809 | 804 | ||
810 | static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, | 805 | static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, |
@@ -849,115 +844,33 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) | |||
849 | } | 844 | } |
850 | #endif | 845 | #endif |
851 | 846 | ||
852 | static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, | 847 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) |
853 | int index, | ||
854 | uint8_t *data, int8_t size, uint8_t tx_rate) | ||
855 | { | ||
856 | uint8_t set_buf_index[2]; | ||
857 | |||
858 | set_buf_index[0] = index; | ||
859 | set_buf_index[1] = 0; | ||
860 | |||
861 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, | ||
862 | set_buf_index, 2)) | ||
863 | return false; | ||
864 | |||
865 | for (; size > 0; size -= 8) { | ||
866 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) | ||
867 | return false; | ||
868 | |||
869 | data += 8; | ||
870 | } | ||
871 | |||
872 | return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); | ||
873 | } | ||
874 | |||
875 | static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) | ||
876 | { | ||
877 | uint8_t csum = 0; | ||
878 | int i; | ||
879 | |||
880 | for (i = 0; i < size; i++) | ||
881 | csum += data[i]; | ||
882 | |||
883 | return 0x100 - csum; | ||
884 | } | ||
885 | |||
886 | #define DIP_TYPE_AVI 0x82 | ||
887 | #define DIP_VERSION_AVI 0x2 | ||
888 | #define DIP_LEN_AVI 13 | ||
889 | |||
890 | struct dip_infoframe { | ||
891 | uint8_t type; | ||
892 | uint8_t version; | ||
893 | uint8_t len; | ||
894 | uint8_t checksum; | ||
895 | union { | ||
896 | struct { | ||
897 | /* Packet Byte #1 */ | ||
898 | uint8_t S:2; | ||
899 | uint8_t B:2; | ||
900 | uint8_t A:1; | ||
901 | uint8_t Y:2; | ||
902 | uint8_t rsvd1:1; | ||
903 | /* Packet Byte #2 */ | ||
904 | uint8_t R:4; | ||
905 | uint8_t M:2; | ||
906 | uint8_t C:2; | ||
907 | /* Packet Byte #3 */ | ||
908 | uint8_t SC:2; | ||
909 | uint8_t Q:2; | ||
910 | uint8_t EC:3; | ||
911 | uint8_t ITC:1; | ||
912 | /* Packet Byte #4 */ | ||
913 | uint8_t VIC:7; | ||
914 | uint8_t rsvd2:1; | ||
915 | /* Packet Byte #5 */ | ||
916 | uint8_t PR:4; | ||
917 | uint8_t rsvd3:4; | ||
918 | /* Packet Byte #6~13 */ | ||
919 | uint16_t top_bar_end; | ||
920 | uint16_t bottom_bar_start; | ||
921 | uint16_t left_bar_end; | ||
922 | uint16_t right_bar_start; | ||
923 | } avi; | ||
924 | struct { | ||
925 | /* Packet Byte #1 */ | ||
926 | uint8_t channel_count:3; | ||
927 | uint8_t rsvd1:1; | ||
928 | uint8_t coding_type:4; | ||
929 | /* Packet Byte #2 */ | ||
930 | uint8_t sample_size:2; /* SS0, SS1 */ | ||
931 | uint8_t sample_frequency:3; | ||
932 | uint8_t rsvd2:3; | ||
933 | /* Packet Byte #3 */ | ||
934 | uint8_t coding_type_private:5; | ||
935 | uint8_t rsvd3:3; | ||
936 | /* Packet Byte #4 */ | ||
937 | uint8_t channel_allocation; | ||
938 | /* Packet Byte #5 */ | ||
939 | uint8_t rsvd4:3; | ||
940 | uint8_t level_shift:4; | ||
941 | uint8_t downmix_inhibit:1; | ||
942 | } audio; | ||
943 | uint8_t payload[28]; | ||
944 | } __attribute__ ((packed)) u; | ||
945 | } __attribute__((packed)); | ||
946 | |||
947 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, | ||
948 | struct drm_display_mode * mode) | ||
949 | { | 848 | { |
950 | struct dip_infoframe avi_if = { | 849 | struct dip_infoframe avi_if = { |
951 | .type = DIP_TYPE_AVI, | 850 | .type = DIP_TYPE_AVI, |
952 | .version = DIP_VERSION_AVI, | 851 | .ver = DIP_VERSION_AVI, |
953 | .len = DIP_LEN_AVI, | 852 | .len = DIP_LEN_AVI, |
954 | }; | 853 | }; |
854 | uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; | ||
855 | uint8_t set_buf_index[2] = { 1, 0 }; | ||
856 | uint64_t *data = (uint64_t *)&avi_if; | ||
857 | unsigned i; | ||
858 | |||
859 | intel_dip_infoframe_csum(&avi_if); | ||
860 | |||
861 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, | ||
862 | set_buf_index, 2)) | ||
863 | return false; | ||
955 | 864 | ||
956 | avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, | 865 | for (i = 0; i < sizeof(avi_if); i += 8) { |
957 | 4 + avi_if.len); | 866 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, |
958 | return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, | 867 | data, 8)) |
959 | 4 + avi_if.len, | 868 | return false; |
960 | SDVO_HBUF_TX_VSYNC); | 869 | data++; |
870 | } | ||
871 | |||
872 | return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, | ||
873 | &tx_rate, 1); | ||
961 | } | 874 | } |
962 | 875 | ||
963 | static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) | 876 | static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) |
@@ -1111,7 +1024,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, | |||
1111 | return; | 1024 | return; |
1112 | 1025 | ||
1113 | if (intel_sdvo->is_hdmi && | 1026 | if (intel_sdvo->is_hdmi && |
1114 | !intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) | 1027 | !intel_sdvo_set_avi_infoframe(intel_sdvo)) |
1115 | return; | 1028 | return; |
1116 | 1029 | ||
1117 | if (intel_sdvo->is_tv && | 1030 | if (intel_sdvo->is_tv && |
@@ -1150,7 +1063,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, | |||
1150 | } | 1063 | } |
1151 | if (intel_crtc->pipe == 1) | 1064 | if (intel_crtc->pipe == 1) |
1152 | sdvox |= SDVO_PIPE_B_SELECT; | 1065 | sdvox |= SDVO_PIPE_B_SELECT; |
1153 | if (intel_sdvo->is_hdmi) | 1066 | if (intel_sdvo->has_audio) |
1154 | sdvox |= SDVO_AUDIO_ENABLE; | 1067 | sdvox |= SDVO_AUDIO_ENABLE; |
1155 | 1068 | ||
1156 | if (INTEL_INFO(dev)->gen >= 4) { | 1069 | if (INTEL_INFO(dev)->gen >= 4) { |
@@ -1476,11 +1389,18 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) | |||
1476 | if (edid->input & DRM_EDID_INPUT_DIGITAL) { | 1389 | if (edid->input & DRM_EDID_INPUT_DIGITAL) { |
1477 | status = connector_status_connected; | 1390 | status = connector_status_connected; |
1478 | intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); | 1391 | intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); |
1392 | intel_sdvo->has_audio = drm_detect_monitor_audio(edid); | ||
1479 | } | 1393 | } |
1480 | connector->display_info.raw_edid = NULL; | 1394 | connector->display_info.raw_edid = NULL; |
1481 | kfree(edid); | 1395 | kfree(edid); |
1482 | } | 1396 | } |
1483 | 1397 | ||
1398 | if (status == connector_status_connected) { | ||
1399 | struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); | ||
1400 | if (intel_sdvo_connector->force_audio) | ||
1401 | intel_sdvo->has_audio = intel_sdvo_connector->force_audio > 0; | ||
1402 | } | ||
1403 | |||
1484 | return status; | 1404 | return status; |
1485 | } | 1405 | } |
1486 | 1406 | ||
@@ -1787,6 +1707,21 @@ intel_sdvo_set_property(struct drm_connector *connector, | |||
1787 | if (ret) | 1707 | if (ret) |
1788 | return ret; | 1708 | return ret; |
1789 | 1709 | ||
1710 | if (property == intel_sdvo_connector->force_audio_property) { | ||
1711 | if (val == intel_sdvo_connector->force_audio) | ||
1712 | return 0; | ||
1713 | |||
1714 | intel_sdvo_connector->force_audio = val; | ||
1715 | |||
1716 | if (val > 0 && intel_sdvo->has_audio) | ||
1717 | return 0; | ||
1718 | if (val < 0 && !intel_sdvo->has_audio) | ||
1719 | return 0; | ||
1720 | |||
1721 | intel_sdvo->has_audio = val > 0; | ||
1722 | goto done; | ||
1723 | } | ||
1724 | |||
1790 | #define CHECK_PROPERTY(name, NAME) \ | 1725 | #define CHECK_PROPERTY(name, NAME) \ |
1791 | if (intel_sdvo_connector->name == property) { \ | 1726 | if (intel_sdvo_connector->name == property) { \ |
1792 | if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ | 1727 | if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ |
@@ -2013,12 +1948,22 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, | |||
2013 | } | 1948 | } |
2014 | 1949 | ||
2015 | static bool | 1950 | static bool |
2016 | intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) | 1951 | intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device) |
2017 | { | 1952 | { |
2018 | return intel_sdvo_set_target_output(intel_sdvo, | 1953 | int is_hdmi; |
2019 | device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) && | 1954 | |
2020 | intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, | 1955 | if (!intel_sdvo_check_supp_encode(intel_sdvo)) |
2021 | &intel_sdvo->is_hdmi, 1); | 1956 | return false; |
1957 | |||
1958 | if (!intel_sdvo_set_target_output(intel_sdvo, | ||
1959 | device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1)) | ||
1960 | return false; | ||
1961 | |||
1962 | is_hdmi = 0; | ||
1963 | if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1)) | ||
1964 | return false; | ||
1965 | |||
1966 | return !!is_hdmi; | ||
2022 | } | 1967 | } |
2023 | 1968 | ||
2024 | static u8 | 1969 | static u8 |
@@ -2078,6 +2023,21 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, | |||
2078 | drm_sysfs_connector_add(&connector->base.base); | 2023 | drm_sysfs_connector_add(&connector->base.base); |
2079 | } | 2024 | } |
2080 | 2025 | ||
2026 | static void | ||
2027 | intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) | ||
2028 | { | ||
2029 | struct drm_device *dev = connector->base.base.dev; | ||
2030 | |||
2031 | connector->force_audio_property = | ||
2032 | drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2); | ||
2033 | if (connector->force_audio_property) { | ||
2034 | connector->force_audio_property->values[0] = -1; | ||
2035 | connector->force_audio_property->values[1] = 1; | ||
2036 | drm_connector_attach_property(&connector->base.base, | ||
2037 | connector->force_audio_property, 0); | ||
2038 | } | ||
2039 | } | ||
2040 | |||
2081 | static bool | 2041 | static bool |
2082 | intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) | 2042 | intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) |
2083 | { | 2043 | { |
@@ -2104,20 +2064,21 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) | |||
2104 | encoder->encoder_type = DRM_MODE_ENCODER_TMDS; | 2064 | encoder->encoder_type = DRM_MODE_ENCODER_TMDS; |
2105 | connector->connector_type = DRM_MODE_CONNECTOR_DVID; | 2065 | connector->connector_type = DRM_MODE_CONNECTOR_DVID; |
2106 | 2066 | ||
2107 | if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode) | 2067 | if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { |
2108 | && intel_sdvo_get_digital_encoding_mode(intel_sdvo, device) | ||
2109 | && intel_sdvo->is_hdmi) { | ||
2110 | /* enable hdmi encoding mode if supported */ | 2068 | /* enable hdmi encoding mode if supported */ |
2111 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); | 2069 | intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); |
2112 | intel_sdvo_set_colorimetry(intel_sdvo, | 2070 | intel_sdvo_set_colorimetry(intel_sdvo, |
2113 | SDVO_COLORIMETRY_RGB256); | 2071 | SDVO_COLORIMETRY_RGB256); |
2114 | connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; | 2072 | connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; |
2073 | intel_sdvo->is_hdmi = true; | ||
2115 | } | 2074 | } |
2116 | intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | | 2075 | intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | |
2117 | (1 << INTEL_ANALOG_CLONE_BIT)); | 2076 | (1 << INTEL_ANALOG_CLONE_BIT)); |
2118 | 2077 | ||
2119 | intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); | 2078 | intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); |
2120 | 2079 | ||
2080 | intel_sdvo_add_hdmi_properties(intel_sdvo_connector); | ||
2081 | |||
2121 | return true; | 2082 | return true; |
2122 | } | 2083 | } |
2123 | 2084 | ||