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 && |
