From a57b8e3d45b416f10bb2bb6ada96b2d69c938542 Mon Sep 17 00:00:00 2001 From: juhosg Date: Sat, 29 Dec 2012 13:52:38 +0000 Subject: ar71xx: use a backported patch to fix AR933x UART baud rate calculation Signed-off-by: Gabor Juhos git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34915 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- ...ial-ar933x_uart-fix-baud-rate-calculation.patch | 239 +++++++++++++++++++++ ...33x_uart-improve-serial-clock-calculation.patch | 181 ---------------- 2 files changed, 239 insertions(+), 181 deletions(-) create mode 100644 target/linux/ar71xx/patches-3.6/004-tty-serial-ar933x_uart-fix-baud-rate-calculation.patch delete mode 100644 target/linux/ar71xx/patches-3.6/211-ar933x_uart-improve-serial-clock-calculation.patch diff --git a/target/linux/ar71xx/patches-3.6/004-tty-serial-ar933x_uart-fix-baud-rate-calculation.patch b/target/linux/ar71xx/patches-3.6/004-tty-serial-ar933x_uart-fix-baud-rate-calculation.patch new file mode 100644 index 000000000..44eebabb1 --- /dev/null +++ b/target/linux/ar71xx/patches-3.6/004-tty-serial-ar933x_uart-fix-baud-rate-calculation.patch @@ -0,0 +1,239 @@ +From 2dff8ad92661b6c99e9ba8b5918e43b522551556 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + ++#include ++ + #include + #include + + #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); diff --git a/target/linux/ar71xx/patches-3.6/211-ar933x_uart-improve-serial-clock-calculation.patch b/target/linux/ar71xx/patches-3.6/211-ar933x_uart-improve-serial-clock-calculation.patch deleted file mode 100644 index 510b75ed0..000000000 --- a/target/linux/ar71xx/patches-3.6/211-ar933x_uart-improve-serial-clock-calculation.patch +++ /dev/null @@ -1,181 +0,0 @@ ---- a/drivers/tty/serial/ar933x_uart.c -+++ b/drivers/tty/serial/ar933x_uart.c -@@ -25,11 +25,19 @@ - #include - #include - -+#include -+ - #include - #include - - #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); -- cgit v1.2.3