aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Ossman <pierre@ossman.eu>2013-11-06 14:09:08 -0500
committerAlex Deucher <alexander.deucher@amd.com>2013-11-08 13:06:33 -0500
commita2098250fbda149cfad9e626afe80abe3b21e574 (patch)
tree4665435ea53e688cb0e3955860ef3674105fe4b3
parent3e71985f2439d8c4090dc2820e497e6f3d72dcff (diff)
drm/radeon/audio: improve ACR calculation
In order to have any realistic chance of calculating proper ACR values, we need to be able to calculate both N and CTS, not just CTS. We still aim for the ideal N as specified in the HDMI spec though. bug: https://bugs.freedesktop.org/show_bug.cgi?id=69675 Signed-off-by: Pierre Ossman <pierre@ossman.eu> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c68
1 files changed, 46 insertions, 22 deletions
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index b83962d7915b..4b89262f3f0e 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -24,6 +24,7 @@
24 * Authors: Christian König 24 * Authors: Christian König
25 */ 25 */
26#include <linux/hdmi.h> 26#include <linux/hdmi.h>
27#include <linux/gcd.h>
27#include <drm/drmP.h> 28#include <drm/drmP.h>
28#include <drm/radeon_drm.h> 29#include <drm/radeon_drm.h>
29#include "radeon.h" 30#include "radeon.h"
@@ -67,25 +68,47 @@ static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
67 { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ 68 { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
68 { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */ 69 { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
69 { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ 70 { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
70 { 0, 4096, 0, 6272, 0, 6144, 0 } /* Other */
71}; 71};
72 72
73
73/* 74/*
74 * calculate CTS value if it's not found in the table 75 * calculate CTS and N values if they are not found in the table
75 */ 76 */
76static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq) 77static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
77{ 78{
78 u64 n; 79 int n, cts;
79 u32 d; 80 unsigned long div, mul;
80 81
81 if (*CTS == 0) { 82 /* Safe, but overly large values */
82 n = (u64)clock * (u64)N * 1000ULL; 83 n = 128 * freq;
83 d = 128 * freq; 84 cts = clock * 1000;
84 do_div(n, d); 85
85 *CTS = n; 86 /* Smallest valid fraction */
86 } 87 div = gcd(n, cts);
87 DRM_DEBUG("Using ACR timing N=%d CTS=%d for frequency %d\n", 88
88 N, *CTS, freq); 89 n /= div;
90 cts /= div;
91
92 /*
93 * The optimal N is 128*freq/1000. Calculate the closest larger
94 * value that doesn't truncate any bits.
95 */
96 mul = ((128*freq/1000) + (n-1))/n;
97
98 n *= mul;
99 cts *= mul;
100
101 /* Check that we are in spec (not always possible) */
102 if (n < (128*freq/1500))
103 printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
104 if (n > (128*freq/300))
105 printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
106
107 *N = n;
108 *CTS = cts;
109
110 DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
111 *N, *CTS, freq);
89} 112}
90 113
91struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) 114struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
@@ -93,15 +116,16 @@ struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
93 struct radeon_hdmi_acr res; 116 struct radeon_hdmi_acr res;
94 u8 i; 117 u8 i;
95 118
96 for (i = 0; r600_hdmi_predefined_acr[i].clock != clock && 119 /* Precalculated values for common clocks */
97 r600_hdmi_predefined_acr[i].clock != 0; i++) 120 for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) {
98 ; 121 if (r600_hdmi_predefined_acr[i].clock == clock)
99 res = r600_hdmi_predefined_acr[i]; 122 return r600_hdmi_predefined_acr[i];
123 }
100 124
101 /* In case some CTS are missing */ 125 /* And odd clocks get manually calculated */
102 r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000); 126 r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
103 r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100); 127 r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
104 r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000); 128 r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
105 129
106 return res; 130 return res;
107} 131}