diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 126 |
4 files changed, 130 insertions, 105 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c52e209321c1..25ed911a3112 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -1353,6 +1353,22 @@ | |||
1353 | #define LVDS_B0B3_POWER_DOWN (0 << 2) | 1353 | #define LVDS_B0B3_POWER_DOWN (0 << 2) |
1354 | #define LVDS_B0B3_POWER_UP (3 << 2) | 1354 | #define LVDS_B0B3_POWER_UP (3 << 2) |
1355 | 1355 | ||
1356 | /* Video Data Island Packet control */ | ||
1357 | #define VIDEO_DIP_DATA 0x61178 | ||
1358 | #define VIDEO_DIP_CTL 0x61170 | ||
1359 | #define VIDEO_DIP_ENABLE (1 << 31) | ||
1360 | #define VIDEO_DIP_PORT_B (1 << 29) | ||
1361 | #define VIDEO_DIP_PORT_C (2 << 29) | ||
1362 | #define VIDEO_DIP_ENABLE_AVI (1 << 21) | ||
1363 | #define VIDEO_DIP_ENABLE_VENDOR (2 << 21) | ||
1364 | #define VIDEO_DIP_ENABLE_SPD (8 << 21) | ||
1365 | #define VIDEO_DIP_SELECT_AVI (0 << 19) | ||
1366 | #define VIDEO_DIP_SELECT_VENDOR (1 << 19) | ||
1367 | #define VIDEO_DIP_SELECT_SPD (3 << 19) | ||
1368 | #define VIDEO_DIP_FREQ_ONCE (0 << 16) | ||
1369 | #define VIDEO_DIP_FREQ_VSYNC (1 << 16) | ||
1370 | #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) | ||
1371 | |||
1356 | /* Panel power sequencing */ | 1372 | /* Panel power sequencing */ |
1357 | #define PP_STATUS 0x61200 | 1373 | #define PP_STATUS 0x61200 |
1358 | #define PP_ON (1 << 31) | 1374 | #define PP_ON (1 << 31) |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0581e5e5ac55..9af9f86a8765 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -178,6 +178,38 @@ struct intel_crtc { | |||
178 | #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) | 178 | #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) |
179 | #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) | 179 | #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) |
180 | 180 | ||
181 | #define DIP_TYPE_AVI 0x82 | ||
182 | #define DIP_VERSION_AVI 0x2 | ||
183 | #define DIP_LEN_AVI 13 | ||
184 | |||
185 | struct dip_infoframe { | ||
186 | uint8_t type; /* HB0 */ | ||
187 | uint8_t ver; /* HB1 */ | ||
188 | uint8_t len; /* HB2 - body len, not including checksum */ | ||
189 | uint8_t ecc; /* Header ECC */ | ||
190 | uint8_t checksum; /* PB0 */ | ||
191 | union { | ||
192 | struct { | ||
193 | /* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */ | ||
194 | uint8_t Y_A_B_S; | ||
195 | /* PB2 - C 7:6, M 5:4, R 3:0 */ | ||
196 | uint8_t C_M_R; | ||
197 | /* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */ | ||
198 | uint8_t ITC_EC_Q_SC; | ||
199 | /* PB4 - VIC 6:0 */ | ||
200 | uint8_t VIC; | ||
201 | /* PB5 - PR 3:0 */ | ||
202 | uint8_t PR; | ||
203 | /* PB6 to PB13 */ | ||
204 | uint16_t top_bar_end; | ||
205 | uint16_t bottom_bar_start; | ||
206 | uint16_t left_bar_end; | ||
207 | uint16_t right_bar_start; | ||
208 | } avi; | ||
209 | uint8_t payload[27]; | ||
210 | } __attribute__ ((packed)) body; | ||
211 | } __attribute__((packed)); | ||
212 | |||
181 | static inline struct drm_crtc * | 213 | static inline struct drm_crtc * |
182 | intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) | 214 | intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) |
183 | { | 215 | { |
@@ -200,6 +232,7 @@ extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); | |||
200 | 232 | ||
201 | extern void intel_crt_init(struct drm_device *dev); | 233 | extern void intel_crt_init(struct drm_device *dev); |
202 | extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); | 234 | extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); |
235 | void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); | ||
203 | extern bool intel_sdvo_init(struct drm_device *dev, int output_device); | 236 | extern bool intel_sdvo_init(struct drm_device *dev, int output_device); |
204 | extern void intel_dvo_init(struct drm_device *dev); | 237 | extern void intel_dvo_init(struct drm_device *dev); |
205 | extern void intel_tv_init(struct drm_device *dev); | 238 | extern void intel_tv_init(struct drm_device *dev); |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6c3b2ecd59d5..0d0273e7b029 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
@@ -58,6 +58,60 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) | |||
58 | struct intel_hdmi, base); | 58 | struct intel_hdmi, base); |
59 | } | 59 | } |
60 | 60 | ||
61 | void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) | ||
62 | { | ||
63 | uint8_t *data = (uint8_t *)avi_if; | ||
64 | uint8_t sum = 0; | ||
65 | unsigned i; | ||
66 | |||
67 | avi_if->checksum = 0; | ||
68 | avi_if->ecc = 0; | ||
69 | |||
70 | for (i = 0; i < sizeof(*avi_if); i++) | ||
71 | sum += data[i]; | ||
72 | |||
73 | avi_if->checksum = 0x100 - sum; | ||
74 | } | ||
75 | |||
76 | static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | ||
77 | { | ||
78 | struct dip_infoframe avi_if = { | ||
79 | .type = DIP_TYPE_AVI, | ||
80 | .ver = DIP_VERSION_AVI, | ||
81 | .len = DIP_LEN_AVI, | ||
82 | }; | ||
83 | uint32_t *data = (uint32_t *)&avi_if; | ||
84 | struct drm_device *dev = encoder->dev; | ||
85 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
86 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||
87 | u32 port; | ||
88 | unsigned i; | ||
89 | |||
90 | if (!intel_hdmi->has_hdmi_sink) | ||
91 | return; | ||
92 | |||
93 | /* XXX first guess at handling video port, is this corrent? */ | ||
94 | if (intel_hdmi->sdvox_reg == SDVOB) | ||
95 | port = VIDEO_DIP_PORT_B; | ||
96 | else if (intel_hdmi->sdvox_reg == SDVOC) | ||
97 | port = VIDEO_DIP_PORT_C; | ||
98 | else | ||
99 | return; | ||
100 | |||
101 | I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | | ||
102 | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); | ||
103 | |||
104 | intel_dip_infoframe_csum(&avi_if); | ||
105 | for (i = 0; i < sizeof(avi_if); i += 4) { | ||
106 | I915_WRITE(VIDEO_DIP_DATA, *data); | ||
107 | data++; | ||
108 | } | ||
109 | |||
110 | I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | | ||
111 | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | | ||
112 | VIDEO_DIP_ENABLE_AVI); | ||
113 | } | ||
114 | |||
61 | static void intel_hdmi_mode_set(struct drm_encoder *encoder, | 115 | static void intel_hdmi_mode_set(struct drm_encoder *encoder, |
62 | struct drm_display_mode *mode, | 116 | struct drm_display_mode *mode, |
63 | struct drm_display_mode *adjusted_mode) | 117 | struct drm_display_mode *adjusted_mode) |
@@ -79,8 +133,10 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, | |||
79 | if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) | 133 | if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) |
80 | sdvox |= HDMI_MODE_SELECT; | 134 | sdvox |= HDMI_MODE_SELECT; |
81 | 135 | ||
82 | if (intel_hdmi->has_audio) | 136 | if (intel_hdmi->has_audio) { |
83 | sdvox |= SDVO_AUDIO_ENABLE; | 137 | sdvox |= SDVO_AUDIO_ENABLE; |
138 | sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC; | ||
139 | } | ||
84 | 140 | ||
85 | if (intel_crtc->pipe == 1) { | 141 | if (intel_crtc->pipe == 1) { |
86 | if (HAS_PCH_CPT(dev)) | 142 | if (HAS_PCH_CPT(dev)) |
@@ -91,6 +147,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, | |||
91 | 147 | ||
92 | I915_WRITE(intel_hdmi->sdvox_reg, sdvox); | 148 | I915_WRITE(intel_hdmi->sdvox_reg, sdvox); |
93 | POSTING_READ(intel_hdmi->sdvox_reg); | 149 | POSTING_READ(intel_hdmi->sdvox_reg); |
150 | |||
151 | intel_hdmi_set_avi_infoframe(encoder); | ||
94 | } | 152 | } |
95 | 153 | ||
96 | static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) | 154 | static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index c245383cf7ed..6739a7455174 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -854,115 +854,33 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) | |||
854 | } | 854 | } |
855 | #endif | 855 | #endif |
856 | 856 | ||
857 | static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, | 857 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) |
858 | int index, | ||
859 | uint8_t *data, int8_t size, uint8_t tx_rate) | ||
860 | { | ||
861 | uint8_t set_buf_index[2]; | ||
862 | |||
863 | set_buf_index[0] = index; | ||
864 | set_buf_index[1] = 0; | ||
865 | |||
866 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, | ||
867 | set_buf_index, 2)) | ||
868 | return false; | ||
869 | |||
870 | for (; size > 0; size -= 8) { | ||
871 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) | ||
872 | return false; | ||
873 | |||
874 | data += 8; | ||
875 | } | ||
876 | |||
877 | return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); | ||
878 | } | ||
879 | |||
880 | static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) | ||
881 | { | ||
882 | uint8_t csum = 0; | ||
883 | int i; | ||
884 | |||
885 | for (i = 0; i < size; i++) | ||
886 | csum += data[i]; | ||
887 | |||
888 | return 0x100 - csum; | ||
889 | } | ||
890 | |||
891 | #define DIP_TYPE_AVI 0x82 | ||
892 | #define DIP_VERSION_AVI 0x2 | ||
893 | #define DIP_LEN_AVI 13 | ||
894 | |||
895 | struct dip_infoframe { | ||
896 | uint8_t type; | ||
897 | uint8_t version; | ||
898 | uint8_t len; | ||
899 | uint8_t checksum; | ||
900 | union { | ||
901 | struct { | ||
902 | /* Packet Byte #1 */ | ||
903 | uint8_t S:2; | ||
904 | uint8_t B:2; | ||
905 | uint8_t A:1; | ||
906 | uint8_t Y:2; | ||
907 | uint8_t rsvd1:1; | ||
908 | /* Packet Byte #2 */ | ||
909 | uint8_t R:4; | ||
910 | uint8_t M:2; | ||
911 | uint8_t C:2; | ||
912 | /* Packet Byte #3 */ | ||
913 | uint8_t SC:2; | ||
914 | uint8_t Q:2; | ||
915 | uint8_t EC:3; | ||
916 | uint8_t ITC:1; | ||
917 | /* Packet Byte #4 */ | ||
918 | uint8_t VIC:7; | ||
919 | uint8_t rsvd2:1; | ||
920 | /* Packet Byte #5 */ | ||
921 | uint8_t PR:4; | ||
922 | uint8_t rsvd3:4; | ||
923 | /* Packet Byte #6~13 */ | ||
924 | uint16_t top_bar_end; | ||
925 | uint16_t bottom_bar_start; | ||
926 | uint16_t left_bar_end; | ||
927 | uint16_t right_bar_start; | ||
928 | } avi; | ||
929 | struct { | ||
930 | /* Packet Byte #1 */ | ||
931 | uint8_t channel_count:3; | ||
932 | uint8_t rsvd1:1; | ||
933 | uint8_t coding_type:4; | ||
934 | /* Packet Byte #2 */ | ||
935 | uint8_t sample_size:2; /* SS0, SS1 */ | ||
936 | uint8_t sample_frequency:3; | ||
937 | uint8_t rsvd2:3; | ||
938 | /* Packet Byte #3 */ | ||
939 | uint8_t coding_type_private:5; | ||
940 | uint8_t rsvd3:3; | ||
941 | /* Packet Byte #4 */ | ||
942 | uint8_t channel_allocation; | ||
943 | /* Packet Byte #5 */ | ||
944 | uint8_t rsvd4:3; | ||
945 | uint8_t level_shift:4; | ||
946 | uint8_t downmix_inhibit:1; | ||
947 | } audio; | ||
948 | uint8_t payload[28]; | ||
949 | } __attribute__ ((packed)) u; | ||
950 | } __attribute__((packed)); | ||
951 | |||
952 | static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, | ||
953 | struct drm_display_mode * mode) | ||
954 | { | 858 | { |
955 | struct dip_infoframe avi_if = { | 859 | struct dip_infoframe avi_if = { |
956 | .type = DIP_TYPE_AVI, | 860 | .type = DIP_TYPE_AVI, |
957 | .version = DIP_VERSION_AVI, | 861 | .ver = DIP_VERSION_AVI, |
958 | .len = DIP_LEN_AVI, | 862 | .len = DIP_LEN_AVI, |
959 | }; | 863 | }; |
864 | uint8_t tx_rate = SDVO_HBUF_TX_VSYNC; | ||
865 | uint8_t set_buf_index[2] = { 1, 0 }; | ||
866 | uint64_t *data = (uint64_t *)&avi_if; | ||
867 | unsigned i; | ||
868 | |||
869 | intel_dip_infoframe_csum(&avi_if); | ||
870 | |||
871 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, | ||
872 | set_buf_index, 2)) | ||
873 | return false; | ||
874 | |||
875 | for (i = 0; i < sizeof(avi_if); i += 8) { | ||
876 | if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, | ||
877 | data, 8)) | ||
878 | return false; | ||
879 | data++; | ||
880 | } | ||
960 | 881 | ||
961 | avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, | 882 | return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, |
962 | 4 + avi_if.len); | 883 | &tx_rate, 1); |
963 | return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, | ||
964 | 4 + avi_if.len, | ||
965 | SDVO_HBUF_TX_VSYNC); | ||
966 | } | 884 | } |
967 | 885 | ||
968 | static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) | 886 | static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) |
@@ -1116,7 +1034,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, | |||
1116 | return; | 1034 | return; |
1117 | 1035 | ||
1118 | if (intel_sdvo->is_hdmi && | 1036 | if (intel_sdvo->is_hdmi && |
1119 | !intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) | 1037 | !intel_sdvo_set_avi_infoframe(intel_sdvo)) |
1120 | return; | 1038 | return; |
1121 | 1039 | ||
1122 | if (intel_sdvo->is_tv && | 1040 | if (intel_sdvo->is_tv && |