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