aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2010-09-24 15:44:32 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-10-22 04:14:30 -0400
commit3c17fe4b8f40a112a85758a9ab2aebf772bdd647 (patch)
tree11200d46545ce7d139cd5be8268ee43c402fa433 /drivers/gpu/drm
parentdc3f82c2e5c3f06e43855f417e4fcfc244383916 (diff)
i915: enable AVI infoframe for intel_hdmi.c [v4]
This patch enables the sending of AVI infoframes in drivers/gpu/drm/i915/intel_hdmi.c. My receiver currently loses sync when the HDMI output on my computer (DG45FC motherboard) is switched from 800x600 (the BIOS resolution) to 1920x1080 as part of the boot. Fixable by switching inputs on the receiver a couple of times. With this patch, my receiver has not lost sync yet (> 40 tries). Fourth version, now based on drm-intel-next from: git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git Two questions still remain: I'm assuming that the sdvo hardware also stores a header ECC byte in the MSB of the first dword - is this correct? Does the SDVOB and SDVOC handling in intel_hdmi_set_avi_infoframe() look correct? Signed-off-by: David Härdeman <david@hardeman.nu> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h16
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h33
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c60
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c126
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
185struct 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
181static inline struct drm_crtc * 213static inline struct drm_crtc *
182intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) 214intel_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
201extern void intel_crt_init(struct drm_device *dev); 233extern void intel_crt_init(struct drm_device *dev);
202extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); 234extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
235void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
203extern bool intel_sdvo_init(struct drm_device *dev, int output_device); 236extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
204extern void intel_dvo_init(struct drm_device *dev); 237extern void intel_dvo_init(struct drm_device *dev);
205extern void intel_tv_init(struct drm_device *dev); 238extern 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
61void 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
76static 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
61static void intel_hdmi_mode_set(struct drm_encoder *encoder, 115static 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
96static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 154static 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
857static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, 857static 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
880static 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
895struct 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
952static 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
968static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) 886static 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 &&