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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 be67a596eee..56cae72a520 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 6e990f9760e..2f47dcf0b36 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 105e2b892f3..d43cebdea1e 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); |