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

serial: sh-sci: Add calculation recive margin for HSCIF

When the error of the same bit rate is detected, we will need to select
the recive margin is large. Current code holds the minimum error, it does
not have to check the recive margin. This adds this calculation.

Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Nobuhiro Iwamatsu and committed by
Greg Kroah-Hartman
730c4e78 bcb9973a

+59 -18
+59 -18
drivers/tty/serial/sh-sci.c
··· 1776 1776 return ((freq + 16 * bps) / (32 * bps) - 1); 1777 1777 } 1778 1778 1779 + /* calculate frame length from SMR */ 1780 + static int sci_baud_calc_frame_len(unsigned int smr_val) 1781 + { 1782 + int len = 10; 1783 + 1784 + if (smr_val & SCSMR_CHR) 1785 + len--; 1786 + if (smr_val & SCSMR_PE) 1787 + len++; 1788 + if (smr_val & SCSMR_STOP) 1789 + len++; 1790 + 1791 + return len; 1792 + } 1793 + 1794 + 1779 1795 /* calculate sample rate, BRR, and clock select for HSCIF */ 1780 1796 static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, 1781 1797 int *brr, unsigned int *srr, 1782 - unsigned int *cks) 1798 + unsigned int *cks, int frame_len) 1783 1799 { 1784 - int sr, c, br, err; 1800 + int sr, c, br, err, recv_margin; 1785 1801 int min_err = 1000; /* 100% */ 1802 + int recv_max_margin = 0; 1786 1803 1787 1804 /* Find the combination of sample rate and clock select with the 1788 1805 smallest deviation from the desired baud rate. */ ··· 1812 1795 err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * 1813 1796 (1 << (2 * c + 1)) / 1000)) - 1814 1797 1000; 1798 + if (err < 0) 1799 + continue; 1800 + 1801 + /* Calc recv margin 1802 + * M: Receive margin (%) 1803 + * N: Ratio of bit rate to clock (N = sampling rate) 1804 + * D: Clock duty (D = 0 to 1.0) 1805 + * L: Frame length (L = 9 to 12) 1806 + * F: Absolute value of clock frequency deviation 1807 + * 1808 + * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) - 1809 + * (|D - 0.5| / N * (1 + F))| 1810 + * NOTE: Usually, treat D for 0.5, F is 0 by this 1811 + * calculation. 1812 + */ 1813 + recv_margin = abs((500 - 1814 + DIV_ROUND_CLOSEST(1000, sr << 1)) / 10); 1815 1815 if (min_err > err) { 1816 1816 min_err = err; 1817 - *brr = br; 1818 - *srr = sr - 1; 1819 - *cks = c; 1820 - } 1817 + recv_max_margin = recv_margin; 1818 + } else if ((min_err == err) && 1819 + (recv_margin > recv_max_margin)) 1820 + recv_max_margin = recv_margin; 1821 + else 1822 + continue; 1823 + 1824 + *brr = br; 1825 + *srr = sr - 1; 1826 + *cks = c; 1821 1827 } 1822 1828 } 1823 1829 ··· 1874 1834 { 1875 1835 struct sci_port *s = to_sci_port(port); 1876 1836 struct plat_sci_reg *reg; 1877 - unsigned int baud, smr_val, max_baud, cks = 0; 1837 + unsigned int baud, smr_val = 0, max_baud, cks = 0; 1878 1838 int t = -1; 1879 1839 unsigned int srr = 15; 1840 + 1841 + if ((termios->c_cflag & CSIZE) == CS7) 1842 + smr_val |= SCSMR_CHR; 1843 + if (termios->c_cflag & PARENB) 1844 + smr_val |= SCSMR_PE; 1845 + if (termios->c_cflag & PARODD) 1846 + smr_val |= SCSMR_PE | SCSMR_ODD; 1847 + if (termios->c_cflag & CSTOPB) 1848 + smr_val |= SCSMR_STOP; 1880 1849 1881 1850 /* 1882 1851 * earlyprintk comes here early on with port->uartclk set to zero. ··· 1900 1851 baud = uart_get_baud_rate(port, termios, old, 0, max_baud); 1901 1852 if (likely(baud && port->uartclk)) { 1902 1853 if (s->cfg->type == PORT_HSCIF) { 1854 + int frame_len = sci_baud_calc_frame_len(smr_val); 1903 1855 sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, 1904 - &cks); 1856 + &cks, frame_len); 1905 1857 } else { 1906 1858 t = sci_scbrr_calc(s, baud, port->uartclk); 1907 1859 for (cks = 0; t >= 256 && cks <= 3; cks++) ··· 1914 1864 1915 1865 sci_reset(port); 1916 1866 1917 - smr_val = serial_port_in(port, SCSMR) & 3; 1918 - 1919 - if ((termios->c_cflag & CSIZE) == CS7) 1920 - smr_val |= SCSMR_CHR; 1921 - if (termios->c_cflag & PARENB) 1922 - smr_val |= SCSMR_PE; 1923 - if (termios->c_cflag & PARODD) 1924 - smr_val |= SCSMR_PE | SCSMR_ODD; 1925 - if (termios->c_cflag & CSTOPB) 1926 - smr_val |= SCSMR_STOP; 1867 + smr_val |= serial_port_in(port, SCSMR) & 3; 1927 1868 1928 1869 uart_update_timeout(port, termios->c_cflag, baud); 1929 1870