Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: sh-sci: Support for HSCIF RX sampling point adjustment

HSCIF has facilities that allow moving the RX sampling point by between
-8 and 7 sampling cycles (one sampling cycles equals 1/15 of a bit
by default) to improve the error margin in case of slightly mismatched
bit rates between sender and receiver.

This patch tries to determine if shifting the sampling point can improve
the error margin and will enable it if so.

Signed-off-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ulrich Hecht and committed by
Greg Kroah-Hartman
63ba1e00 7678f4c2

+46 -23
+42 -23
drivers/tty/serial/sh-sci.c
··· 2391 2391 2392 2392 uart_update_timeout(port, termios->c_cflag, baud); 2393 2393 2394 + /* byte size and parity */ 2395 + switch (termios->c_cflag & CSIZE) { 2396 + case CS5: 2397 + bits = 7; 2398 + break; 2399 + case CS6: 2400 + bits = 8; 2401 + break; 2402 + case CS7: 2403 + bits = 9; 2404 + break; 2405 + default: 2406 + bits = 10; 2407 + break; 2408 + } 2409 + 2410 + if (termios->c_cflag & CSTOPB) 2411 + bits++; 2412 + if (termios->c_cflag & PARENB) 2413 + bits++; 2414 + 2394 2415 if (best_clk >= 0) { 2395 2416 if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) 2396 2417 switch (srr + 1) { ··· 2428 2407 serial_port_out(port, SCSCR, scr_val | s->hscif_tot); 2429 2408 serial_port_out(port, SCSMR, smr_val); 2430 2409 serial_port_out(port, SCBRR, brr); 2431 - if (sci_getreg(port, HSSRR)->size) 2432 - serial_port_out(port, HSSRR, srr | HSCIF_SRE); 2410 + if (sci_getreg(port, HSSRR)->size) { 2411 + unsigned int hssrr = srr | HSCIF_SRE; 2412 + /* Calculate deviation from intended rate at the 2413 + * center of the last stop bit in sampling clocks. 2414 + */ 2415 + int last_stop = bits * 2 - 1; 2416 + int deviation = min_err * srr * last_stop / 2 / baud; 2417 + 2418 + if (abs(deviation) >= 2) { 2419 + /* At least two sampling clocks off at the 2420 + * last stop bit; we can increase the error 2421 + * margin by shifting the sampling point. 2422 + */ 2423 + int shift = min(-8, max(7, deviation / 2)); 2424 + 2425 + hssrr |= (shift << HSCIF_SRHP_SHIFT) & 2426 + HSCIF_SRHP_MASK; 2427 + hssrr |= HSCIF_SRDE; 2428 + } 2429 + serial_port_out(port, HSSRR, hssrr); 2430 + } 2433 2431 2434 2432 /* Wait one bit interval */ 2435 2433 udelay((1000000 + (baud - 1)) / baud); ··· 2515 2475 * value obtained by this formula is too small. Therefore, if the value 2516 2476 * is smaller than 20ms, use 20ms as the timeout value for DMA. 2517 2477 */ 2518 - /* byte size and parity */ 2519 - switch (termios->c_cflag & CSIZE) { 2520 - case CS5: 2521 - bits = 7; 2522 - break; 2523 - case CS6: 2524 - bits = 8; 2525 - break; 2526 - case CS7: 2527 - bits = 9; 2528 - break; 2529 - default: 2530 - bits = 10; 2531 - break; 2532 - } 2533 - 2534 - if (termios->c_cflag & CSTOPB) 2535 - bits++; 2536 - if (termios->c_cflag & PARENB) 2537 - bits++; 2538 - 2539 2478 s->rx_frame = (10000 * bits) / (baud / 100); 2540 2479 #ifdef CONFIG_SERIAL_SH_SCI_DMA 2541 2480 s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame;
+4
drivers/tty/serial/sh-sci.h
··· 130 130 131 131 /* HSSRR HSCIF */ 132 132 #define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ 133 + #define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */ 134 + 135 + #define HSCIF_SRHP_SHIFT 8 136 + #define HSCIF_SRHP_MASK 0x0f00 133 137 134 138 /* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ 135 139 #define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */