Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1518dd8e authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/radeon: fix audio dto calculation on DCE3+ (v3)



Need to set the wallclock ratio and adjust the phase
and module registers appropriately.  May fix problems
with audio timing at certain display timings.

v2: properly handle clocks below 24mhz
v3: rebase r600 changes

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ce149a94
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -148,18 +148,40 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
	u32 base_rate = 24000;
	u32 max_ratio = clock / base_rate;
	u32 dto_phase;
	u32 dto_modulo = clock;
	u32 wallclock_ratio;
	u32 dto_cntl;

	if (!dig || !dig->afmt)
		return;

	if (max_ratio >= 8) {
		dto_phase = 192 * 1000;
		wallclock_ratio = 3;
	} else if (max_ratio >= 4) {
		dto_phase = 96 * 1000;
		wallclock_ratio = 2;
	} else if (max_ratio >= 2) {
		dto_phase = 48 * 1000;
		wallclock_ratio = 1;
	} else {
		dto_phase = 24 * 1000;
		wallclock_ratio = 0;
	}
	dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
	dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
	WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);

	/* XXX two dtos; generally use dto0 for hdmi */
	/* Express [24MHz / target pixel clock] as an exact rational
	 * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
	 * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
	 */
	WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
	WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
	WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
	WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
	WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
}


+3 −0
Original line number Diff line number Diff line
@@ -497,6 +497,9 @@
#define DCCG_AUDIO_DTO0_MODULE            0x05b4
#define DCCG_AUDIO_DTO0_LOAD              0x05b8
#define DCCG_AUDIO_DTO0_CNTL              0x05bc
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0

#define DCCG_AUDIO_DTO1_PHASE             0x05c0
#define DCCG_AUDIO_DTO1_MODULE            0x05c4
+29 −4
Original line number Diff line number Diff line
@@ -226,10 +226,29 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
	u32 base_rate = 24000;
	u32 max_ratio = clock / base_rate;
	u32 dto_phase;
	u32 dto_modulo = clock;
	u32 wallclock_ratio;
	u32 dto_cntl;

	if (!dig || !dig->afmt)
		return;

	if (max_ratio >= 8) {
		dto_phase = 192 * 1000;
		wallclock_ratio = 3;
	} else if (max_ratio >= 4) {
		dto_phase = 96 * 1000;
		wallclock_ratio = 2;
	} else if (max_ratio >= 2) {
		dto_phase = 48 * 1000;
		wallclock_ratio = 1;
	} else {
		dto_phase = 24 * 1000;
		wallclock_ratio = 0;
	}

	/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
	 * doesn't matter which one you use.  Just use the first one.
	 */
@@ -243,12 +262,18 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
		 * practice it seems to cover DCE3.0 as well.
		 */
		if (dig->dig_encoder == 0) {
			WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
			WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
			dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
			dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
			WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
			WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
			WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
			WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
		} else {
			WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100);
			WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
			dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
			dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
			WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
			WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
			WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
			WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
		}
	} else {
+3 −0
Original line number Diff line number Diff line
@@ -933,6 +933,9 @@
#define DCCG_AUDIO_DTO0_LOAD              0x051c
#       define DTO_LOAD                   (1 << 31)
#define DCCG_AUDIO_DTO0_CNTL              0x0520
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0

#define DCCG_AUDIO_DTO1_PHASE             0x0524
#define DCCG_AUDIO_DTO1_MODULE            0x0528