--- zzzz-none-000/linux-3.10.107/drivers/tty/serial/sh-sci.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/serial/sh-sci.c 2021-02-04 17:41:59.000000000 +0000 @@ -23,35 +23,34 @@ #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 #ifdef CONFIG_SUPERH #include @@ -59,11 +58,34 @@ #include "sh-sci.h" +/* Offsets into the sci_port->irqs array */ +enum { + SCIx_ERI_IRQ, + SCIx_RXI_IRQ, + SCIx_TXI_IRQ, + SCIx_BRI_IRQ, + SCIx_NR_IRQS, + + SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */ +}; + +#define SCIx_IRQ_IS_MUXED(port) \ + ((port)->irqs[SCIx_ERI_IRQ] == \ + (port)->irqs[SCIx_RXI_IRQ]) || \ + ((port)->irqs[SCIx_ERI_IRQ] && \ + ((port)->irqs[SCIx_RXI_IRQ] < 0)) + struct sci_port { struct uart_port port; /* Platform configuration */ struct plat_sci_port *cfg; + unsigned int overrun_reg; + unsigned int overrun_mask; + unsigned int error_mask; + unsigned int error_clear; + unsigned int sampling_rate; + resource_size_t reg_size; /* Break timer */ struct timer_list break_timer; @@ -74,38 +96,27 @@ /* Function clock */ struct clk *fclk; + 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; #ifdef CONFIG_SERIAL_SH_SCI_DMA - struct dma_async_tx_descriptor *desc_tx; - struct dma_async_tx_descriptor *desc_rx[2]; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx[2]; dma_cookie_t active_rx; - struct scatterlist sg_tx; - unsigned int sg_len_tx; + dma_addr_t tx_dma_addr; + unsigned int tx_dma_len; struct scatterlist sg_rx[2]; + void *rx_buf[2]; size_t buf_len_rx; - struct sh_dmae_slave param_tx; - struct sh_dmae_slave param_rx; struct work_struct work_tx; - struct work_struct work_rx; struct timer_list rx_timer; unsigned int rx_timeout; #endif - - struct notifier_block freq_transition; }; -/* Function prototypes */ -static void sci_start_tx(struct uart_port *port); -static void sci_stop_tx(struct uart_port *port); -static void sci_start_rx(struct uart_port *port); - #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS static struct sci_port sci_ports[SCI_NPORTS]; @@ -124,7 +135,7 @@ /* Helper for invalidating specific entries of an inherited map. */ #define sci_reg_invalid { .offset = 0, .size = 0 } -static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { +static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCIx_PROBE_REGTYPE] = { [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid, }, @@ -146,6 +157,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -165,6 +179,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -183,6 +200,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -201,6 +221,9 @@ [SCRFDR] = { 0x3c, 16 }, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -220,6 +243,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -238,6 +264,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -256,6 +285,30 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, + }, + + /* + * Common HSCIF definitions. + */ + [SCIx_HSCIF_REGTYPE] = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCTFDR] = sci_reg_invalid, + [SCRFDR] = sci_reg_invalid, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + [HSSRR] = { 0x40, 16 }, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -275,6 +328,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -294,6 +350,9 @@ [SCRFDR] = { 0x20, 16 }, [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -313,6 +372,9 @@ [SCRFDR] = sci_reg_invalid, [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, + [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, }; @@ -326,7 +388,7 @@ */ static unsigned int sci_serial_in(struct uart_port *p, int offset) { - struct plat_sci_reg *reg = sci_getreg(p, offset); + const struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) return ioread8(p->membase + (reg->offset << p->regshift)); @@ -340,7 +402,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value) { - struct plat_sci_reg *reg = sci_getreg(p, offset); + const struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) iowrite8(value, p->membase + (reg->offset << p->regshift)); @@ -374,8 +436,11 @@ */ cfg->regtype = SCIx_SH4_SCIF_REGTYPE; break; + case PORT_HSCIF: + cfg->regtype = SCIx_HSCIF_REGTYPE; + break; default: - printk(KERN_ERR "Can't probe register map for given port\n"); + pr_err("Can't probe register map for given port\n"); return -EINVAL; } @@ -389,9 +454,9 @@ 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) @@ -399,12 +464,119 @@ if (!sci_port->port.dev) return; - clk_disable(sci_port->fclk); - clk_disable(sci_port->iclk); + /* 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_unprepare(sci_port->fclk); + clk_disable_unprepare(sci_port->iclk); pm_runtime_put_sync(sci_port->port.dev); } +static inline unsigned long port_rx_irq_mask(struct uart_port *port) +{ + /* + * Not all ports (such as SCIFA) will support REIE. Rather than + * special-casing the port type, we check the port initialization + * IRQ enable mask to see whether the IRQ is desired at all. If + * it's unset, it's logically inferred that there's no point in + * testing for it. + */ + return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); +} + +static void sci_start_tx(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + unsigned short ctrl; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 new, scr = serial_port_in(port, SCSCR); + if (s->chan_tx) + new = scr | SCSCR_TDRQE; + else + new = scr & ~SCSCR_TDRQE; + if (new != scr) + serial_port_out(port, SCSCR, new); + } + + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + dma_submit_error(s->cookie_tx)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } +#endif + + if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); + } +} + +static void sci_stop_tx(struct uart_port *port) +{ + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_TDRQE; + + ctrl &= ~SCSCR_TIE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_start_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_stop_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + ctrl &= ~port_rx_irq_mask(port); + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) +{ + if (port->type == PORT_SCI) { + /* Just store the mask */ + serial_port_out(port, SCxSR, mask); + } else if (to_sci_port(port)->overrun_mask == SCIFA_ORER) { + /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ + /* Only clear the status bits we want to clear */ + serial_port_out(port, SCxSR, + serial_port_in(port, SCxSR) & mask); + } else { + /* Store the mask, clear parity/framing errors */ + serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); + } +} + #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) #ifdef CONFIG_CONSOLE_POLL @@ -416,7 +588,7 @@ do { status = serial_port_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); continue; } break; @@ -429,7 +601,7 @@ /* Dummy read */ serial_port_in(port, SCxSR); - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); return c; } @@ -444,14 +616,14 @@ } while (!(status & SCxSR_TDxE(port))); serial_port_out(port, SCxTDR, c); - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ static void sci_init_pins(struct uart_port *port, unsigned int cflag) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; + const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. @@ -481,7 +653,7 @@ static int sci_txfill(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; reg = sci_getreg(port, SCTFDR); if (reg->size) @@ -501,7 +673,7 @@ static int sci_rxfill(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; reg = sci_getreg(port, SCRFDR); if (reg->size) @@ -525,7 +697,7 @@ 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); } /* ********************************************************************** * @@ -571,7 +743,7 @@ port->icount.tx++; } while (--count > 0); - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -582,7 +754,7 @@ if (port->type != PORT_SCI) { serial_port_in(port, SCxSR); /* Dummy read */ - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); } ctrl |= SCSCR_TIE; @@ -666,7 +838,7 @@ } serial_port_in(port, SCxSR); /* dummy read */ - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; @@ -677,7 +849,7 @@ tty_flip_buffer_push(tport); } else { serial_port_in(port, SCxSR); /* dummy read */ - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } @@ -701,8 +873,6 @@ { 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); @@ -712,8 +882,6 @@ sci_schedule_break_timer(port); } else port->break_flag = 0; - - sci_port_disable(port); } static int sci_handle_errors(struct uart_port *port) @@ -723,19 +891,15 @@ 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 & s->overrun_mask) { + 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\n"); } if (status & SCxSR_FER(port)) { @@ -777,7 +941,7 @@ if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; - dev_notice(port->dev, "parity error"); + dev_notice(port->dev, "parity error\n"); } if (copied) @@ -790,22 +954,25 @@ { struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; int copied = 0; + u16 status; - reg = sci_getreg(port, SCLSR); + reg = sci_getreg(port, s->overrun_reg); if (!reg->size) return 0; - if ((serial_port_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) { - serial_port_out(port, SCLSR, 0); + status = serial_port_in(port, s->overrun_reg); + if (status & s->overrun_mask) { + status &= ~s->overrun_mask; + serial_port_out(port, s->overrun_reg, status); port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); tty_flip_buffer_push(tport); - dev_notice(port->dev, "overrun error\n"); + dev_dbg(port->dev, "overrun error\n"); copied++; } @@ -845,6 +1012,460 @@ return copied; } +#ifdef CONFIG_SERIAL_SH_SCI_DMA +static void sci_dma_tx_complete(void *arg) +{ + struct sci_port *s = arg; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += s->tx_dma_len; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += s->tx_dma_len; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!uart_circ_empty(xmit)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } else { + s->cookie_tx = -EINVAL; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Locking: called with port lock held */ +static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count) +{ + struct uart_port *port = &s->port; + struct tty_port *tport = &port->state->port; + int copied; + + copied = tty_insert_flip_string(tport, buf, count); + if (copied < count) { + dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", + count - copied); + port->icount.buf_overrun++; + } + + port->icount.rx += copied; + + return copied; +} + +static int sci_dma_rx_find_active(struct sci_port *s) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + if (s->active_rx == s->cookie_rx[i]) + return i; + + dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__, + s->active_rx); + return -1; +} + +static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], + sg_dma_address(&s->sg_rx[0])); + dma_release_channel(chan); + if (enable_pio) + sci_start_rx(port); +} + +static void sci_dma_rx_complete(void *arg) +{ + struct sci_port *s = arg; + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + unsigned long flags; + int active, count = 0; + + dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, + s->active_rx); + + spin_lock_irqsave(&port->lock, flags); + + active = sci_dma_rx_find_active(s); + if (active >= 0) + count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx); + + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + if (count) + tty_flip_buffer_push(&port->state->port); + + desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[active], 1, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[active] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[active])) + goto fail; + + s->active_rx = s->cookie_rx[!active]; + + dma_async_issue_pending(chan); + + dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", + __func__, s->cookie_rx[active], active, s->active_rx); + spin_unlock_irqrestore(&port->lock, flags); + return; + +fail: + spin_unlock_irqrestore(&port->lock, flags); + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); +} + +static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE, + DMA_TO_DEVICE); + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); +} + +static void sci_submit_rx(struct sci_port *s) +{ + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = dmaengine_prep_slave_sg(chan, + sg, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[i])) + goto fail; + + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, + s->cookie_rx[i], i); + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); + return; + +fail: + if (i) + dmaengine_terminate_all(chan); + for (i = 0; i < 2; i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = -EINVAL; + dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n"); + sci_rx_dma_release(s, true); +} + +static void work_fn_tx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_tx); + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + struct circ_buf *xmit = &port->state->xmit; + dma_addr_t buf; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1)); + s->tx_dma_len = min_t(unsigned int, + CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + spin_unlock_irq(&port->lock); + + desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len, + DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_tx)) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); +} + +static void rx_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + struct dma_tx_state state; + enum dma_status status; + unsigned long flags; + unsigned int read; + int active, count; + u16 scr; + + spin_lock_irqsave(&port->lock, flags); + + dev_dbg(port->dev, "DMA Rx timed out\n"); + + active = sci_dma_rx_find_active(s); + if (active < 0) { + spin_unlock_irqrestore(&port->lock, flags); + return; + } + + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { + dev_dbg(port->dev, "Cookie %d #%d has already completed\n", + s->active_rx, active); + spin_unlock_irqrestore(&port->lock, flags); + + /* Let packet complete handler take care of the packet */ + return; + } + + dmaengine_pause(chan); + + /* + * sometimes DMA transfer doesn't stop even if it is stopped and + * data keeps on coming until transaction is complete so check + * for DMA_COMPLETE again + * Let packet complete handler take care of the packet + */ + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { + spin_unlock_irqrestore(&port->lock, flags); + dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); + return; + } + + /* Handle incomplete DMA receive */ + dmaengine_terminate_all(s->chan_rx); + read = sg_dma_len(&s->sg_rx[active]) - state.residue; + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read, + s->active_rx); + + if (read) { + count = sci_dma_rx_push(s, s->rx_buf[active], read); + if (count) + tty_flip_buffer_push(&port->state->port); + } + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + sci_submit_rx(s); + + /* Direct new serial port interrupts back to CPU */ + scr = serial_port_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static struct dma_chan *sci_request_dma_chan(struct uart_port *port, + enum dma_transfer_direction dir, + unsigned int id) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + struct dma_slave_config cfg; + int ret; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)(unsigned long)id, port->dev, + dir == DMA_MEM_TO_DEV ? "tx" : "rx"); + if (!chan) { + dev_warn(port->dev, + "dma_request_slave_channel_compat failed\n"); + return NULL; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.direction = dir; + if (dir == DMA_MEM_TO_DEV) { + cfg.dst_addr = port->mapbase + + (sci_getreg(port, SCxTDR)->offset << port->regshift); + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } else { + cfg.src_addr = port->mapbase + + (sci_getreg(port, SCxRDR)->offset << port->regshift); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } + + ret = dmaengine_slave_config(chan, &cfg); + if (ret) { + dev_warn(port->dev, "dmaengine_slave_config failed %d\n", ret); + dma_release_channel(chan); + return NULL; + } + + return chan; +} + +static void sci_request_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct dma_chan *chan; + + dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); + + if (!port->dev->of_node && + (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)) + return; + + s->cookie_tx = -EINVAL; + chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV, s->cfg->dma_slave_tx); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + /* UART circular tx buffer is an aligned page. */ + s->tx_dma_addr = dma_map_single(chan->device->dev, + port->state->xmit.buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { + dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n"); + dma_release_channel(chan); + s->chan_tx = NULL; + } else { + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", + __func__, UART_XMIT_SIZE, + port->state->xmit.buf, &s->tx_dma_addr); + } + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM, s->cfg->dma_slave_rx); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + unsigned int i; + dma_addr_t dma; + void *buf; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize); + buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2, + &dma, GFP_KERNEL); + if (!buf) { + dev_warn(port->dev, + "Failed to allocate Rx dma buffer, using PIO\n"); + dma_release_channel(chan); + s->chan_rx = NULL; + return; + } + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + s->rx_buf[i] = buf; + sg_dma_address(sg) = dma; + sg_dma_len(sg) = s->buf_len_rx; + + buf += s->buf_len_rx; + dma += s->buf_len_rx; + } + + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + sci_submit_rx(s); + } +} + +static void sci_free_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); +} +#else +static inline void sci_request_dma(struct uart_port *port) +{ +} + +static inline void sci_free_dma(struct uart_port *port) +{ +} +#endif + static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -858,13 +1479,15 @@ /* Disable future Rx interrupts */ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { disable_irq_nosync(irq); - scr |= 0x4000; + scr |= SCSCR_RDRQE; } else { scr &= ~SCSCR_RIE; + sci_submit_rx(s); } serial_port_out(port, SCSCR, scr); /* Clear current interrupt */ - serial_port_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + serial_port_out(port, SCxSR, + ssr & ~(SCIF_DR | SCxSR_RDxF(port))); dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", jiffies, s->rx_timeout); mod_timer(&s->rx_timer, jiffies + s->rx_timeout); @@ -897,23 +1520,26 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); /* Handle errors */ if (port->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ serial_port_in(port, SCxSR); - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } else { sci_handle_fifo_overrun(port); - sci_rx_interrupt(irq, ptr); + if (!s->chan_rx) + sci_receive_chars(ptr); } - serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ - sci_tx_interrupt(irq, ptr); + if (!s->chan_tx) + sci_tx_interrupt(irq, ptr); return IRQ_HANDLED; } @@ -924,32 +1550,27 @@ /* Handle BREAKs */ sci_handle_breaks(port); - serial_port_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } -static inline unsigned long port_rx_irq_mask(struct uart_port *port) -{ - /* - * Not all ports (such as SCIFA) will support REIE. Rather than - * special-casing the port type, we check the port initialization - * IRQ enable mask to see whether the IRQ is desired at all. If - * it's unset, it's logically inferred that there's no point in - * testing for it. - */ - return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); -} - static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { - unsigned short ssr_status, scr_status, err_enabled; + unsigned short ssr_status, scr_status, err_enabled, orer_status = 0; struct uart_port *port = ptr; struct sci_port *s = to_sci_port(port); irqreturn_t ret = IRQ_NONE; ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); + if (s->overrun_reg == SCxSR) + orer_status = ssr_status; + else { + if (sci_getreg(port, s->overrun_reg)->size) + orer_status = serial_port_in(port, s->overrun_reg); + } + err_enabled = scr_status & port_rx_irq_mask(port); /* Tx Interrupt */ @@ -973,34 +1594,16 @@ if ((ssr_status & SCxSR_BRK(port)) && err_enabled) ret = sci_br_interrupt(irq, ptr); - return ret; -} - -/* - * Here we define a transition notifier so that we can update all of our - * ports' baud rate when the peripheral clock changes. - */ -static int sci_notifier(struct notifier_block *self, - unsigned long phase, void *p) -{ - struct sci_port *sci_port; - unsigned long flags; - - sci_port = container_of(self, struct sci_port, freq_transition); - - if ((phase == CPUFREQ_POSTCHANGE) || - (phase == CPUFREQ_RESUMECHANGE)) { - struct uart_port *port = &sci_port->port; - - spin_lock_irqsave(&port->lock, flags); - port->uartclk = clk_get_rate(sci_port->iclk); - spin_unlock_irqrestore(&port->lock, flags); + /* Overrun Interrupt */ + if (orer_status & s->overrun_mask) { + sci_handle_fifo_overrun(port); + ret = IRQ_HANDLED; } - return NOTIFY_OK; + return ret; } -static struct sci_irq_desc { +static const struct sci_irq_desc { const char *desc; irq_handler_t handler; } sci_irq_desc[] = { @@ -1042,31 +1645,28 @@ int i, j, ret = 0; for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { - struct sci_irq_desc *desc; - unsigned int irq; + const struct sci_irq_desc *desc; + 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; } desc = sci_irq_desc + i; port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s", dev_name(up->dev), desc->desc); - if (!port->irqstr[j]) { - dev_err(up->dev, "Failed to allocate %s IRQ string\n", - desc->desc); + if (!port->irqstr[j]) goto out_nomem; - } ret = request_irq(irq, desc->handler, up->irqflags, port->irqstr[j], port); @@ -1080,7 +1680,7 @@ out_noirq: while (--i >= 0) - free_irq(port->cfg->irqs[i], port); + free_irq(port->irqs[i], port); out_nomem: while (--j >= 0) @@ -1098,16 +1698,16 @@ * 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)) { @@ -1117,67 +1717,6 @@ } } -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); @@ -1201,14 +1740,16 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) { if (mctrl & TIOCM_LOOP) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; /* * Standard loopback mode for SCFCR ports. */ reg = sci_getreg(port, SCFCR); if (reg->size) - serial_port_out(port, SCFCR, serial_port_in(port, SCFCR) | 1); + serial_port_out(port, SCFCR, + serial_port_in(port, SCFCR) | + SCFCR_LOOP); } } @@ -1221,362 +1762,10 @@ return TIOCM_DSR | TIOCM_CAR; } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static void sci_dma_tx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; - unsigned long flags; - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - spin_lock_irqsave(&port->lock, flags); - - xmit->tail += sg_dma_len(&s->sg_tx); - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += sg_dma_len(&s->sg_tx); - - async_tx_ack(s->desc_tx); - s->desc_tx = NULL; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } else { - s->cookie_tx = -EINVAL; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); - } - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Locking: called with port lock held */ -static int sci_dma_rx_push(struct sci_port *s, size_t count) -{ - struct uart_port *port = &s->port; - struct tty_port *tport = &port->state->port; - int i, active, room; - - room = tty_buffer_request_room(tport, count); - - if (s->active_rx == s->cookie_rx[0]) { - active = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - active = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return 0; - } - - if (room < count) - dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", - count - room); - if (!room) - return room; - - for (i = 0; i < room; i++) - tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i], - TTY_NORMAL); - - port->icount.rx += room; - - return room; -} - -static void sci_dma_rx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - unsigned long flags; - int count; - - dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx); - - spin_lock_irqsave(&port->lock, flags); - - count = sci_dma_rx_push(s, s->buf_len_rx); - - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); - - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(&port->state->port); - - schedule_work(&s->work_rx); -} - -static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_rx; - struct uart_port *port = &s->port; - - s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; - dma_release_channel(chan); - if (sg_dma_address(&s->sg_rx[0])) - dma_free_coherent(port->dev, s->buf_len_rx * 2, - sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); - if (enable_pio) - sci_start_rx(port); -} - -static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - - s->chan_tx = NULL; - s->cookie_tx = -EINVAL; - dma_release_channel(chan); - if (enable_pio) - sci_start_tx(port); -} - -static void sci_submit_rx(struct sci_port *s) -{ - struct dma_chan *chan = s->chan_rx; - int i; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - struct dma_async_tx_descriptor *desc; - - desc = dmaengine_prep_slave_sg(chan, - sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); - - if (desc) { - s->desc_rx[i] = desc; - desc->callback = sci_dma_rx_complete; - desc->callback_param = s; - s->cookie_rx[i] = desc->tx_submit(desc); - } - - if (!desc || s->cookie_rx[i] < 0) { - if (i) { - async_tx_ack(s->desc_rx[0]); - s->cookie_rx[0] = -EINVAL; - } - if (desc) { - async_tx_ack(desc); - s->cookie_rx[i] = -EINVAL; - } - dev_warn(s->port.dev, - "failed to re-start DMA, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, - s->cookie_rx[i], i); - } - - s->active_rx = s->cookie_rx[0]; - - dma_async_issue_pending(chan); -} - -static void work_fn_rx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_rx); - struct uart_port *port = &s->port; - struct dma_async_tx_descriptor *desc; - int new; - - if (s->active_rx == s->cookie_rx[0]) { - new = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - new = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return; - } - desc = s->desc_rx[new]; - - if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != - DMA_SUCCESS) { - /* Handle incomplete DMA receive */ - struct dma_chan *chan = s->chan_rx; - struct shdma_desc *sh_desc = container_of(desc, - struct shdma_desc, async_tx); - unsigned long flags; - int count; - - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); - dev_dbg(port->dev, "Read %u bytes with cookie %d\n", - sh_desc->partial, sh_desc->cookie); - - spin_lock_irqsave(&port->lock, flags); - count = sci_dma_rx_push(s, sh_desc->partial); - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(&port->state->port); - - sci_submit_rx(s); - - return; - } - - s->cookie_rx[new] = desc->tx_submit(desc); - if (s->cookie_rx[new] < 0) { - dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); - sci_rx_dma_release(s, true); - return; - } - - s->active_rx = s->cookie_rx[!new]; - - dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__, - s->cookie_rx[new], new, s->active_rx); -} - -static void work_fn_tx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_tx); - struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - struct circ_buf *xmit = &port->state->xmit; - struct scatterlist *sg = &s->sg_tx; - - /* - * DMA is idle now. - * Port xmit buffer is already mapped, and it is one page... Just adjust - * offsets and lengths. Since it is a circular buffer, we have to - * transmit till the end, and then the rest. Take the port lock to get a - * consistent xmit buffer state. - */ - spin_lock_irq(&port->lock); - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + - sg->offset; - sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); - spin_unlock_irq(&port->lock); - - BUG_ON(!sg_dma_len(sg)); - - desc = dmaengine_prep_slave_sg(chan, - sg, s->sg_len_tx, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); - - spin_lock_irq(&port->lock); - s->desc_tx = desc; - desc->callback = sci_dma_tx_complete; - desc->callback_param = s; - spin_unlock_irq(&port->lock); - s->cookie_tx = desc->tx_submit(desc); - if (s->cookie_tx < 0) { - dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__, - xmit->buf, xmit->tail, xmit->head, s->cookie_tx); - - dma_async_issue_pending(chan); -} -#endif - -static void sci_start_tx(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - unsigned short ctrl; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = serial_port_in(port, SCSCR); - if (s->chan_tx) - new = scr | 0x8000; - else - new = scr & ~0x8000; - if (new != scr) - serial_port_out(port, SCSCR, new); - } - - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && - s->cookie_tx < 0) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } -#endif - - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); - } -} - -static void sci_stop_tx(struct uart_port *port) -{ - unsigned short ctrl; - - /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x8000; - - ctrl &= ~SCSCR_TIE; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_start_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_stop_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~0x4000; - - ctrl &= ~port_rx_irq_mask(port); - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_enable_ms(struct uart_port *port) -{ - /* - * Not supported by hardware, always a nop. - */ -} - static void sci_break_ctl(struct uart_port *port, int break_state) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; + const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; unsigned short scscr, scsptr; /* check wheter the port has SCSPTR */ @@ -1603,141 +1792,6 @@ serial_port_out(port, SCSCR, scscr); } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static bool filter(struct dma_chan *chan, void *slave) -{ - struct sh_dmae_slave *param = slave; - - dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__, - param->shdma_slave.slave_id); - - chan->private = ¶m->shdma_slave; - return true; -} - -static void rx_timer_fn(unsigned long arg) -{ - struct sci_port *s = (struct sci_port *)arg; - struct uart_port *port = &s->port; - u16 scr = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~0x4000; - enable_irq(s->cfg->irqs[1]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); - dev_dbg(port->dev, "DMA Rx timed out\n"); - schedule_work(&s->work_rx); -} - -static void sci_request_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - struct sh_dmae_slave *param; - struct dma_chan *chan; - dma_cap_mask_t mask; - int nent; - - dev_dbg(port->dev, "%s: port %d\n", __func__, - port->line); - - if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) - return; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - param = &s->param_tx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_tx; - - s->cookie_tx = -EINVAL; - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); - if (chan) { - 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); - sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, (int)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)); - - s->sg_len_tx = nent; - - INIT_WORK(&s->work_tx, work_fn_tx); - } - - param = &s->param_rx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_rx; - - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); - if (chan) { - dma_addr_t dma[2]; - void *buf[2]; - int i; - - s->chan_rx = chan; - - s->buf_len_rx = 2 * max(16, (int)port->fifosize); - buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, - &dma[0], GFP_KERNEL); - - if (!buf[0]) { - dev_warn(port->dev, - "failed to allocate dma buffer, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - - buf[1] = buf[0] + s->buf_len_rx; - dma[1] = dma[0] + s->buf_len_rx; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - - sg_init_table(sg, 1); - sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, - (int)buf[i] & ~PAGE_MASK); - sg_dma_address(sg) = dma[i]; - } - - INIT_WORK(&s->work_rx, work_fn_rx); - setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); - - sci_submit_rx(s); - } -} - -static void sci_free_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - if (s->chan_tx) - sci_tx_dma_release(s, false); - if (s->chan_rx) - sci_rx_dma_release(s, false); -} -#else -static inline void sci_request_dma(struct uart_port *port) -{ -} - -static inline void sci_free_dma(struct uart_port *port) -{ -} -#endif - static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); @@ -1772,25 +1826,23 @@ sci_stop_tx(port); spin_unlock_irqrestore(&port->lock, flags); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (s->chan_rx) { + dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__, + port->line); + del_timer_sync(&s->rx_timer); + } +#endif + sci_free_dma(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) { - case SCBRR_ALGO_1: - return ((freq + 16 * bps) / (16 * bps) - 1); - case SCBRR_ALGO_2: - return ((freq + 16 * bps) / (32 * bps) - 1); - case SCBRR_ALGO_3: - 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); - } + if (s->sampling_rate) + return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1; /* Warn, but use a safe default */ WARN_ON(1); @@ -1798,9 +1850,83 @@ return ((freq + 16 * bps) / (32 * bps) - 1); } +/* calculate frame length from SMR */ +static int sci_baud_calc_frame_len(unsigned int smr_val) +{ + int len = 10; + + if (smr_val & SCSMR_CHR) + len--; + if (smr_val & SCSMR_PE) + len++; + if (smr_val & SCSMR_STOP) + len++; + + return len; +} + + +/* calculate sample rate, BRR, and clock select for HSCIF */ +static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, + int *brr, unsigned int *srr, + unsigned int *cks, int frame_len) +{ + int sr, c, br, err, recv_margin; + int min_err = 1000; /* 100% */ + int recv_max_margin = 0; + + /* Find the combination of sample rate and clock select with the + smallest deviation from the desired baud rate. */ + for (sr = 8; sr <= 32; sr++) { + for (c = 0; c <= 3; c++) { + /* integerized formulas from HSCIF documentation */ + br = DIV_ROUND_CLOSEST(freq, (sr * + (1 << (2 * c + 1)) * bps)) - 1; + br = clamp(br, 0, 255); + err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr * + (1 << (2 * c + 1)) / 1000)) - + 1000; + /* Calc recv margin + * M: Receive margin (%) + * N: Ratio of bit rate to clock (N = sampling rate) + * D: Clock duty (D = 0 to 1.0) + * L: Frame length (L = 9 to 12) + * F: Absolute value of clock frequency deviation + * + * M = |(0.5 - 1 / 2 * N) - ((L - 0.5) * F) - + * (|D - 0.5| / N * (1 + F))| + * NOTE: Usually, treat D for 0.5, F is 0 by this + * calculation. + */ + recv_margin = abs((500 - + DIV_ROUND_CLOSEST(1000, sr << 1)) / 10); + if (abs(min_err) > abs(err)) { + min_err = err; + recv_max_margin = recv_margin; + } else if ((min_err == err) && + (recv_margin > recv_max_margin)) + recv_max_margin = recv_margin; + else + continue; + + *brr = br; + *srr = sr - 1; + *cks = c; + } + } + + if (min_err == 1000) { + WARN_ON(1); + /* use defaults */ + *brr = 255; + *srr = 15; + *cks = 0; + } +} + static void sci_reset(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; unsigned int status; do { @@ -1818,9 +1944,19 @@ struct ktermios *old) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg; - unsigned int baud, smr_val, max_baud, cks; + const struct plat_sci_reg *reg; + unsigned int baud, smr_val = 0, max_baud, cks = 0; int t = -1; + unsigned int srr = 15; + + if ((termios->c_cflag & CSIZE) == CS7) + smr_val |= SCSMR_CHR; + if (termios->c_cflag & PARENB) + smr_val |= SCSMR_PE; + if (termios->c_cflag & PARODD) + smr_val |= SCSMR_PE | SCSMR_ODD; + if (termios->c_cflag & CSTOPB) + smr_val |= SCSMR_STOP; /* * earlyprintk comes here early on with port->uartclk set to zero. @@ -1833,35 +1969,35 @@ max_baud = port->uartclk ? port->uartclk / 16 : 115200; baud = uart_get_baud_rate(port, termios, old, 0, max_baud); - if (likely(baud && port->uartclk)) - t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk); + if (likely(baud && port->uartclk)) { + if (s->cfg->type == PORT_HSCIF) { + int frame_len = sci_baud_calc_frame_len(smr_val); + sci_baud_calc_hscif(baud, port->uartclk, &t, &srr, + &cks, frame_len); + } else { + t = sci_scbrr_calc(s, baud, port->uartclk); + for (cks = 0; t >= 256 && cks <= 3; cks++) + t >>= 2; + } + } sci_port_enable(s); sci_reset(port); - smr_val = serial_port_in(port, SCSMR) & 3; - - if ((termios->c_cflag & CSIZE) == CS7) - smr_val |= 0x40; - if (termios->c_cflag & PARENB) - smr_val |= 0x20; - if (termios->c_cflag & PARODD) - smr_val |= 0x30; - if (termios->c_cflag & CSTOPB) - smr_val |= 0x08; + smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS; uart_update_timeout(port, termios->c_cflag, baud); - for (cks = 0; t >= 256 && cks <= 3; cks++) - t >>= 2; - dev_dbg(port->dev, "%s: SMR %x, cks %x, t %x, SCSCR %x\n", __func__, smr_val, cks, t, s->cfg->scscr); if (t >= 0) { - serial_port_out(port, SCSMR, (smr_val & ~3) | cks); + serial_port_out(port, SCSMR, (smr_val & ~SCSMR_CKS) | cks); serial_port_out(port, SCBRR, t); + reg = sci_getreg(port, HSSRR); + if (reg->size) + serial_port_out(port, HSSRR, srr | HSCIF_SRE); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ } else serial_port_out(port, SCSMR, smr_val); @@ -1893,20 +2029,41 @@ #ifdef CONFIG_SERIAL_SH_SCI_DMA /* - * Calculate delay for 1.5 DMA buffers: see - * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits - * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function - * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." - * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO - * sizes), but it has been found out experimentally, that this is not - * enough: the driver too often needlessly runs on a DMA timeout. 20ms - * as a minimum seem to work perfectly. + * Calculate delay for 2 DMA buffers (4 FIFO). + * See serial_core.c::uart_update_timeout(). + * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above + * function calculates 1 jiffie for the data plus 5 jiffies for the + * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA + * buffers (4 FIFO sizes), but when performing a faster transfer, the + * value obtained by this formula is too small. Therefore, if the value + * is smaller than 20ms, use 20ms as the timeout value for DMA. */ if (s->chan_rx) { - s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 / - port->fifosize / 2; - dev_dbg(port->dev, - "DMA Rx t-out %ums, tty t-out %u jiffies\n", + unsigned int bits; + + /* byte size and parity */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; + } + + if (termios->c_cflag & CSTOPB) + bits++; + if (termios->c_cflag & PARENB) + bits++; + s->rx_timeout = DIV_ROUND_UP((s->buf_len_rx * 2 * bits * HZ) / + (baud / 10), 10); + dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n", s->rx_timeout * 1000 / HZ, port->timeout); if (s->rx_timeout < msecs_to_jiffies(20)) s->rx_timeout = msecs_to_jiffies(20); @@ -1925,7 +2082,7 @@ struct sci_port *sci_port = to_sci_port(port); switch (state) { - case 3: + case UART_PM_STATE_OFF: sci_port_disable(sci_port); break; default: @@ -1947,25 +2104,16 @@ return "scifa"; case PORT_SCIFB: return "scifb"; + case PORT_HSCIF: + return "hscif"; } return NULL; } -static inline unsigned long sci_port_size(struct uart_port *port) -{ - /* - * Pick an arbitrary size that encapsulates all of the base - * registers by default. This can be optimized later, or derived - * from platform resource data at such a time that ports begin to - * behave more erratically. - */ - return 64; -} - static int sci_remap_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); + struct sci_port *sport = to_sci_port(port); /* * Nothing to do if there's already an established membase. @@ -1974,7 +2122,7 @@ return 0; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); + port->membase = ioremap_nocache(port->mapbase, sport->reg_size); if (unlikely(!port->membase)) { dev_err(port->dev, "can't remap port#%d\n", port->line); return -ENXIO; @@ -1985,7 +2133,7 @@ * need to do any remapping, just cast the cookie * directly. */ - port->membase = (void __iomem *)port->mapbase; + port->membase = (void __iomem *)(uintptr_t)port->mapbase; } return 0; @@ -1993,23 +2141,28 @@ static void sci_release_port(struct uart_port *port) { + struct sci_port *sport = to_sci_port(port); + if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } - release_mem_region(port->mapbase, sci_port_size(port)); + release_mem_region(port->mapbase, sport->reg_size); } static int sci_request_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); struct resource *res; + struct sci_port *sport = to_sci_port(port); int ret; - res = request_mem_region(port->mapbase, size, dev_name(port->dev)); - if (unlikely(res == NULL)) + res = request_mem_region(port->mapbase, sport->reg_size, + dev_name(port->dev)); + if (unlikely(res == NULL)) { + dev_err(port->dev, "request_mem_region failed."); return -EBUSY; + } ret = sci_remap_port(port); if (unlikely(ret != 0)) { @@ -2032,10 +2185,6 @@ 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) - return -EINVAL; if (ser->baud_base < 2400) /* No paper tape reader for Mitch.. */ return -EINVAL; @@ -2050,7 +2199,6 @@ .start_tx = sci_start_tx, .stop_tx = sci_stop_tx, .stop_rx = sci_stop_rx, - .enable_ms = sci_enable_ms, .break_ctl = sci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, @@ -2068,11 +2216,12 @@ }; 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; @@ -2081,28 +2230,83 @@ port->iotype = UPIO_MEM; port->line = index; + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res == NULL) + return -ENOMEM; + + port->mapbase = res->start; + sci_port->reg_size = resource_size(res); + + 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]; + } + + 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_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; + break; + case PORT_HSCIF: + port->fifosize = 128; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; + sci_port->sampling_rate = 0; break; case PORT_SCIFA: port->fifosize = 64; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; + if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; + } else { + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; + sci_port->sampling_rate = 32; + } break; default: port->fifosize = 1; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCI_ORER; + sci_port->sampling_rate = 32; break; } - if (p->regtype == SCIx_PROBE_REGTYPE) { - ret = sci_probe_regmap(p); - if (unlikely(ret)) - return ret; - } + /* 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. + */ + if (p->sampling_rate) + sci_port->sampling_rate = p->sampling_rate; - 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"); @@ -2122,8 +2326,6 @@ port->dev = &dev->dev; - sci_init_gpios(sci_port); - pm_runtime_enable(&dev->dev); } @@ -2134,32 +2336,25 @@ /* * Establish some sensible defaults for the error detection. */ - if (!p->error_mask) - p->error_mask = (p->type == PORT_SCI) ? - SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; + if (p->type == PORT_SCI) { + sci_port->error_mask = SCI_DEFAULT_ERROR_MASK; + sci_port->error_clear = SCI_ERROR_CLEAR; + } else { + sci_port->error_mask = SCIF_DEFAULT_ERROR_MASK; + sci_port->error_clear = SCIF_ERROR_CLEAR; + } /* - * 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; - - /* - * 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. + */ + if (sci_port->overrun_reg == SCxSR) { + sci_port->error_mask |= sci_port->overrun_mask; + sci_port->error_clear &= ~sci_port->overrun_mask; } - port->mapbase = p->mapbase; port->type = p->type; - port->flags = p->flags; + port->flags = UPF_FIXED_PORT | p->flags; port->regshift = p->regshift; /* @@ -2169,7 +2364,7 @@ * * 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; @@ -2184,8 +2379,6 @@ static void sci_cleanup_single(struct sci_port *port) { - sci_free_gpios(port); - clk_put(port->iclk); clk_put(port->fclk); @@ -2294,14 +2487,14 @@ static int sci_probe_earlyprintk(struct platform_device *pdev) { - struct plat_sci_port *cfg = pdev->dev.platform_data; + struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev); if (early_serial_console.data) return -EEXIST; 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); @@ -2324,8 +2517,7 @@ #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -static char banner[] __initdata = - KERN_INFO "SuperH SCI(F) driver initialized\n"; +static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized"; static struct uart_driver sci_uart_driver = { .owner = THIS_MODULE, @@ -2341,9 +2533,6 @@ { struct sci_port *port = platform_get_drvdata(dev); - cpufreq_unregister_notifier(&port->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); - uart_remove_one_port(&sci_uart_driver, &port->port); sci_cleanup_single(port); @@ -2351,6 +2540,87 @@ return 0; } +struct sci_port_info { + unsigned int type; + unsigned int regtype; +}; + +static const struct of_device_id of_sci_match[] = { + { + .compatible = "renesas,scif", + .data = &(const struct sci_port_info) { + .type = PORT_SCIF, + .regtype = SCIx_SH4_SCIF_REGTYPE, + }, + }, { + .compatible = "renesas,scifa", + .data = &(const struct sci_port_info) { + .type = PORT_SCIFA, + .regtype = SCIx_SCIFA_REGTYPE, + }, + }, { + .compatible = "renesas,scifb", + .data = &(const struct sci_port_info) { + .type = PORT_SCIFB, + .regtype = SCIx_SCIFB_REGTYPE, + }, + }, { + .compatible = "renesas,hscif", + .data = &(const struct sci_port_info) { + .type = PORT_HSCIF, + .regtype = SCIx_HSCIF_REGTYPE, + }, + }, { + .compatible = "renesas,sci", + .data = &(const struct sci_port_info) { + .type = PORT_SCI, + .regtype = SCIx_SCI_REGTYPE, + }, + }, { + /* Terminator */ + }, +}; +MODULE_DEVICE_TABLE(of, of_sci_match); + +static struct plat_sci_port * +sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct sci_port_info *info; + struct plat_sci_port *p; + int id; + + if (!IS_ENABLED(CONFIG_OF) || !np) + return NULL; + + match = of_match_node(of_sci_match, pdev->dev.of_node); + if (!match) + return NULL; + + info = match->data; + + p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); + if (!p) + return NULL; + + /* Get the line number for the aliases node. */ + id = of_alias_get_id(np, "serial"); + if (id < 0) { + dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); + return NULL; + } + + *dev_id = id; + + p->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + p->type = info->type; + p->regtype = info->regtype; + p->scscr = SCSCR_RE | SCSCR_TE; + + return p; +} + static int sci_probe_single(struct platform_device *dev, unsigned int index, struct plat_sci_port *p, @@ -2360,15 +2630,13 @@ /* Sanity check */ if (unlikely(index >= SCI_NPORTS)) { - dev_notice(&dev->dev, "Attempting to register port " - "%d when only %d are available.\n", + dev_notice(&dev->dev, "Attempting to register port %d when only %d are available\n", index+1, SCI_NPORTS); - dev_notice(&dev->dev, "Consider bumping " - "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); + dev_notice(&dev->dev, "Consider bumping CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); return -EINVAL; } - ret = sci_init_single(dev, sciport, index, p); + ret = sci_init_single(dev, sciport, index, p, false); if (ret) return ret; @@ -2383,8 +2651,9 @@ static int sci_probe(struct platform_device *dev) { - struct plat_sci_port *p = dev->dev.platform_data; - struct sci_port *sp = &sci_ports[dev->id]; + struct plat_sci_port *p; + struct sci_port *sp; + unsigned int dev_id; int ret; /* @@ -2395,20 +2664,26 @@ if (is_early_platform_device(dev)) return sci_probe_earlyprintk(dev); - platform_set_drvdata(dev, sp); + if (dev->dev.of_node) { + p = sci_parse_dt(dev, &dev_id); + if (p == NULL) + return -EINVAL; + } else { + p = dev->dev.platform_data; + if (p == NULL) { + dev_err(&dev->dev, "no platform data supplied\n"); + return -EINVAL; + } - ret = sci_probe_single(dev, dev->id, p, sp); - if (ret) - return ret; + dev_id = dev->id; + } - sp->freq_transition.notifier_call = sci_notifier; + sp = &sci_ports[dev_id]; + platform_set_drvdata(dev, sp); - ret = cpufreq_register_notifier(&sp->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); - if (unlikely(ret < 0)) { - sci_cleanup_single(sp); + ret = sci_probe_single(dev, dev_id, p, sp); + if (ret) return ret; - } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); @@ -2417,7 +2692,7 @@ return 0; } -static int sci_suspend(struct device *dev) +static __maybe_unused int sci_suspend(struct device *dev) { struct sci_port *sport = dev_get_drvdata(dev); @@ -2427,7 +2702,7 @@ return 0; } -static int sci_resume(struct device *dev) +static __maybe_unused int sci_resume(struct device *dev) { struct sci_port *sport = dev_get_drvdata(dev); @@ -2437,18 +2712,15 @@ return 0; } -static const struct dev_pm_ops sci_dev_pm_ops = { - .suspend = sci_suspend, - .resume = sci_resume, -}; +static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume); static struct platform_driver sci_driver = { .probe = sci_probe, .remove = sci_remove, .driver = { .name = "sh-sci", - .owner = THIS_MODULE, .pm = &sci_dev_pm_ops, + .of_match_table = of_match_ptr(of_sci_match), }, }; @@ -2456,7 +2728,7 @@ { int ret; - printk(banner); + pr_info("%s\n", banner); ret = uart_register_driver(&sci_uart_driver); if (likely(ret == 0)) { @@ -2484,4 +2756,4 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:sh-sci"); MODULE_AUTHOR("Paul Mundt"); -MODULE_DESCRIPTION("SuperH SCI(F) serial driver"); +MODULE_DESCRIPTION("SuperH (H)SCI(F) serial driver");