On 01/22/2015 12:24 PM, Peter Hurley wrote:
> Exar XR17V35X PCIe uarts support a 4-bit fractional divisor register.
> Refactor the divisor calculation from the divisor programming.
> 
> Allow a fractional result from serial8250_get_divisor() and pass this
> result to serial8250_dl_write().
> 
> Simplify the calculation for quot and quot_frac. This was verified
> to be identical to the results of the original calculation with a test
> jig.
> 
> NB: The results were also compared with the divisor value chart
> on pg 33 of the Exar XR17V352 datasheet, rev 1.0.3, here:
> http://www.exar.com/common/content/document.ashx?id=1585
> which differs from the calculated values by 1 in the fractional result.
> This is because the calculated values are still rounded in the
> fractional result, whereas the table values are truncated. Note
> that the data error rate % values in the datasheet are for
> rounded fractional results, as the truncated fractional results
> have more error.
> 
> Cc: Joe Schultz <[email protected]>
> Cc: Aaron Sierra <[email protected]>
> Signed-off-by: Peter Hurley <[email protected]>

FWIW, here's the test jig:

--- /dev/null   2015-01-22 11:30:11.407707482 -0500
+++ divisor.c   2015-01-22 12:42:34.722403359 -0500
@@ -0,0 +1,92 @@
+/*
+ * divisor.c - test jig for evaluating computation equivalence
+ *            of divisors for XR17V35x UART
+ */
+
+#include <stdio.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+/* from include/linux/kernel.h */
+
+#define DIV_ROUND_CLOSEST(x, divisor)(                 \
+{                                                      \
+       typeof(x) __x = x;                              \
+       typeof(divisor) __d = divisor;                  \
+       (((typeof(x))-1) > 0 ||                         \
+        ((typeof(divisor))-1) > 0 || (__x) > 0) ?      \
+               (((__x) + ((__d) / 2)) / (__d)) :       \
+               (((__x) - ((__d) / 2)) / (__d));        \
+}                                                      \
+)
+
+/* 125MHz clock on XR17V35x */
+unsigned int clk = 125000000;
+
+
+void calc_quot(unsigned int baud, unsigned int *quot, unsigned int *frac) {
+
+       unsigned int baud_x32 = (2 * clk) / baud;
+
+       *quot = baud_x32 / 32;
+       *frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
+}
+
+void calc_quot2(unsigned int baud, unsigned int *quot, unsigned int *frac) {
+
+       /* compute quotient as a 16.4 fixed point value */
+       unsigned int quot_16 = DIV_ROUND_CLOSEST(clk, baud);
+
+       *quot = quot_16 >> 4;
+       *frac = quot_16 & 0x0f;
+}
+
+
+int main() {
+       int i;
+       unsigned int bauds[] = {   2400,
+                                  4800,
+                                  9600,
+                                 10000,
+                                 19200,
+                                 25000,
+                                 28800,
+                                 38400,
+                                 50000,
+                                 57600,
+                                 75000,
+                                100000,
+                                115200,
+                                153600,
+                                200000,
+                                225000,
+                                230400,
+                                250000,
+                                300000,
+                                400000,
+                                460800,
+                                500000,
+                                576000,
+                                750000,
+                                921600,
+                               1000000,
+                               1152000,
+                              };
+
+       for (i = 0; i < ARRAY_SIZE(bauds); i++) {
+               unsigned int quot, frac;
+               unsigned int quot2, frac2;
+
+               calc_quot(bauds[i], &quot, &frac);
+               calc_quot2(bauds[i], &quot2, &frac2);
+
+               if (quot != quot2 || frac != frac2) {
+                       printf("diff: %04x.%01x != %04x.%01x\n", quot, frac,
+                              quot2, frac2);
+               } else
+                       printf("%10d  %02X %02X %01X\n", bauds[i],
+                              quot2 >> 8, quot2 & 0xff, frac2);
+       }
+
+       return 0;
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to