ar71xx: use a backported patch to fix AR933x UART baud rate calculation
[openwrt.git] / target / linux / ar71xx / patches-3.6 / 004-tty-serial-ar933x_uart-fix-baud-rate-calculation.patch
1 From 2dff8ad92661b6c99e9ba8b5918e43b522551556 Mon Sep 17 00:00:00 2001
2 From: Gabor Juhos <juhosg@openwrt.org>
3 Date: Wed, 14 Nov 2012 10:38:13 +0100
4 Subject: [PATCH] tty/serial/ar933x_uart: fix baud rate calculation
5
6 commit 2dff8ad92661b6c99e9ba8b5918e43b522551556 upstream.
7
8 The UART of the AR933x SoC implements a fractional divisor
9 for generating the desired baud rate.
10
11 The current code uses a fixed value for the fractional
12 part of the divisor, and this leads to improperly
13 calculated baud rates:
14
15    baud    scale   step  real baud         diff
16      300   5207*   8192     17756     17456   5818.66%
17      600   2603*   8192     35511     34911   5818.50%
18     1200   1301*   8192     71023     69823   5818.58%
19     2400    650*   8192     11241      8841    368.37%
20     4800    324*   8192     22645     17845    371.77%
21     9600    161    8192      9645        45      0.46%
22    14400    107    8192     14468        68      0.47%
23    19200     80    8192     19290        90      0.46%
24    28800     53    8192     28935       135      0.46%
25    38400     39    8192     39063       663      1.72%
26    57600     26    8192     57870       270      0.46%
27   115200     12    8192    120192      4992      4.33%
28   230400      5    8192    260417     30017     13.02%
29   460800      2    8192    520833     60033     13.02%
30   921600      0    8192   1562500    640900     69.93%
31
32 After the patch, the integer and fractional parts of the
33 divisor will be calculated dynamically. This ensures that
34 the UART will use correct baud rates:
35
36    baud    scale   step  real baud         diff
37      300      6      11       300         0      0.00%
38      600     54     173       600         0      0.00%
39     1200     30     195      1200         0      0.00%
40     2400     30     390      2400         0      0.00%
41     4800     48    1233      4800         0      0.00%
42     9600     78    3976      9600         0      0.00%
43    14400     98    7474     14400         0      0.00%
44    19200     55    5637     19200         0      0.00%
45    28800    130   19780     28800         0      0.00%
46    38400     36    7449     38400         0      0.00%
47    57600     78   23857     57600         0      0.00%
48   115200     43   26575    115200         0      0.00%
49   230400     23   28991    230400         0      0.00%
50   460800     11   28991    460800         0      0.00%
51   921600      5   28991    921599        -1      0.00%
52
53 Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
54 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
55 ---
56  drivers/tty/serial/ar933x_uart.c |   90 +++++++++++++++++++++++++++++++++++---
57  1 file changed, 85 insertions(+), 5 deletions(-)
58
59 --- a/drivers/tty/serial/ar933x_uart.c
60 +++ b/drivers/tty/serial/ar933x_uart.c
61 @@ -25,11 +25,19 @@
62  #include <linux/io.h>
63  #include <linux/irq.h>
64  
65 +#include <asm/div64.h>
66 +
67  #include <asm/mach-ath79/ar933x_uart.h>
68  #include <asm/mach-ath79/ar933x_uart_platform.h>
69  
70  #define DRIVER_NAME "ar933x-uart"
71  
72 +#define AR933X_UART_MAX_SCALE  0xff
73 +#define AR933X_UART_MAX_STEP   0xffff
74 +
75 +#define AR933X_UART_MIN_BAUD   300
76 +#define AR933X_UART_MAX_BAUD   3000000
77 +
78  #define AR933X_DUMMY_STATUS_RD 0x01
79  
80  static struct uart_driver ar933x_uart_driver;
81 @@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_dr
82  struct ar933x_uart_port {
83         struct uart_port        port;
84         unsigned int            ier;    /* shadow Interrupt Enable Register */
85 +       unsigned int            min_baud;
86 +       unsigned int            max_baud;
87  };
88  
89  static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
90 @@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct
91  {
92  }
93  
94 +/*
95 + * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
96 + */
97 +static unsigned long ar933x_uart_get_baud(unsigned int clk,
98 +                                         unsigned int scale,
99 +                                         unsigned int step)
100 +{
101 +       u64 t;
102 +       u32 div;
103 +
104 +       div = (2 << 16) * (scale + 1);
105 +       t = clk;
106 +       t *= step;
107 +       t += (div / 2);
108 +       do_div(t, div);
109 +
110 +       return t;
111 +}
112 +
113 +static void ar933x_uart_get_scale_step(unsigned int clk,
114 +                                      unsigned int baud,
115 +                                      unsigned int *scale,
116 +                                      unsigned int *step)
117 +{
118 +       unsigned int tscale;
119 +       long min_diff;
120 +
121 +       *scale = 0;
122 +       *step = 0;
123 +
124 +       min_diff = baud;
125 +       for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
126 +               u64 tstep;
127 +               int diff;
128 +
129 +               tstep = baud * (tscale + 1);
130 +               tstep *= (2 << 16);
131 +               do_div(tstep, clk);
132 +
133 +               if (tstep > AR933X_UART_MAX_STEP)
134 +                       break;
135 +
136 +               diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
137 +               if (diff < min_diff) {
138 +                       min_diff = diff;
139 +                       *scale = tscale;
140 +                       *step = tstep;
141 +               }
142 +       }
143 +}
144 +
145  static void ar933x_uart_set_termios(struct uart_port *port,
146                                     struct ktermios *new,
147                                     struct ktermios *old)
148 @@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(stru
149         struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
150         unsigned int cs;
151         unsigned long flags;
152 -       unsigned int baud, scale;
153 +       unsigned int baud, scale, step;
154  
155         /* Only CS8 is supported */
156         new->c_cflag &= ~CSIZE;
157 @@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(stru
158         /* Mark/space parity is not supported */
159         new->c_cflag &= ~CMSPAR;
160  
161 -       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
162 -       scale = (port->uartclk / (16 * baud)) - 1;
163 +       baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
164 +       ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
165  
166         /*
167          * Ok, we're now changing the port state. Do it with
168 @@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(stru
169          */
170         spin_lock_irqsave(&up->port.lock, flags);
171  
172 +       /* disable the UART */
173 +       ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
174 +                     AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
175 +
176         /* Update the per-port timeout. */
177         uart_update_timeout(port, new->c_cflag, baud);
178  
179 @@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(stru
180                 up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
181  
182         ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
183 -                         scale << AR933X_UART_CLOCK_SCALE_S | 8192);
184 +                         scale << AR933X_UART_CLOCK_SCALE_S | step);
185  
186         /* setup configuration register */
187         ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
188 @@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(stru
189         ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
190                             AR933X_UART_CS_HOST_INT_EN);
191  
192 +       /* reenable the UART */
193 +       ar933x_uart_rmw(up, AR933X_UART_CS_REG,
194 +                       AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
195 +                       AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
196 +
197         spin_unlock_irqrestore(&up->port.lock, flags);
198  
199         if (tty_termios_baud_rate(new))
200 @@ -401,6 +471,8 @@ static void ar933x_uart_config_port(stru
201  static int ar933x_uart_verify_port(struct uart_port *port,
202                                    struct serial_struct *ser)
203  {
204 +       struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
205 +
206         if (ser->type != PORT_UNKNOWN &&
207             ser->type != PORT_AR933X)
208                 return -EINVAL;
209 @@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struc
210         if (ser->irq < 0 || ser->irq >= NR_IRQS)
211                 return -EINVAL;
212  
213 -       if (ser->baud_base < 28800)
214 +       if (ser->baud_base < up->min_baud ||
215 +           ser->baud_base > up->max_baud)
216                 return -EINVAL;
217  
218         return 0;
219 @@ -561,6 +634,7 @@ static int __devinit ar933x_uart_probe(s
220         struct uart_port *port;
221         struct resource *mem_res;
222         struct resource *irq_res;
223 +       unsigned int baud;
224         int id;
225         int ret;
226  
227 @@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(s
228         port->fifosize = AR933X_UART_FIFO_SIZE;
229         port->ops = &ar933x_uart_ops;
230  
231 +       baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
232 +       up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
233 +
234 +       baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
235 +       up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
236 +
237         ar933x_uart_add_console_port(up);
238  
239         ret = uart_add_one_port(&ar933x_uart_driver, &up->port);