diff options
author | Pierre Ossman <pierre@ossman.eu> | 2013-11-06 14:09:08 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-11-08 13:06:33 -0500 |
commit | a2098250fbda149cfad9e626afe80abe3b21e574 (patch) | |
tree | 4665435ea53e688cb0e3955860ef3674105fe4b3 | |
parent | 3e71985f2439d8c4090dc2820e497e6f3d72dcff (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.c | 68 |
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 | */ |
76 | static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq) | 77 | static 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 | ||
91 | struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock) | 114 | struct 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 | } |