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 <jschultz@xxxxxxxxxxx> > Cc: Aaron Sierra <asierra@xxxxxxxxxxx> > Signed-off-by: Peter Hurley <peter@xxxxxxxxxxxxxxxxxx> 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], ", &frac); + calc_quot2(bauds[i], "2, &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-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html