Root/target/linux/ar71xx/patches-3.3/211-ar933x_uart-improve-serial-clock-calculation.patch

1--- a/drivers/tty/serial/ar933x_uart.c
2+++ b/drivers/tty/serial/ar933x_uart.c
3@@ -25,11 +25,19 @@
4 #include <linux/io.h>
5 #include <linux/irq.h>
6 
7+#include <asm/div64.h>
8+
9 #include <asm/mach-ath79/ar933x_uart.h>
10 #include <asm/mach-ath79/ar933x_uart_platform.h>
11 
12 #define DRIVER_NAME "ar933x-uart"
13 
14+#define AR933X_UART_MAX_SCALE 0xff
15+#define AR933X_UART_MAX_STEP 0xffff
16+
17+#define AR933X_UART_MIN_BAUD 300
18+#define AR933X_UART_MAX_BAUD 3000000
19+
20 #define AR933X_DUMMY_STATUS_RD 0x01
21 
22 static struct uart_driver ar933x_uart_driver;
23@@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_dr
24 struct ar933x_uart_port {
25     struct uart_port port;
26     unsigned int ier; /* shadow Interrupt Enable Register */
27+ unsigned int min_baud;
28+ unsigned int max_baud;
29 };
30 
31 static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
32@@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct
33 {
34 }
35 
36+/*
37+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
38+ */
39+static unsigned long ar933x_uart_get_baud(unsigned int clk,
40+ unsigned int scale,
41+ unsigned int step)
42+{
43+ u64 t;
44+ u32 div;
45+
46+ div = (2 << 16) * (scale + 1);
47+ t = clk;
48+ t *= step;
49+ t += (div / 2);
50+ do_div(t, div);
51+
52+ return t;
53+}
54+
55+static void ar933x_uart_get_scale_step(unsigned int clk,
56+ unsigned int baud,
57+ unsigned int *scale,
58+ unsigned int *step)
59+{
60+ unsigned int tscale;
61+ long min_diff;
62+
63+ *scale = 0;
64+ *step = 0;
65+
66+ min_diff = baud;
67+ for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
68+ u64 tstep;
69+ int diff;
70+
71+ tstep = baud * (tscale + 1);
72+ tstep *= (2 << 16);
73+ do_div(tstep, clk);
74+
75+ if (tstep > AR933X_UART_MAX_STEP)
76+ break;
77+
78+ diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
79+ if (diff < min_diff) {
80+ min_diff = diff;
81+ *scale = tscale;
82+ *step = tstep;
83+ }
84+ }
85+}
86+
87 static void ar933x_uart_set_termios(struct uart_port *port,
88                     struct ktermios *new,
89                     struct ktermios *old)
90@@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(stru
91     struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
92     unsigned int cs;
93     unsigned long flags;
94- unsigned int baud, scale;
95+ unsigned int baud, scale, step;
96 
97     /* Only CS8 is supported */
98     new->c_cflag &= ~CSIZE;
99@@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(stru
100     /* Mark/space parity is not supported */
101     new->c_cflag &= ~CMSPAR;
102 
103- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
104- scale = (port->uartclk / (16 * baud)) - 1;
105+ baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
106+ ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
107 
108     /*
109      * Ok, we're now changing the port state. Do it with
110@@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(stru
111      */
112     spin_lock_irqsave(&up->port.lock, flags);
113 
114+ /* disable the UART */
115+ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
116+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
117+
118     /* Update the per-port timeout. */
119     uart_update_timeout(port, new->c_cflag, baud);
120 
121@@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(stru
122         up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
123 
124     ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
125- scale << AR933X_UART_CLOCK_SCALE_S | 8192);
126+ scale << AR933X_UART_CLOCK_SCALE_S | step);
127 
128     /* setup configuration register */
129     ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
130@@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(stru
131     ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
132                 AR933X_UART_CS_HOST_INT_EN);
133 
134+ /* reenable the UART */
135+ ar933x_uart_rmw(up, AR933X_UART_CS_REG,
136+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
137+ AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
138+
139     spin_unlock_irqrestore(&up->port.lock, flags);
140 
141     if (tty_termios_baud_rate(new))
142@@ -401,6 +471,8 @@ static void ar933x_uart_config_port(stru
143 static int ar933x_uart_verify_port(struct uart_port *port,
144                    struct serial_struct *ser)
145 {
146+ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
147+
148     if (ser->type != PORT_UNKNOWN &&
149         ser->type != PORT_AR933X)
150         return -EINVAL;
151@@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struc
152     if (ser->irq < 0 || ser->irq >= NR_IRQS)
153         return -EINVAL;
154 
155- if (ser->baud_base < 28800)
156+ if (ser->baud_base < up->min_baud ||
157+ ser->baud_base > up->max_baud)
158         return -EINVAL;
159 
160     return 0;
161@@ -561,6 +634,7 @@ static int __devinit ar933x_uart_probe(s
162     struct uart_port *port;
163     struct resource *mem_res;
164     struct resource *irq_res;
165+ unsigned int baud;
166     int id;
167     int ret;
168 
169@@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(s
170     port->fifosize = AR933X_UART_FIFO_SIZE;
171     port->ops = &ar933x_uart_ops;
172 
173+ baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
174+ up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
175+
176+ baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
177+ up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
178+
179     ar933x_uart_add_console_port(up);
180 
181     ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
182

Archive Download this file



interactive