From e2afca6988c335d2ec7b66f2fadcd63286570bf8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 13:40:31 +0100 Subject: [PATCH 01/14] serial: sh-sci: Fix warnings due to improper casts and printk formats Use the %zu and %pad printk specifiers to print size_t and dma_addr_t variables, and cast pointers to uintptr_t instead of unsigned int where applicable. This fixes warnings on platforms where pointers and/or dma_addr_t have a different size than int. Cc: linux-serial@vger.kernel.org Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7d8103cd3e2e..6e5ce628b4eb 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -557,7 +557,7 @@ static inline int sci_rxd_in(struct uart_port *port) return 1; /* Cast for ARM damage */ - return !!__raw_readb((void __iomem *)s->cfg->port_reg); + return !!__raw_readb((void __iomem *)(uintptr_t)s->cfg->port_reg); } /* ********************************************************************** * @@ -1309,7 +1309,7 @@ static int sci_dma_rx_push(struct sci_port *s, size_t count) } if (room < count) - dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", + dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", count - room); if (!room) return room; @@ -1442,7 +1442,7 @@ static void work_fn_rx(struct work_struct *work) int count; chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); - dev_dbg(port->dev, "Read %u bytes with cookie %d\n", + dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", sh_desc->partial, sh_desc->cookie); spin_lock_irqsave(&port->lock, flags); @@ -1691,16 +1691,17 @@ static void sci_request_dma(struct uart_port *port) s->chan_tx = chan; sg_init_table(&s->sg_tx, 1); /* UART circular tx buffer is an aligned page. */ - BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK); + BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK); sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK); + UART_XMIT_SIZE, + (uintptr_t)port->state->xmit.buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); if (!nent) sci_tx_dma_release(s, false); else - dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, - sg_dma_len(&s->sg_tx), - port->state->xmit.buf, sg_dma_address(&s->sg_tx)); + dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__, + sg_dma_len(&s->sg_tx), port->state->xmit.buf, + &sg_dma_address(&s->sg_tx)); s->sg_len_tx = nent; @@ -1740,7 +1741,7 @@ static void sci_request_dma(struct uart_port *port) sg_init_table(sg, 1); sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, - (int)buf[i] & ~PAGE_MASK); + (uintptr_t)buf[i] & ~PAGE_MASK); sg_dma_address(sg) = dma[i]; } From caec70381b469d6ed1bd3d0441a19aa6de0bbff3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 28 Nov 2013 18:11:45 +0100 Subject: [PATCH 02/14] serial: sh-sci: Don't enable/disable port from within break timer The break timer accesses hardware registers and thus requires the port to be enabled. It currently ensures this by enabling the port at the beginning of the timer handler, and disabling it at the end. However, the enable/disable operations call the runtime PM sync functions, which are not allowed in atomic context. The current situation is thus broken. This change relies on non-atomic code to enable/disable the port. The break timer will only be started from the IRQ handler, which already runs with the port enabled. We just need to ensure that the port won't be disabled with the timer running, and that's easily done by just cancelling the timer in the port disable function. Signed-off-by: Laurent Pinchart Acked-by: Magnus Damm Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 6e5ce628b4eb..1ebac3e9e53a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -431,6 +431,14 @@ static void sci_port_disable(struct sci_port *sci_port) if (!sci_port->port.dev) return; + /* Cancel the break timer to ensure that the timer handler will not try + * to access the hardware with clocks and power disabled. Reset the + * break flag to make the break debouncing state machine ready for the + * next break. + */ + del_timer_sync(&sci_port->break_timer); + sci_port->break_flag = 0; + clk_disable(sci_port->fclk); clk_disable(sci_port->iclk); @@ -733,8 +741,6 @@ static void sci_break_timer(unsigned long data) { struct sci_port *port = (struct sci_port *)data; - sci_port_enable(port); - if (sci_rxd_in(&port->port) == 0) { port->break_flag = 1; sci_schedule_break_timer(port); @@ -744,8 +750,6 @@ static void sci_break_timer(unsigned long data) sci_schedule_break_timer(port); } else port->break_flag = 0; - - sci_port_disable(port); } static int sci_handle_errors(struct uart_port *port) From b016b646e8676858f39ea9be760494b04b9ee0af Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 28 Nov 2013 18:11:46 +0100 Subject: [PATCH 03/14] serial: sh-sci: Convert to clk_prepare/unprepare Turn clk_enable() and clk_disable() calls into clk_prepare_enable() and clk_disable_unprepare() to get ready for the migration to the common clock framework. Signed-off-by: Laurent Pinchart Acked-by: Magnus Damm Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 1ebac3e9e53a..1a3fc7a2e4db 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -421,9 +421,9 @@ static void sci_port_enable(struct sci_port *sci_port) pm_runtime_get_sync(sci_port->port.dev); - clk_enable(sci_port->iclk); + clk_prepare_enable(sci_port->iclk); sci_port->port.uartclk = clk_get_rate(sci_port->iclk); - clk_enable(sci_port->fclk); + clk_prepare_enable(sci_port->fclk); } static void sci_port_disable(struct sci_port *sci_port) @@ -439,8 +439,8 @@ static void sci_port_disable(struct sci_port *sci_port) del_timer_sync(&sci_port->break_timer); sci_port->break_flag = 0; - clk_disable(sci_port->fclk); - clk_disable(sci_port->iclk); + clk_disable_unprepare(sci_port->fclk); + clk_disable_unprepare(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } From 8fb9631c517b862267590e7af93615a6ef03394d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:10 +0100 Subject: [PATCH 04/14] serial: sh-sci: Sort headers alphabetically This helps locating duplicates. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 1a3fc7a2e4db..e98a217e2fc0 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -23,35 +23,35 @@ #undef DEBUG -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include -#include +#include +#include #include #include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef CONFIG_SUPERH #include From 6db201da2522d7dd231982ff7b83916cf4db3e41 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:11 +0100 Subject: [PATCH 05/14] serial: sh-sci: Remove baud rate calculation algorithm 5 The algorithm isn't used, remove it. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 2 -- include/linux/serial_sci.h | 1 - 2 files changed, 3 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e98a217e2fc0..eb59bb235a52 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1825,8 +1825,6 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, return (((freq * 2) + 16 * bps) / (16 * bps) - 1); case SCBRR_ALGO_4: return (((freq * 2) + 16 * bps) / (32 * bps) - 1); - case SCBRR_ALGO_5: - return (((freq * 1000 / 32) / bps) - 1); } /* Warn, but use a safe default */ diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 50fe651da965..babc5fe070b9 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -15,7 +15,6 @@ enum { SCBRR_ALGO_2, /* ((clk + 16 * bps) / (32 * bps) - 1) */ SCBRR_ALGO_3, /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */ SCBRR_ALGO_4, /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */ - SCBRR_ALGO_5, /* (((clk * 1000 / 32) / bps) - 1) */ SCBRR_ALGO_6, /* HSCIF variable sample rate algorithm */ }; From 6557b1f69ea0961efde7ab33bfe0cb7e3bfed54e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:12 +0100 Subject: [PATCH 06/14] serial: sh-sci: Simplify baud rate calculation algorithms Rewrite the baud rate register value calculations in easier to read forms. The computed value isn't modified. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 8 ++++---- include/linux/serial_sci.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index eb59bb235a52..f2fad4d8eb9e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1818,13 +1818,13 @@ static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, { switch (algo_id) { case SCBRR_ALGO_1: - return ((freq + 16 * bps) / (16 * bps) - 1); + return freq / (16 * bps); case SCBRR_ALGO_2: - return ((freq + 16 * bps) / (32 * bps) - 1); + return DIV_ROUND_CLOSEST(freq, 32 * bps) - 1; case SCBRR_ALGO_3: - return (((freq * 2) + 16 * bps) / (16 * bps) - 1); + return freq / (8 * bps); case SCBRR_ALGO_4: - return (((freq * 2) + 16 * bps) / (32 * bps) - 1); + return DIV_ROUND_CLOSEST(freq, 16 * bps) - 1; } /* Warn, but use a safe default */ diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index babc5fe070b9..12cf50c1c047 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -11,10 +11,10 @@ #define SCIx_NOT_SUPPORTED (-1) enum { - SCBRR_ALGO_1, /* ((clk + 16 * bps) / (16 * bps) - 1) */ - SCBRR_ALGO_2, /* ((clk + 16 * bps) / (32 * bps) - 1) */ - SCBRR_ALGO_3, /* (((clk * 2) + 16 * bps) / (16 * bps) - 1) */ - SCBRR_ALGO_4, /* (((clk * 2) + 16 * bps) / (32 * bps) - 1) */ + SCBRR_ALGO_1, /* clk / (16 * bps) */ + SCBRR_ALGO_2, /* DIV_ROUND_CLOSEST(clk, 32 * bps) - 1 */ + SCBRR_ALGO_3, /* clk / (8 * bps) */ + SCBRR_ALGO_4, /* DIV_ROUND_CLOSEST(clk, 16 * bps) - 1 */ SCBRR_ALGO_6, /* HSCIF variable sample rate algorithm */ }; From b5e17b71c6b2ff284b4018e272e18876ccfa9b2c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:13 +0100 Subject: [PATCH 07/14] serial: sh-sci: Remove duplicate interrupt check in verify port op The driver checks if the interrupt number is greater than nr_irqs and returns an error in that case. The same check is already performed by the caller, remove it. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index f2fad4d8eb9e..8c17d551f32b 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2120,7 +2120,7 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { struct sci_port *s = to_sci_port(port); - if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs) + if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ]) return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ From b6e4a3f18c0d289c7eed652dc0253a7f8fea27e4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:14 +0100 Subject: [PATCH 08/14] serial: sh-sci: Set the UPF_FIXED_PORT flag The base address, IRQ and baud rate generator parent clock rate can't be changed by userspace. Mark the port as fixed. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 8c17d551f32b..67dadbd97adb 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2248,7 +2248,7 @@ static int sci_init_single(struct platform_device *dev, port->mapbase = p->mapbase; port->type = p->type; - port->flags = p->flags; + port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; /* From bc14e00672b563f41a1ac1d421b5c78c94868983 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:15 +0100 Subject: [PATCH 09/14] serial: sh-sci: Don't check IRQ in verify port operation The IRQ number can't be modified by the user as the port is fixed. There's no need to check the new IRQ number as it will be ignored by the core. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 67dadbd97adb..b3d0e00ecedf 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2118,10 +2118,6 @@ static void sci_config_port(struct uart_port *port, int flags) static int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { - struct sci_port *s = to_sci_port(port); - - if (ser->irq != s->cfg->irqs[SCIx_TXI_IRQ]) - return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ return -EINVAL; From 1fcc91a607de0bf72d3a6073dfe459f7e9145ac5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:16 +0100 Subject: [PATCH 10/14] serial: sh-sci: Support resources passed through platform resources Memory and IRQ resources are currently passed to the driver through platform data. Support passing them through the standard platform resources mechanism instead. This deprecates platform data resources. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 65 ++++++++++++++++++++++++++++--------- include/linux/serial_sci.h | 8 ++--- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index b3d0e00ecedf..e9c6e2339884 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -74,6 +74,7 @@ struct sci_port { /* Function clock */ struct clk *fclk; + int irqs[SCIx_NR_IRQS]; char *irqstr[SCIx_NR_IRQS]; char *gpiostr[SCIx_NR_FNS]; @@ -1079,19 +1080,19 @@ static int sci_request_irq(struct sci_port *port) for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { struct sci_irq_desc *desc; - unsigned int irq; + int irq; if (SCIx_IRQ_IS_MUXED(port)) { i = SCIx_MUX_IRQ; irq = up->irq; } else { - irq = port->cfg->irqs[i]; + irq = port->irqs[i]; /* * Certain port types won't support all of the * available interrupt sources. */ - if (unlikely(!irq)) + if (unlikely(irq < 0)) continue; } @@ -1116,7 +1117,7 @@ static int sci_request_irq(struct sci_port *port) out_noirq: while (--i >= 0) - free_irq(port->cfg->irqs[i], port); + free_irq(port->irqs[i], port); out_nomem: while (--j >= 0) @@ -1134,16 +1135,16 @@ static void sci_free_irq(struct sci_port *port) * IRQ first. */ for (i = 0; i < SCIx_NR_IRQS; i++) { - unsigned int irq = port->cfg->irqs[i]; + int irq = port->irqs[i]; /* * Certain port types won't support all of the available * interrupt sources. */ - if (unlikely(!irq)) + if (unlikely(irq < 0)) continue; - free_irq(port->cfg->irqs[i], port); + free_irq(port->irqs[i], port); kfree(port->irqstr[i]); if (SCIx_IRQ_IS_MUXED(port)) { @@ -1659,7 +1660,7 @@ static void rx_timer_fn(unsigned long arg) if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { scr &= ~0x4000; - enable_irq(s->cfg->irqs[1]); + enable_irq(s->irqs[SCIx_RXI_IRQ]); } serial_port_out(port, SCSCR, scr | SCSCR_RIE); dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -2150,11 +2151,12 @@ static struct uart_ops sci_uart_ops = { }; static int sci_init_single(struct platform_device *dev, - struct sci_port *sci_port, - unsigned int index, - struct plat_sci_port *p) + struct sci_port *sci_port, unsigned int index, + struct plat_sci_port *p, bool early) { struct uart_port *port = &sci_port->port; + const struct resource *res; + unsigned int i; int ret; sci_port->cfg = p; @@ -2163,6 +2165,38 @@ static int sci_init_single(struct platform_device *dev, port->iotype = UPIO_MEM; port->line = index; + if (dev->num_resources) { + /* Device has resources, use them. */ + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENOMEM; + + port->mapbase = res->start; + + for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) + sci_port->irqs[i] = platform_get_irq(dev, i); + + /* The SCI generates several interrupts. They can be muxed + * together or connected to different interrupt lines. In the + * muxed case only one interrupt resource is specified. In the + * non-muxed case three or four interrupt resources are + * specified, as the BRI interrupt is optional. + */ + if (sci_port->irqs[0] < 0) + return -ENXIO; + + if (sci_port->irqs[1] < 0) { + sci_port->irqs[1] = sci_port->irqs[0]; + sci_port->irqs[2] = sci_port->irqs[0]; + sci_port->irqs[3] = sci_port->irqs[0]; + } + } else { + /* No resources, use old-style platform data. */ + port->mapbase = p->mapbase; + for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) + sci_port->irqs[i] = p->irqs[i] ? p->irqs[i] : -ENXIO; + } + switch (p->type) { case PORT_SCIFB: port->fifosize = 256; @@ -2187,7 +2221,7 @@ static int sci_init_single(struct platform_device *dev, return ret; } - if (dev) { + if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { sci_port->iclk = clk_get(&dev->dev, "peripheral_clk"); @@ -2242,7 +2276,6 @@ static int sci_init_single(struct platform_device *dev, p->error_mask |= (1 << p->overrun_bit); } - port->mapbase = p->mapbase; port->type = p->type; port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; @@ -2254,7 +2287,7 @@ static int sci_init_single(struct platform_device *dev, * * For the muxed case there's nothing more to do. */ - port->irq = p->irqs[SCIx_RXI_IRQ]; + port->irq = sci_port->irqs[SCIx_RXI_IRQ]; port->irqflags = 0; port->serial_in = sci_serial_in; @@ -2386,7 +2419,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev) early_serial_console.index = pdev->id; - sci_init_single(NULL, &sci_ports[pdev->id], pdev->id, cfg); + sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); serial_console_setup(&early_serial_console, early_serial_buf); @@ -2453,7 +2486,7 @@ static int sci_probe_single(struct platform_device *dev, return -EINVAL; } - ret = sci_init_single(dev, sciport, index, p); + ret = sci_init_single(dev, sciport, index, p, false); if (ret) return ret; diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 12cf50c1c047..42620f1dce82 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -107,10 +107,10 @@ enum { } #define SCIx_IRQ_IS_MUXED(port) \ - ((port)->cfg->irqs[SCIx_ERI_IRQ] == \ - (port)->cfg->irqs[SCIx_RXI_IRQ]) || \ - ((port)->cfg->irqs[SCIx_ERI_IRQ] && \ - !(port)->cfg->irqs[SCIx_RXI_IRQ]) + ((port)->irqs[SCIx_ERI_IRQ] == \ + (port)->irqs[SCIx_RXI_IRQ]) || \ + ((port)->irqs[SCIx_ERI_IRQ] && \ + ((port)->irqs[SCIx_RXI_IRQ] < 0)) /* * SCI register subset common for all port types. * Not all registers will exist on all parts. From 3ae988d97b160c07463b980ccf26ed9226660fef Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:17 +0100 Subject: [PATCH 11/14] serial: sh-sci: Move overrun_bit and error_mask fields out of pdata None of the fields is ever set by board code, and both of them are set in the driver at probe time. Move them out of struct plat_sci_port to struct sci_port. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 50 +++++++++++++++++-------------------- drivers/tty/serial/sh-sci.h | 2 +- include/linux/serial_sci.h | 3 --- 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e9c6e2339884..98b8e3c98586 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -64,6 +64,9 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; + int overrun_bit; + unsigned int error_mask; + /* Break timer */ struct timer_list break_timer; @@ -760,19 +763,15 @@ static int sci_handle_errors(struct uart_port *port) struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); - /* - * Handle overruns, if supported. - */ - if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) { - if (status & (1 << s->cfg->overrun_bit)) { - port->icount.overrun++; + /* Handle overruns */ + if (status & (1 << s->overrun_bit)) { + port->icount.overrun++; - /* overrun error */ - if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) - copied++; + /* overrun error */ + if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) + copied++; - dev_notice(port->dev, "overrun error"); - } + dev_notice(port->dev, "overrun error"); } if (status & SCxSR_FER(port)) { @@ -834,7 +833,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) if (!reg->size) return 0; - if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { + if ((serial_port_in(port, SCLSR) & (1 << s->overrun_bit))) { serial_port_out(port, SCLSR, 0); port->icount.overrun++; @@ -2253,28 +2252,25 @@ static int sci_init_single(struct platform_device *dev, /* * Establish some sensible defaults for the error detection. */ - if (!p->error_mask) - p->error_mask = (p->type == PORT_SCI) ? + sci_port->error_mask = (p->type == PORT_SCI) ? SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; /* * Establish sensible defaults for the overrun detection, unless * the part has explicitly disabled support for it. */ - if (p->overrun_bit != SCIx_NOT_SUPPORTED) { - if (p->type == PORT_SCI) - p->overrun_bit = 5; - else if (p->scbrr_algo_id == SCBRR_ALGO_4) - p->overrun_bit = 9; - else - p->overrun_bit = 0; + if (p->type == PORT_SCI) + sci_port->overrun_bit = 5; + else if (p->scbrr_algo_id == SCBRR_ALGO_4) + sci_port->overrun_bit = 9; + else + sci_port->overrun_bit = 0; - /* - * Make the error mask inclusive of overrun detection, if - * supported. - */ - p->error_mask |= (1 << p->overrun_bit); - } + /* + * Make the error mask inclusive of overrun detection, if + * supported. + */ + sci_port->error_mask |= 1 << sci_port->overrun_bit; port->type = p->type; port->flags = UPF_FIXED_PORT | p->flags; diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 5aca7364634c..d5db81a0a430 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -9,7 +9,7 @@ #define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) #define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) -#define SCxSR_ERRORS(port) (to_sci_port(port)->cfg->error_mask) +#define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask) #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ defined(CONFIG_CPU_SUBTYPE_SH7720) || \ diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index 42620f1dce82..af9834bc6771 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -152,9 +152,6 @@ struct plat_sci_port { /* * Platform overrides if necessary, defaults otherwise. */ - int overrun_bit; - unsigned int error_mask; - int port_reg; unsigned char regshift; unsigned char regtype; From 520402bbc6fe328ae28e08bfc87a2b1eb7f10b2c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:18 +0100 Subject: [PATCH 12/14] serial: sh-sci: Remove unused GPIO request code The driver requests at initialization time GPIOs passed through platform data. No platform makes use of this feature, remove it. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 67 ------------------------------------- include/linux/serial_sci.h | 12 ------- 2 files changed, 79 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 98b8e3c98586..99a64fd16d46 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -79,7 +78,6 @@ struct sci_port { int irqs[SCIx_NR_IRQS]; char *irqstr[SCIx_NR_IRQS]; - char *gpiostr[SCIx_NR_FNS]; struct dma_chan *chan_tx; struct dma_chan *chan_rx; @@ -1153,67 +1151,6 @@ static void sci_free_irq(struct sci_port *port) } } -static const char *sci_gpio_names[SCIx_NR_FNS] = { - "sck", "rxd", "txd", "cts", "rts", -}; - -static const char *sci_gpio_str(unsigned int index) -{ - return sci_gpio_names[index]; -} - -static void sci_init_gpios(struct sci_port *port) -{ - struct uart_port *up = &port->port; - int i; - - if (!port->cfg) - return; - - for (i = 0; i < SCIx_NR_FNS; i++) { - const char *desc; - int ret; - - if (!port->cfg->gpios[i]) - continue; - - desc = sci_gpio_str(i); - - port->gpiostr[i] = kasprintf(GFP_KERNEL, "%s:%s", - dev_name(up->dev), desc); - - /* - * If we've failed the allocation, we can still continue - * on with a NULL string. - */ - if (!port->gpiostr[i]) - dev_notice(up->dev, "%s string allocation failure\n", - desc); - - ret = gpio_request(port->cfg->gpios[i], port->gpiostr[i]); - if (unlikely(ret != 0)) { - dev_notice(up->dev, "failed %s gpio request\n", desc); - - /* - * If we can't get the GPIO for whatever reason, - * no point in keeping the verbose string around. - */ - kfree(port->gpiostr[i]); - } - } -} - -static void sci_free_gpios(struct sci_port *port) -{ - int i; - - for (i = 0; i < SCIx_NR_FNS; i++) - if (port->cfg->gpios[i]) { - gpio_free(port->cfg->gpios[i]); - kfree(port->gpiostr[i]); - } -} - static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = serial_port_in(port, SCxSR); @@ -2240,8 +2177,6 @@ static int sci_init_single(struct platform_device *dev, port->dev = &dev->dev; - sci_init_gpios(sci_port); - pm_runtime_enable(&dev->dev); } @@ -2298,8 +2233,6 @@ static int sci_init_single(struct platform_device *dev, static void sci_cleanup_single(struct sci_port *port) { - sci_free_gpios(port); - clk_put(port->iclk); clk_put(port->fclk); diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index af9834bc6771..e9c3021a37ae 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -69,17 +69,6 @@ enum { SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ }; -/* Offsets into the sci_port->gpios array */ -enum { - SCIx_SCK, - SCIx_RXD, - SCIx_TXD, - SCIx_CTS, - SCIx_RTS, - - SCIx_NR_FNS, -}; - enum { SCIx_PROBE_REGTYPE, @@ -141,7 +130,6 @@ struct plat_sci_port_ops { struct plat_sci_port { unsigned long mapbase; /* resource base */ unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */ - unsigned int gpios[SCIx_NR_FNS]; /* SCK, RXD, TXD, CTS, RTS */ unsigned int type; /* SCI / SCIF / IRDA / HSCIF */ upf_t flags; /* UPF_* flags */ unsigned long capabilities; /* Port features/capabilities */ From b545e4f40613be708ad660517f10c87423a09e8d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:19 +0100 Subject: [PATCH 13/14] serial: sh-sci: Compute overrun_bit without using baud rate algo The overrun bit index is a property of the hardware. It's currently computed based on a different and unrelated hardware property, the baud rate calculation algorithm. Compute it using hardware identification information only. Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 50 +++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 99a64fd16d46..d5239d5ff98b 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2133,30 +2133,38 @@ static int sci_init_single(struct platform_device *dev, sci_port->irqs[i] = p->irqs[i] ? p->irqs[i] : -ENXIO; } - switch (p->type) { - case PORT_SCIFB: - port->fifosize = 256; - break; - case PORT_HSCIF: - port->fifosize = 128; - break; - case PORT_SCIFA: - port->fifosize = 64; - break; - case PORT_SCIF: - port->fifosize = 16; - break; - default: - port->fifosize = 1; - break; - } - if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); if (unlikely(ret)) return ret; } + switch (p->type) { + case PORT_SCIFB: + port->fifosize = 256; + sci_port->overrun_bit = 9; + break; + case PORT_HSCIF: + port->fifosize = 128; + sci_port->overrun_bit = 0; + break; + case PORT_SCIFA: + port->fifosize = 64; + sci_port->overrun_bit = 9; + break; + case PORT_SCIF: + port->fifosize = 16; + if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) + sci_port->overrun_bit = 9; + else + sci_port->overrun_bit = 0; + break; + default: + port->fifosize = 1; + sci_port->overrun_bit = 5; + break; + } + if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { @@ -2194,12 +2202,6 @@ static int sci_init_single(struct platform_device *dev, * Establish sensible defaults for the overrun detection, unless * the part has explicitly disabled support for it. */ - if (p->type == PORT_SCI) - sci_port->overrun_bit = 5; - else if (p->scbrr_algo_id == SCBRR_ALGO_4) - sci_port->overrun_bit = 9; - else - sci_port->overrun_bit = 0; /* * Make the error mask inclusive of overrun detection, if From ec09c5eb491834d4011c72538e58d8b7096076bd Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 6 Dec 2013 10:59:20 +0100 Subject: [PATCH 14/14] serial: sh-sci: Rework baud rate calculation Computing the baud rate register value requires knowledge of the hardware sampling rate. This information is currently encoded in a baud rate calculation algorithm ID passed through platform data. However, it can be derived from the port type directly in most cases. Compute the sampling rate internally in the driver if the baud rate calculation algorithm ID isn't specified, and allow platforms to override the sampling rate through platform data in special cases (this is only required for SCIFA ports on sh7723 and sh7724, the reason needs to be investigated). Signed-off-by: Laurent Pinchart Acked-by: Greg Kroah-Hartman Signed-off-by: Simon Horman --- drivers/tty/serial/sh-sci.c | 37 ++++++++++++++++++++++++++++++------- include/linux/serial_sci.h | 2 ++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d5239d5ff98b..e4bf0e435af6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -65,6 +65,7 @@ struct sci_port { struct plat_sci_port *cfg; int overrun_bit; unsigned int error_mask; + unsigned int sampling_rate; /* Break timer */ @@ -1750,10 +1751,13 @@ static void sci_shutdown(struct uart_port *port) sci_free_irq(s); } -static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps, +static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned long freq) { - switch (algo_id) { + if (s->sampling_rate) + return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; + + switch (s->cfg->scbrr_algo_id) { case SCBRR_ALGO_1: return freq / (16 * bps); case SCBRR_ALGO_2: @@ -1843,12 +1847,11 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, baud = uart_get_baud_rate(port, termios, old, 0, max_baud); if (likely(baud && port->uartclk)) { - if (s->cfg->scbrr_algo_id == SCBRR_ALGO_6) { + if (s->cfg->type == PORT_HSCIF) { sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, &cks); } else { - t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, - port->uartclk); + t = sci_scbrr_calc(s, baud, port->uartclk); for (cks = 0; t >= 256 && cks <= 3; cks++) t >>= 2; } @@ -2092,6 +2095,7 @@ static int sci_init_single(struct platform_device *dev, { struct uart_port *port = &sci_port->port; const struct resource *res; + unsigned int sampling_rate; unsigned int i; int ret; @@ -2143,28 +2147,47 @@ static int sci_init_single(struct platform_device *dev, case PORT_SCIFB: port->fifosize = 256; sci_port->overrun_bit = 9; + sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; + sampling_rate = 0; sci_port->overrun_bit = 0; break; case PORT_SCIFA: port->fifosize = 64; sci_port->overrun_bit = 9; + sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; - if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) + if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { sci_port->overrun_bit = 9; - else + sampling_rate = 16; + } else { sci_port->overrun_bit = 0; + sampling_rate = 32; + } break; default: port->fifosize = 1; sci_port->overrun_bit = 5; + sampling_rate = 32; break; } + /* Set the sampling rate if the baud rate calculation algorithm isn't + * specified. + */ + if (p->scbrr_algo_id == SCBRR_ALGO_NONE) { + /* SCIFA on sh7723 and sh7724 need a custom sampling rate that + * doesn't match the SoC datasheet, this should be investigated. + * Let platform data override the sampling rate for now. + */ + sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate + : sampling_rate; + } + if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); if (IS_ERR(sci_port->iclk)) { diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h index e9c3021a37ae..af414e1895a5 100644 --- a/include/linux/serial_sci.h +++ b/include/linux/serial_sci.h @@ -11,6 +11,7 @@ #define SCIx_NOT_SUPPORTED (-1) enum { + SCBRR_ALGO_NONE, /* Compute sampling rate in the driver */ SCBRR_ALGO_1, /* clk / (16 * bps) */ SCBRR_ALGO_2, /* DIV_ROUND_CLOSEST(clk, 32 * bps) - 1 */ SCBRR_ALGO_3, /* clk / (8 * bps) */ @@ -134,6 +135,7 @@ struct plat_sci_port { upf_t flags; /* UPF_* flags */ unsigned long capabilities; /* Port features/capabilities */ + unsigned int sampling_rate; unsigned int scbrr_algo_id; /* SCBRR calculation algo */ unsigned int scscr; /* SCSCR initialization */