diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-04-18 10:50:55 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-04-23 18:03:53 -0400 |
commit | b1f6f47e3e33c4a74534f1301aca241ffabbb3a0 (patch) | |
tree | 22542b1fb96d0cf822c1bdbc4db76fe072260d93 /drivers/gpu/drm/radeon | |
parent | 26250e65fdabf4d406dc7846da7f948748cbb922 (diff) |
drm/radeon: clean up audio dto programming
Split into DCE2/3 and DCE4/5 variants. Still todo is to
calculate the DTO dividers properly. Add proper formula
to the comments.
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r-- | drivers/gpu/drm/radeon/evergreen_hdmi.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600_audio.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600_hdmi.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 1 |
4 files changed, 50 insertions, 62 deletions
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 380933bc1782..9fc22ee40f96 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c | |||
@@ -85,6 +85,30 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder, | |||
85 | frame[0xC] | (frame[0xD] << 8)); | 85 | frame[0xC] | (frame[0xD] << 8)); |
86 | } | 86 | } |
87 | 87 | ||
88 | static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) | ||
89 | { | ||
90 | struct drm_device *dev = encoder->dev; | ||
91 | struct radeon_device *rdev = dev->dev_private; | ||
92 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
93 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
94 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); | ||
95 | u32 base_rate = 48000; | ||
96 | |||
97 | if (!dig || !dig->afmt) | ||
98 | return; | ||
99 | |||
100 | /* XXX: properly calculate this */ | ||
101 | /* XXX two dtos; generally use dto0 for hdmi */ | ||
102 | /* Express [24MHz / target pixel clock] as an exact rational | ||
103 | * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE | ||
104 | * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator | ||
105 | */ | ||
106 | WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff); | ||
107 | WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff); | ||
108 | WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); | ||
109 | } | ||
110 | |||
111 | |||
88 | /* | 112 | /* |
89 | * update the info frames with the data from the current display mode | 113 | * update the info frames with the data from the current display mode |
90 | */ | 114 | */ |
@@ -104,7 +128,7 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode | |||
104 | return; | 128 | return; |
105 | offset = dig->afmt->offset; | 129 | offset = dig->afmt->offset; |
106 | 130 | ||
107 | r600_audio_set_clock(encoder, mode->clock); | 131 | evergreen_audio_set_dto(encoder, mode->clock); |
108 | 132 | ||
109 | WREG32(HDMI_VBI_PACKET_CONTROL + offset, | 133 | WREG32(HDMI_VBI_PACKET_CONTROL + offset, |
110 | HDMI_NULL_SEND); /* send null packets when required */ | 134 | HDMI_NULL_SEND); /* send null packets when required */ |
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 72561e4a0799..c92eb86a8e55 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c | |||
@@ -181,65 +181,6 @@ int r600_audio_init(struct radeon_device *rdev) | |||
181 | } | 181 | } |
182 | 182 | ||
183 | /* | 183 | /* |
184 | * atach the audio codec to the clock source of the encoder | ||
185 | */ | ||
186 | void r600_audio_set_clock(struct drm_encoder *encoder, int clock) | ||
187 | { | ||
188 | struct drm_device *dev = encoder->dev; | ||
189 | struct radeon_device *rdev = dev->dev_private; | ||
190 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
191 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
192 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); | ||
193 | int base_rate = 48000; | ||
194 | |||
195 | switch (radeon_encoder->encoder_id) { | ||
196 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: | ||
197 | case ENCODER_OBJECT_ID_INTERNAL_LVTM1: | ||
198 | WREG32_P(R600_AUDIO_TIMING, 0, ~0x301); | ||
199 | break; | ||
200 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: | ||
201 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: | ||
202 | case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: | ||
203 | case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: | ||
204 | WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301); | ||
205 | break; | ||
206 | default: | ||
207 | dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n", | ||
208 | radeon_encoder->encoder_id); | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | if (ASIC_IS_DCE4(rdev)) { | ||
213 | /* TODO: other PLLs? */ | ||
214 | WREG32(EVERGREEN_AUDIO_PLL1_MUL, base_rate * 10); | ||
215 | WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10); | ||
216 | WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071); | ||
217 | |||
218 | /* Select DTO source */ | ||
219 | WREG32(0x5ac, radeon_crtc->crtc_id); | ||
220 | } else { | ||
221 | switch (dig->dig_encoder) { | ||
222 | case 0: | ||
223 | WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50); | ||
224 | WREG32(R600_AUDIO_PLL1_DIV, clock * 100); | ||
225 | WREG32(R600_AUDIO_CLK_SRCSEL, 0); | ||
226 | break; | ||
227 | |||
228 | case 1: | ||
229 | WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50); | ||
230 | WREG32(R600_AUDIO_PLL2_DIV, clock * 100); | ||
231 | WREG32(R600_AUDIO_CLK_SRCSEL, 1); | ||
232 | break; | ||
233 | default: | ||
234 | dev_err(rdev->dev, | ||
235 | "Unsupported DIG on encoder 0x%02X\n", | ||
236 | radeon_encoder->encoder_id); | ||
237 | return; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * release the audio timer | 184 | * release the audio timer |
244 | * TODO: How to do this correctly on SMP systems? | 185 | * TODO: How to do this correctly on SMP systems? |
245 | */ | 186 | */ |
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 95397b215701..62721bfabe77 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c | |||
@@ -226,6 +226,30 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) | |||
226 | value, ~HDMI0_AUDIO_TEST_EN); | 226 | value, ~HDMI0_AUDIO_TEST_EN); |
227 | } | 227 | } |
228 | 228 | ||
229 | void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) | ||
230 | { | ||
231 | struct drm_device *dev = encoder->dev; | ||
232 | struct radeon_device *rdev = dev->dev_private; | ||
233 | struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); | ||
234 | struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; | ||
235 | u32 base_rate = 48000; | ||
236 | |||
237 | if (!dig || !dig->afmt) | ||
238 | return; | ||
239 | |||
240 | /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. | ||
241 | * doesn't matter which one you use. Just use the first one. | ||
242 | */ | ||
243 | /* XXX: properly calculate this */ | ||
244 | /* XXX two dtos; generally use dto0 for hdmi */ | ||
245 | /* Express [24MHz / target pixel clock] as an exact rational | ||
246 | * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE | ||
247 | * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator | ||
248 | */ | ||
249 | WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff); | ||
250 | WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff); | ||
251 | WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ | ||
252 | } | ||
229 | 253 | ||
230 | /* | 254 | /* |
231 | * update the info frames with the data from the current display mode | 255 | * update the info frames with the data from the current display mode |
@@ -246,7 +270,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod | |||
246 | return; | 270 | return; |
247 | offset = dig->afmt->offset; | 271 | offset = dig->afmt->offset; |
248 | 272 | ||
249 | r600_audio_set_clock(encoder, mode->clock); | 273 | r600_audio_set_dto(encoder, mode->clock); |
250 | 274 | ||
251 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, | 275 | WREG32(HDMI0_VBI_PACKET_CONTROL + offset, |
252 | HDMI0_NULL_SEND); /* send null packets when required */ | 276 | HDMI0_NULL_SEND); /* send null packets when required */ |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2add5268d280..fa8b8bf61c2d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
@@ -374,7 +374,6 @@ void r600_disable_interrupts(struct radeon_device *rdev); | |||
374 | void r600_rlc_stop(struct radeon_device *rdev); | 374 | void r600_rlc_stop(struct radeon_device *rdev); |
375 | /* r600 audio */ | 375 | /* r600 audio */ |
376 | int r600_audio_init(struct radeon_device *rdev); | 376 | int r600_audio_init(struct radeon_device *rdev); |
377 | void r600_audio_set_clock(struct drm_encoder *encoder, int clock); | ||
378 | struct r600_audio r600_audio_status(struct radeon_device *rdev); | 377 | struct r600_audio r600_audio_status(struct radeon_device *rdev); |
379 | void r600_audio_fini(struct radeon_device *rdev); | 378 | void r600_audio_fini(struct radeon_device *rdev); |
380 | int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); | 379 | int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); |