aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-08-03 12:22:55 -0400
committerKeith Packard <keithp@keithp.com>2011-08-03 20:43:13 -0400
commit45187ace97f7b3deb559b25348ccb7e301c158c9 (patch)
tree9538239971c5538b5edc5e777015e453b430a376 /drivers/gpu
parentebec9a7bf11f843b0602b06c402f04bf4213b35a (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/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c149
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
50static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) 52static 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
61void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) 63void 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
76static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) 79static 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
98static 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
117static 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
115static void intel_ironlake_hdmi_set_avi_infoframe(struct drm_encoder *encoder) 152static 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}
181static 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
193static 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
149static void intel_hdmi_mode_set(struct drm_encoder *encoder, 204static 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
198static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) 250static 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);