--- /dev/null
+From 2dff8ad92661b6c99e9ba8b5918e43b522551556 Mon Sep 17 00:00:00 2001
+From: Gabor Juhos <juhosg@openwrt.org>
+Date: Wed, 14 Nov 2012 10:38:13 +0100
+Subject: [PATCH] tty/serial/ar933x_uart: fix baud rate calculation
+
+commit 2dff8ad92661b6c99e9ba8b5918e43b522551556 upstream.
+
+The UART of the AR933x SoC implements a fractional divisor
+for generating the desired baud rate.
+
+The current code uses a fixed value for the fractional
+part of the divisor, and this leads to improperly
+calculated baud rates:
+
+ baud scale step real baud diff
+ 300 5207* 8192 17756 17456 5818.66%
+ 600 2603* 8192 35511 34911 5818.50%
+ 1200 1301* 8192 71023 69823 5818.58%
+ 2400 650* 8192 11241 8841 368.37%
+ 4800 324* 8192 22645 17845 371.77%
+ 9600 161 8192 9645 45 0.46%
+ 14400 107 8192 14468 68 0.47%
+ 19200 80 8192 19290 90 0.46%
+ 28800 53 8192 28935 135 0.46%
+ 38400 39 8192 39063 663 1.72%
+ 57600 26 8192 57870 270 0.46%
+ 115200 12 8192 120192 4992 4.33%
+ 230400 5 8192 260417 30017 13.02%
+ 460800 2 8192 520833 60033 13.02%
+ 921600 0 8192 1562500 640900 69.93%
+
+After the patch, the integer and fractional parts of the
+divisor will be calculated dynamically. This ensures that
+the UART will use correct baud rates:
+
+ baud scale step real baud diff
+ 300 6 11 300 0 0.00%
+ 600 54 173 600 0 0.00%
+ 1200 30 195 1200 0 0.00%
+ 2400 30 390 2400 0 0.00%
+ 4800 48 1233 4800 0 0.00%
+ 9600 78 3976 9600 0 0.00%
+ 14400 98 7474 14400 0 0.00%
+ 19200 55 5637 19200 0 0.00%
+ 28800 130 19780 28800 0 0.00%
+ 38400 36 7449 38400 0 0.00%
+ 57600 78 23857 57600 0 0.00%
+ 115200 43 26575 115200 0 0.00%
+ 230400 23 28991 230400 0 0.00%
+ 460800 11 28991 460800 0 0.00%
+ 921600 5 28991 921599 -1 0.00%
+
+Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/tty/serial/ar933x_uart.c | 90 +++++++++++++++++++++++++++++++++++---
+ 1 file changed, 85 insertions(+), 5 deletions(-)
+
+--- a/drivers/tty/serial/ar933x_uart.c
++++ b/drivers/tty/serial/ar933x_uart.c
+@@ -25,11 +25,19 @@
+ #include <linux/io.h>
+ #include <linux/irq.h>
+
++#include <asm/div64.h>
++
+ #include <asm/mach-ath79/ar933x_uart.h>
+ #include <asm/mach-ath79/ar933x_uart_platform.h>
+
+ #define DRIVER_NAME "ar933x-uart"
+
++#define AR933X_UART_MAX_SCALE 0xff
++#define AR933X_UART_MAX_STEP 0xffff
++
++#define AR933X_UART_MIN_BAUD 300
++#define AR933X_UART_MAX_BAUD 3000000
++
+ #define AR933X_DUMMY_STATUS_RD 0x01
+
+ static struct uart_driver ar933x_uart_driver;
+@@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_dr
+ struct ar933x_uart_port {
+ struct uart_port port;
+ unsigned int ier; /* shadow Interrupt Enable Register */
++ unsigned int min_baud;
++ unsigned int max_baud;
+ };
+
+ static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
+@@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct
+ {
+ }
+
++/*
++ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
++ */
++static unsigned long ar933x_uart_get_baud(unsigned int clk,
++ unsigned int scale,
++ unsigned int step)
++{
++ u64 t;
++ u32 div;
++
++ div = (2 << 16) * (scale + 1);
++ t = clk;
++ t *= step;
++ t += (div / 2);
++ do_div(t, div);
++
++ return t;
++}
++
++static void ar933x_uart_get_scale_step(unsigned int clk,
++ unsigned int baud,
++ unsigned int *scale,
++ unsigned int *step)
++{
++ unsigned int tscale;
++ long min_diff;
++
++ *scale = 0;
++ *step = 0;
++
++ min_diff = baud;
++ for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
++ u64 tstep;
++ int diff;
++
++ tstep = baud * (tscale + 1);
++ tstep *= (2 << 16);
++ do_div(tstep, clk);
++
++ if (tstep > AR933X_UART_MAX_STEP)
++ break;
++
++ diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
++ if (diff < min_diff) {
++ min_diff = diff;
++ *scale = tscale;
++ *step = tstep;
++ }
++ }
++}
++
+ static void ar933x_uart_set_termios(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
+@@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(stru
+ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
+ unsigned int cs;
+ unsigned long flags;
+- unsigned int baud, scale;
++ unsigned int baud, scale, step;
+
+ /* Only CS8 is supported */
+ new->c_cflag &= ~CSIZE;
+@@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(stru
+ /* Mark/space parity is not supported */
+ new->c_cflag &= ~CMSPAR;
+
+- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+- scale = (port->uartclk / (16 * baud)) - 1;
++ baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
++ ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
+
+ /*
+ * Ok, we're now changing the port state. Do it with
+@@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(stru
+ */
+ spin_lock_irqsave(&up->port.lock, flags);
+
++ /* disable the UART */
++ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
++ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
++
+ /* Update the per-port timeout. */
+ uart_update_timeout(port, new->c_cflag, baud);
+
+@@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(stru
+ up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
+
+ ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
+- scale << AR933X_UART_CLOCK_SCALE_S | 8192);
++ scale << AR933X_UART_CLOCK_SCALE_S | step);
+
+ /* setup configuration register */
+ ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
+@@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(stru
+ ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
+ AR933X_UART_CS_HOST_INT_EN);
+
++ /* reenable the UART */
++ ar933x_uart_rmw(up, AR933X_UART_CS_REG,
++ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
++ AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
++
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ if (tty_termios_baud_rate(new))
+@@ -401,6 +471,8 @@ static void ar933x_uart_config_port(stru
+ static int ar933x_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+ {
++ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
++
+ if (ser->type != PORT_UNKNOWN &&
+ ser->type != PORT_AR933X)
+ return -EINVAL;
+@@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struc
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ return -EINVAL;
+
+- if (ser->baud_base < 28800)
++ if (ser->baud_base < up->min_baud ||
++ ser->baud_base > up->max_baud)
+ return -EINVAL;
+
+ return 0;
+@@ -561,6 +634,7 @@ static int __devinit ar933x_uart_probe(s
+ struct uart_port *port;
+ struct resource *mem_res;
+ struct resource *irq_res;
++ unsigned int baud;
+ int id;
+ int ret;
+
+@@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(s
+ port->fifosize = AR933X_UART_FIFO_SIZE;
+ port->ops = &ar933x_uart_ops;
+
++ baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
++ up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
++
++ baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
++ up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
++
+ ar933x_uart_add_console_port(up);
+
+ ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
+++ /dev/null
-From 2dff8ad92661b6c99e9ba8b5918e43b522551556 Mon Sep 17 00:00:00 2001
-From: Gabor Juhos <juhosg@openwrt.org>
-Date: Wed, 14 Nov 2012 10:38:13 +0100
-Subject: [PATCH] tty/serial/ar933x_uart: fix baud rate calculation
-
-commit 2dff8ad92661b6c99e9ba8b5918e43b522551556 upstream.
-
-The UART of the AR933x SoC implements a fractional divisor
-for generating the desired baud rate.
-
-The current code uses a fixed value for the fractional
-part of the divisor, and this leads to improperly
-calculated baud rates:
-
- baud scale step real baud diff
- 300 5207* 8192 17756 17456 5818.66%
- 600 2603* 8192 35511 34911 5818.50%
- 1200 1301* 8192 71023 69823 5818.58%
- 2400 650* 8192 11241 8841 368.37%
- 4800 324* 8192 22645 17845 371.77%
- 9600 161 8192 9645 45 0.46%
- 14400 107 8192 14468 68 0.47%
- 19200 80 8192 19290 90 0.46%
- 28800 53 8192 28935 135 0.46%
- 38400 39 8192 39063 663 1.72%
- 57600 26 8192 57870 270 0.46%
- 115200 12 8192 120192 4992 4.33%
- 230400 5 8192 260417 30017 13.02%
- 460800 2 8192 520833 60033 13.02%
- 921600 0 8192 1562500 640900 69.93%
-
-After the patch, the integer and fractional parts of the
-divisor will be calculated dynamically. This ensures that
-the UART will use correct baud rates:
-
- baud scale step real baud diff
- 300 6 11 300 0 0.00%
- 600 54 173 600 0 0.00%
- 1200 30 195 1200 0 0.00%
- 2400 30 390 2400 0 0.00%
- 4800 48 1233 4800 0 0.00%
- 9600 78 3976 9600 0 0.00%
- 14400 98 7474 14400 0 0.00%
- 19200 55 5637 19200 0 0.00%
- 28800 130 19780 28800 0 0.00%
- 38400 36 7449 38400 0 0.00%
- 57600 78 23857 57600 0 0.00%
- 115200 43 26575 115200 0 0.00%
- 230400 23 28991 230400 0 0.00%
- 460800 11 28991 460800 0 0.00%
- 921600 5 28991 921599 -1 0.00%
-
-Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/tty/serial/ar933x_uart.c | 90 +++++++++++++++++++++++++++++++++++---
- 1 file changed, 85 insertions(+), 5 deletions(-)
-
---- a/drivers/tty/serial/ar933x_uart.c
-+++ b/drivers/tty/serial/ar933x_uart.c
-@@ -25,11 +25,19 @@
- #include <linux/io.h>
- #include <linux/irq.h>
-
-+#include <asm/div64.h>
-+
- #include <asm/mach-ath79/ar933x_uart.h>
- #include <asm/mach-ath79/ar933x_uart_platform.h>
-
- #define DRIVER_NAME "ar933x-uart"
-
-+#define AR933X_UART_MAX_SCALE 0xff
-+#define AR933X_UART_MAX_STEP 0xffff
-+
-+#define AR933X_UART_MIN_BAUD 300
-+#define AR933X_UART_MAX_BAUD 3000000
-+
- #define AR933X_DUMMY_STATUS_RD 0x01
-
- static struct uart_driver ar933x_uart_driver;
-@@ -37,6 +45,8 @@ static struct uart_driver ar933x_uart_dr
- struct ar933x_uart_port {
- struct uart_port port;
- unsigned int ier; /* shadow Interrupt Enable Register */
-+ unsigned int min_baud;
-+ unsigned int max_baud;
- };
-
- static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
-@@ -162,6 +172,57 @@ static void ar933x_uart_enable_ms(struct
- {
- }
-
-+/*
-+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
-+ */
-+static unsigned long ar933x_uart_get_baud(unsigned int clk,
-+ unsigned int scale,
-+ unsigned int step)
-+{
-+ u64 t;
-+ u32 div;
-+
-+ div = (2 << 16) * (scale + 1);
-+ t = clk;
-+ t *= step;
-+ t += (div / 2);
-+ do_div(t, div);
-+
-+ return t;
-+}
-+
-+static void ar933x_uart_get_scale_step(unsigned int clk,
-+ unsigned int baud,
-+ unsigned int *scale,
-+ unsigned int *step)
-+{
-+ unsigned int tscale;
-+ long min_diff;
-+
-+ *scale = 0;
-+ *step = 0;
-+
-+ min_diff = baud;
-+ for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
-+ u64 tstep;
-+ int diff;
-+
-+ tstep = baud * (tscale + 1);
-+ tstep *= (2 << 16);
-+ do_div(tstep, clk);
-+
-+ if (tstep > AR933X_UART_MAX_STEP)
-+ break;
-+
-+ diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
-+ if (diff < min_diff) {
-+ min_diff = diff;
-+ *scale = tscale;
-+ *step = tstep;
-+ }
-+ }
-+}
-+
- static void ar933x_uart_set_termios(struct uart_port *port,
- struct ktermios *new,
- struct ktermios *old)
-@@ -169,7 +230,7 @@ static void ar933x_uart_set_termios(stru
- struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
- unsigned int cs;
- unsigned long flags;
-- unsigned int baud, scale;
-+ unsigned int baud, scale, step;
-
- /* Only CS8 is supported */
- new->c_cflag &= ~CSIZE;
-@@ -191,8 +252,8 @@ static void ar933x_uart_set_termios(stru
- /* Mark/space parity is not supported */
- new->c_cflag &= ~CMSPAR;
-
-- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
-- scale = (port->uartclk / (16 * baud)) - 1;
-+ baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
-+ ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);
-
- /*
- * Ok, we're now changing the port state. Do it with
-@@ -200,6 +261,10 @@ static void ar933x_uart_set_termios(stru
- */
- spin_lock_irqsave(&up->port.lock, flags);
-
-+ /* disable the UART */
-+ ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
-+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);
-+
- /* Update the per-port timeout. */
- uart_update_timeout(port, new->c_cflag, baud);
-
-@@ -210,7 +275,7 @@ static void ar933x_uart_set_termios(stru
- up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;
-
- ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
-- scale << AR933X_UART_CLOCK_SCALE_S | 8192);
-+ scale << AR933X_UART_CLOCK_SCALE_S | step);
-
- /* setup configuration register */
- ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);
-@@ -219,6 +284,11 @@ static void ar933x_uart_set_termios(stru
- ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
- AR933X_UART_CS_HOST_INT_EN);
-
-+ /* reenable the UART */
-+ ar933x_uart_rmw(up, AR933X_UART_CS_REG,
-+ AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
-+ AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
-+
- spin_unlock_irqrestore(&up->port.lock, flags);
-
- if (tty_termios_baud_rate(new))
-@@ -401,6 +471,8 @@ static void ar933x_uart_config_port(stru
- static int ar933x_uart_verify_port(struct uart_port *port,
- struct serial_struct *ser)
- {
-+ struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
-+
- if (ser->type != PORT_UNKNOWN &&
- ser->type != PORT_AR933X)
- return -EINVAL;
-@@ -408,7 +480,8 @@ static int ar933x_uart_verify_port(struc
- if (ser->irq < 0 || ser->irq >= NR_IRQS)
- return -EINVAL;
-
-- if (ser->baud_base < 28800)
-+ if (ser->baud_base < up->min_baud ||
-+ ser->baud_base > up->max_baud)
- return -EINVAL;
-
- return 0;
-@@ -561,6 +634,7 @@ static int __devinit ar933x_uart_probe(s
- struct uart_port *port;
- struct resource *mem_res;
- struct resource *irq_res;
-+ unsigned int baud;
- int id;
- int ret;
-
-@@ -611,6 +685,12 @@ static int __devinit ar933x_uart_probe(s
- port->fifosize = AR933X_UART_FIFO_SIZE;
- port->ops = &ar933x_uart_ops;
-
-+ baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
-+ up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
-+
-+ baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
-+ up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
-+
- ar933x_uart_add_console_port(up);
-
- ret = uart_add_one_port(&ar933x_uart_driver, &up->port);