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 <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to