The function is reworked to be more readable and fix wrong computations at two corner cases: *It takes advantage of the properties of the N and CTS values to recursively compute the parameters for the highest audio sample rates. *Fix an overflow in the computation of CTS that was happening with the pclk = 148.5MHz, fs=176.4kHz and color of 36 bits/pixel use case. *The N value is updated for the pclk=27.027MHz, fs=32kHz and color of 30 bits/pixel use case to produce a CTS value that is closer to an integer and, therefore, produce less clock drift. However, no valid value of N can yield to an integer CTS value for such use case. Signed-off-by: Ricardo Neri <rneri@xxxxxxxxxxxxxx> --- drivers/video/omap2/dss/hdmi.c | 142 ++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 72 deletions(-) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 769d082..0857834 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -824,100 +824,98 @@ static void hdmi_put_clocks(void) #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) { + int r; u32 deep_color; - bool deep_color_correct = false; u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock; - if (n == NULL || cts == NULL) + if (n == NULL || cts == NULL || sample_freq == 0) return -EINVAL; /* TODO: When implemented, query deep color mode here. */ deep_color = 100; - /* - * When using deep color, the default N value (as in the HDMI - * specification) yields to an non-integer CTS. Hence, we - * modify it while keeping the restrictions described in - * section 7.2.1 of the HDMI 1.4a specification. - */ switch (sample_freq) { case 32000: - case 48000: - case 96000: - case 192000: - if (deep_color == 125) - if (pclk == 27027 || pclk == 74250) - deep_color_correct = true; - if (deep_color == 150) - if (pclk == 27027) - deep_color_correct = true; - break; - case 44100: - case 88200: - case 176400: - if (deep_color == 125) - if (pclk == 27027) - deep_color_correct = true; - break; - default: - return -EINVAL; - } - - if (deep_color_correct) { - switch (sample_freq) { - case 32000: + if (deep_color == 125 && pclk == 74250) { *n = 8192; break; - case 44100: - *n = 12544; + } + + if (deep_color == 125 && pclk == 27027) { + /* + * For this specific configuration, no value within the + * allowed interval of N (as per the HDMI spec) will + * produce an integer value of CTS. The value we use + * here will produce CTS = 11587.000427246, which is + * slightly larger than the integer. This difference + * could cause the audio clock at the sink to slowly + * drift. The true solution requires alternating between + * two CTS relevant values with careful timing in order + * to, on average, obtain the true CTS float value. + */ + *n = 13529; break; - case 48000: + } + + if (deep_color == 150 && pclk == 27027) { *n = 8192; break; - case 88200: - *n = 25088; - break; - case 96000: - *n = 16384; - break; - case 176400: - *n = 50176; - break; - case 192000: - *n = 32768; - break; - default: - return -EINVAL; } - } else { - switch (sample_freq) { - case 32000: - *n = 4096; - break; - case 44100: - *n = 6272; - break; - case 48000: - *n = 6144; - break; - case 88200: + + *n = 4096; + break; + case 44100: + if (deep_color == 125 && pclk == 27027) { *n = 12544; break; - case 96000: - *n = 12288; - break; - case 176400: - *n = 25088; + } + + *n = 6272; + break; + case 48000: + if (deep_color == 125 && (pclk == 27027 || pclk == 74250)) { + *n = 8192; break; - case 192000: - *n = 24576; + } + + if (deep_color == 150 && pclk == 27027) { + *n = 8192; break; - default: - return -EINVAL; } + + *n = 6144; + break; + case 88200: + r = hdmi_compute_acr(44100, n, cts); + *n *= 2; + return r; + case 96000: + r = hdmi_compute_acr(48000, n, cts); + *n *= 2; + return r; + case 176400: + r = hdmi_compute_acr(44100, n, cts); + *n *= 4; + return r; + case 192000: + r = hdmi_compute_acr(48000, n, cts); + *n *= 4; + return r; + default: + return -EINVAL; } - /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ - *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); + + /* + * Calculate CTS. See HDMI 1.3a or 1.4a specifications. Preserve the + * remainder in case N is not a multiple of 128. + */ + *cts = (*n / 128) * pclk * deep_color; + *cts += (*n % 128) * pclk * deep_color / 128; + *cts /= (sample_freq / 10); + + if ((pclk * (*n / 128) * deep_color) % (sample_freq / 10)) + DSSWARN("CTS is not integer fs[%u]pclk[%u]N[%u]\n", + sample_freq, pclk, *n); return 0; } -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html