diff options
| author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-08-03 12:22:55 -0400 |
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2011-08-03 20:43:13 -0400 |
| commit | 45187ace97f7b3deb559b25348ccb7e301c158c9 (patch) | |
| tree | 9538239971c5538b5edc5e777015e453b430a376 | |
| parent | ebec9a7bf11f843b0602b06c402f04bf4213b35a (diff) | |
drm/i915/hdmi: split infoframe setting from infoframe type code
This makes it easier to add support for other infoframes (e.g. SPD,
vendor specific).
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 149 |
3 files changed, 106 insertions, 46 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be67a596eee5..56cae72a5207 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
| @@ -1506,6 +1506,7 @@ | |||
| 1506 | #define VIDEO_DIP_SELECT_AVI (0 << 19) | 1506 | #define VIDEO_DIP_SELECT_AVI (0 << 19) |
| 1507 | #define VIDEO_DIP_SELECT_VENDOR (1 << 19) | 1507 | #define VIDEO_DIP_SELECT_VENDOR (1 << 19) |
| 1508 | #define VIDEO_DIP_SELECT_SPD (3 << 19) | 1508 | #define VIDEO_DIP_SELECT_SPD (3 << 19) |
| 1509 | #define VIDEO_DIP_SELECT_MASK (3 << 19) | ||
| 1509 | #define VIDEO_DIP_FREQ_ONCE (0 << 16) | 1510 | #define VIDEO_DIP_FREQ_ONCE (0 << 16) |
| 1510 | #define VIDEO_DIP_FREQ_VSYNC (1 << 16) | 1511 | #define VIDEO_DIP_FREQ_VSYNC (1 << 16) |
| 1511 | #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) | 1512 | #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) |
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6e990f9760ef..2f47dcf0b367 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -178,6 +178,8 @@ 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_HEADER_SIZE 5 | ||
| 182 | |||
| 181 | #define DIP_TYPE_AVI 0x82 | 183 | #define DIP_TYPE_AVI 0x82 |
| 182 | #define DIP_VERSION_AVI 0x2 | 184 | #define DIP_VERSION_AVI 0x2 |
| 183 | #define DIP_LEN_AVI 13 | 185 | #define DIP_LEN_AVI 13 |
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 105e2b892f3a..d43cebdea1ee 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c | |||
| @@ -45,6 +45,8 @@ struct intel_hdmi { | |||
| 45 | bool has_hdmi_sink; | 45 | bool has_hdmi_sink; |
| 46 | bool has_audio; | 46 | bool has_audio; |
| 47 | int force_audio; | 47 | int force_audio; |
| 48 | void (*write_infoframe)(struct drm_encoder *encoder, | ||
| 49 | struct dip_infoframe *frame); | ||
| 48 | }; | 50 | }; |
| 49 | 51 | ||
| 50 | static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) | 52 | static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) |
| @@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) | |||
| 58 | struct intel_hdmi, base); | 60 | struct intel_hdmi, base); |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) | 63 | void intel_dip_infoframe_csum(struct dip_infoframe *frame) |
| 62 | { | 64 | { |
| 63 | uint8_t *data = (uint8_t *)avi_if; | 65 | uint8_t *data = (uint8_t *)frame; |
| 64 | uint8_t sum = 0; | 66 | uint8_t sum = 0; |
| 65 | unsigned i; | 67 | unsigned i; |
| 66 | 68 | ||
| 67 | avi_if->checksum = 0; | 69 | frame->checksum = 0; |
| 68 | avi_if->ecc = 0; | 70 | frame->ecc = 0; |
| 69 | 71 | ||
| 70 | for (i = 0; i < sizeof(*avi_if); i++) | 72 | /* Header isn't part of the checksum */ |
| 73 | for (i = 5; i < frame->len; i++) | ||
| 71 | sum += data[i]; | 74 | sum += data[i]; |
| 72 | 75 | ||
| 73 | avi_if->checksum = 0x100 - sum; | 76 | frame->checksum = 0x100 - sum; |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | 79 | static u32 intel_infoframe_index(struct dip_infoframe *frame) |
| 77 | { | 80 | { |
| 78 | struct dip_infoframe avi_if = { | 81 | u32 flags = 0; |
| 79 | .type = DIP_TYPE_AVI, | 82 | |
| 80 | .ver = DIP_VERSION_AVI, | 83 | switch (frame->type) { |
| 81 | .len = DIP_LEN_AVI, | 84 | case DIP_TYPE_AVI: |
| 82 | }; | 85 | flags |= VIDEO_DIP_SELECT_AVI; |
| 83 | uint32_t *data = (uint32_t *)&avi_if; | 86 | break; |
| 87 | case DIP_TYPE_SPD: | ||
| 88 | flags |= VIDEO_DIP_SELECT_SPD; | ||
| 89 | break; | ||
| 90 | default: | ||
| 91 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | |||
| 95 | return flags; | ||
| 96 | } | ||
| 97 | |||
| 98 | static u32 intel_infoframe_flags(struct dip_infoframe *frame) | ||
| 99 | { | ||
| 100 | u32 flags = 0; | ||
| 101 | |||
| 102 | switch (frame->type) { | ||
| 103 | case DIP_TYPE_AVI: | ||
| 104 | flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; | ||
| 105 | break; | ||
| 106 | case DIP_TYPE_SPD: | ||
| 107 | flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC; | ||
| 108 | break; | ||
| 109 | default: | ||
| 110 | DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | |||
| 114 | return flags; | ||
| 115 | } | ||
| 116 | |||
| 117 | static void i9xx_write_infoframe(struct drm_encoder *encoder, | ||
| 118 | struct dip_infoframe *frame) | ||
| 119 | { | ||
| 120 | uint32_t *data = (uint32_t *)frame; | ||
| 84 | struct drm_device *dev = encoder->dev; | 121 | struct drm_device *dev = encoder->dev; |
| 85 | struct drm_i915_private *dev_priv = dev->dev_private; | 122 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 86 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | 123 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); |
| 87 | u32 port; | 124 | u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); |
| 88 | unsigned i; | 125 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
| 89 | 126 | ||
| 90 | if (!intel_hdmi->has_hdmi_sink) | ||
| 91 | return; | ||
| 92 | 127 | ||
| 93 | /* XXX first guess at handling video port, is this corrent? */ | 128 | /* XXX first guess at handling video port, is this corrent? */ |
| 94 | if (intel_hdmi->sdvox_reg == SDVOB) | 129 | if (intel_hdmi->sdvox_reg == SDVOB) |
| @@ -98,52 +133,72 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | |||
| 98 | else | 133 | else |
| 99 | return; | 134 | return; |
| 100 | 135 | ||
| 101 | I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | | 136 | flags = intel_infoframe_index(frame); |
| 102 | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); | 137 | |
| 138 | val &= ~VIDEO_DIP_SELECT_MASK; | ||
| 139 | |||
| 140 | I915_WRITE(VIDEO_DIP_CTL, val | port | flags); | ||
| 103 | 141 | ||
| 104 | intel_dip_infoframe_csum(&avi_if); | 142 | for (i = 0; i < len; i += 4) { |
| 105 | for (i = 0; i < sizeof(avi_if); i += 4) { | ||
| 106 | I915_WRITE(VIDEO_DIP_DATA, *data); | 143 | I915_WRITE(VIDEO_DIP_DATA, *data); |
| 107 | data++; | 144 | data++; |
| 108 | } | 145 | } |
| 109 | 146 | ||
| 110 | I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | | 147 | flags |= intel_infoframe_flags(frame); |
| 111 | VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | | 148 | |
| 112 | VIDEO_DIP_ENABLE_AVI); | 149 | I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); |
| 113 | } | 150 | } |
| 114 | 151 | ||
| 115 | static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | 152 | static void ironlake_write_infoframe(struct drm_encoder *encoder, |
| 153 | struct dip_infoframe *frame) | ||
| 116 | { | 154 | { |
| 117 | struct dip_infoframe avi_if = { | 155 | uint32_t *data = (uint32_t *)frame; |
| 118 | .type = DIP_TYPE_AVI, | ||
| 119 | .ver = DIP_VERSION_AVI, | ||
| 120 | .len = DIP_LEN_AVI, | ||
| 121 | }; | ||
| 122 | uint32_t *data = (uint32_t *)&avi_if; | ||
| 123 | struct drm_device *dev = encoder->dev; | 156 | struct drm_device *dev = encoder->dev; |
| 124 | struct drm_i915_private *dev_priv = dev->dev_private; | 157 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 125 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||
| 126 | struct drm_crtc *crtc = encoder->crtc; | 158 | struct drm_crtc *crtc = encoder->crtc; |
| 127 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 159 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
| 128 | int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); | 160 | int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); |
| 129 | unsigned i; | 161 | unsigned i, len = DIP_HEADER_SIZE + frame->len; |
| 130 | 162 | u32 flags, val = I915_READ(reg); | |
| 131 | if (!intel_hdmi->has_hdmi_sink) | ||
| 132 | return; | ||
| 133 | 163 | ||
| 134 | intel_wait_for_vblank(dev, intel_crtc->pipe); | 164 | intel_wait_for_vblank(dev, intel_crtc->pipe); |
| 135 | 165 | ||
| 136 | I915_WRITE(reg, VIDEO_DIP_SELECT_AVI); | 166 | flags = intel_infoframe_index(frame); |
| 137 | 167 | ||
| 138 | intel_dip_infoframe_csum(&avi_if); | 168 | val &= ~VIDEO_DIP_SELECT_MASK; |
| 139 | for (i = 0; i < sizeof(avi_if); i += 4) { | 169 | |
| 170 | I915_WRITE(reg, val | flags); | ||
| 171 | |||
| 172 | for (i = 0; i < len; i += 4) { | ||
| 140 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); | 173 | I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); |
| 141 | data++; | 174 | data++; |
| 142 | } | 175 | } |
| 143 | 176 | ||
| 144 | I915_WRITE(reg, VIDEO_DIP_ENABLE | VIDEO_DIP_SELECT_AVI | | 177 | flags |= intel_infoframe_flags(frame); |
| 145 | VIDEO_DIP_FREQ_VSYNC | (DIP_LEN_AVI << 8) | | 178 | |
| 146 | VIDEO_DIP_ENABLE_AVI); | 179 | I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); |
| 180 | } | ||
| 181 | static void intel_set_infoframe(struct drm_encoder *encoder, | ||
| 182 | struct dip_infoframe *frame) | ||
| 183 | { | ||
| 184 | struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); | ||
| 185 | |||
| 186 | if (!intel_hdmi->has_hdmi_sink) | ||
| 187 | return; | ||
| 188 | |||
| 189 | intel_dip_infoframe_csum(frame); | ||
| 190 | intel_hdmi->write_infoframe(encoder, frame); | ||
| 191 | } | ||
| 192 | |||
| 193 | static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | ||
| 194 | { | ||
| 195 | struct dip_infoframe avi_if = { | ||
| 196 | .type = DIP_TYPE_AVI, | ||
| 197 | .ver = DIP_VERSION_AVI, | ||
| 198 | .len = DIP_LEN_AVI, | ||
| 199 | }; | ||
| 200 | |||
| 201 | intel_set_infoframe(encoder, &avi_if); | ||
| 147 | } | 202 | } |
| 148 | 203 | ||
| 149 | static void intel_hdmi_mode_set(struct drm_encoder *encoder, | 204 | static void intel_hdmi_mode_set(struct drm_encoder *encoder, |
| @@ -189,10 +244,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, | |||
| 189 | I915_WRITE(intel_hdmi->sdvox_reg, sdvox); | 244 | I915_WRITE(intel_hdmi->sdvox_reg, sdvox); |
| 190 | POSTING_READ(intel_hdmi->sdvox_reg); | 245 | POSTING_READ(intel_hdmi->sdvox_reg); |
| 191 | 246 | ||
| 192 | if (HAS_PCH_SPLIT(dev)) | 247 | intel_hdmi_set_avi_infoframe(encoder); |
| 193 | intel_ironlake_hdmi_set_avi_infoframe(encoder); | ||
| 194 | else | ||
| 195 | intel_hdmi_set_avi_infoframe(encoder); | ||
| 196 | } | 248 | } |
| 197 | 249 | ||
| 198 | static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) | 250 | static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) |
| @@ -470,6 +522,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) | |||
| 470 | 522 | ||
| 471 | intel_hdmi->sdvox_reg = sdvox_reg; | 523 | intel_hdmi->sdvox_reg = sdvox_reg; |
| 472 | 524 | ||
| 525 | if (!HAS_PCH_SPLIT(dev)) | ||
| 526 | intel_hdmi->write_infoframe = i9xx_write_infoframe; | ||
| 527 | else | ||
| 528 | intel_hdmi->write_infoframe = ironlake_write_infoframe; | ||
| 529 | |||
| 473 | drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); | 530 | drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); |
| 474 | 531 | ||
| 475 | intel_hdmi_add_properties(intel_hdmi, connector); | 532 | intel_hdmi_add_properties(intel_hdmi, connector); |
