Merge xburst target.
[openwrt.git] / target / linux / xburst / patches-2.6.32 / 103-serial.patch
1 From 5b3f9de4171368d9a99fa4c8b8b1bcc8505fb3c6 Mon Sep 17 00:00:00 2001
2 From: Lars-Peter Clausen <lars@metafoo.de>
3 Date: Mon, 11 Jan 2010 04:29:44 +0100
4 Subject: [PATCH] /opt/Projects/openwrt/target/linux/xburst/patches-2.6.31/103-serial.patch
5
6 ---
7  drivers/serial/8250.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++++-
8  1 files changed, 103 insertions(+), 1 deletions(-)
9
10 diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
11 index 737b4c9..65ee974 100644
12 --- a/drivers/serial/8250.c
13 +++ b/drivers/serial/8250.c
14 @@ -196,7 +196,7 @@ static const struct serial8250_config uart_config[] = {
15         [PORT_16550A] = {
16                 .name           = "16550A",
17                 .fifo_size      = 16,
18 -               .tx_loadsz      = 16,
19 +               .tx_loadsz      = 8,
20                 .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
21                 .flags          = UART_CAP_FIFO,
22         },
23 @@ -403,6 +403,10 @@ static unsigned int mem_serial_in(struct uart_port *p, int offset)
24  static void mem_serial_out(struct uart_port *p, int offset, int value)
25  {
26         offset = map_8250_out_reg(p, offset) << p->regshift;
27 +#if defined(CONFIG_JZSOC)
28 +               if (offset == (UART_FCR << p->regshift))
29 +                       value |= 0x10; /* set FCR.UUE */
30 +#endif
31         writeb(value, p->membase + offset);
32  }
33  
34 @@ -2215,6 +2219,83 @@ static void serial8250_shutdown(struct uart_port *port)
35                 serial_unlink_irq_chain(up);
36  }
37  
38 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
39 +static unsigned short quot1[3] = {0}; /* quot[0]:baud_div, quot[1]:umr, quot[2]:uacr */
40 +static unsigned short * serial8250_get_divisor(struct uart_port *port, unsigned int baud)
41 +{
42 +       int err, sum, i, j;
43 +       int a[12], b[12];
44 +       unsigned short div, umr, uacr;
45 +       unsigned short umr_best, div_best, uacr_best;
46 +       long long t0, t1, t2, t3;
47 +
48 +       sum = 0;
49 +       umr_best = div_best = uacr_best = 0;
50 +       div = 1;
51 +
52 +       if ((port->uartclk % (16 * baud)) == 0) {
53 +               quot1[0] = port->uartclk / (16 * baud);
54 +               quot1[1] = 16;
55 +               quot1[2] = 0;
56 +               return quot1;
57 +       }
58 +
59 +       while (1) {
60 +               umr = port->uartclk / (baud * div);
61 +               if (umr > 32) {
62 +                       div++;
63 +                       continue;
64 +               }
65 +               if (umr < 4) {
66 +                       break;
67 +               }
68 +               for (i = 0; i < 12; i++) {
69 +                       a[i] = umr;
70 +                       b[i] = 0;
71 +                       sum = 0;
72 +                       for (j = 0; j <= i; j++) {
73 +                               sum += a[j];
74 +                       }
75 +
76 +                        /* the precision could be 1/2^(36) due to the value of t0 */
77 +                       t0 = 0x1000000000LL;
78 +                       t1 = (i + 1) * t0;
79 +                       t2 = (sum * div) * t0;
80 +                       t3 = div * t0;
81 +                       do_div(t1, baud);
82 +                       do_div(t2, port->uartclk);
83 +                       do_div(t3, (2 * port->uartclk));
84 +                       err = t1 - t2 - t3;
85 +
86 +                       if (err > 0) {
87 +                               a[i] += 1;
88 +                               b[i] = 1;
89 +                       }
90 +               }
91 +
92 +               uacr = 0;
93 +               for (i = 0; i < 12; i++) {
94 +                       if (b[i] == 1) {
95 +                               uacr |= 1 << i;
96 +                       }
97 +               }
98 +
99 +                /* the best value of umr should be near 16, and the value of uacr should better be smaller */
100 +               if (abs(umr - 16) < abs(umr_best - 16) || (abs(umr - 16) == abs(umr_best - 16) && uacr_best > uacr)) {
101 +                       div_best = div;
102 +                       umr_best = umr;
103 +                       uacr_best = uacr;
104 +               }
105 +               div++;
106 +       }
107 +
108 +       quot1[0] = div_best;
109 +       quot1[1] = umr_best;
110 +       quot1[2] = uacr_best;
111 +
112 +       return quot1;
113 +}
114 +#else
115  static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
116  {
117         unsigned int quot;
118 @@ -2234,6 +2315,7 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
119  
120         return quot;
121  }
122 +#endif
123  
124  static void
125  serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
126 @@ -2243,6 +2325,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
127         unsigned char cval, fcr = 0;
128         unsigned long flags;
129         unsigned int baud, quot;
130 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
131 +       unsigned short *quot1;
132 +#endif
133  
134         switch (termios->c_cflag & CSIZE) {
135         case CS5:
136 @@ -2277,7 +2362,12 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
137         baud = uart_get_baud_rate(port, termios, old,
138                                   port->uartclk / 16 / 0xffff,
139                                   port->uartclk / 16);
140 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
141 +       quot1 = serial8250_get_divisor(port, baud);
142 +       quot = quot1[0]; /* not usefull, just let gcc happy */
143 +#else
144         quot = serial8250_get_divisor(port, baud);
145 +#endif
146  
147         /*
148          * Oxford Semi 952 rev B workaround
149 @@ -2355,6 +2445,10 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
150         if (up->capabilities & UART_CAP_UUE)
151                 up->ier |= UART_IER_UUE | UART_IER_RTOIE;
152  
153 +#ifdef CONFIG_JZSOC
154 +       up->ier |= UART_IER_RTOIE; /* Set this flag, or very slow */
155 +#endif
156 +
157         serial_out(up, UART_IER, up->ier);
158  
159         if (up->capabilities & UART_CAP_EFR) {
160 @@ -2389,7 +2483,15 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
161                 serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
162         }
163  
164 +#if defined(CONFIG_JZSOC) && !defined(CONFIG_SOC_JZ4730)
165 +#define UART_UMR  9
166 +#define UART_UACR 10
167 +       serial_dl_write(up, quot1[0]);
168 +       serial_outp(up, UART_UMR, quot1[1]);
169 +       serial_outp(up, UART_UACR, quot1[2]);
170 +#else
171         serial_dl_write(up, quot);
172 +#endif
173  
174         /*
175          * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
176 -- 
177 1.5.6.5
178