summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/sh-sci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r--drivers/tty/serial/sh-sci.c482
1 files changed, 305 insertions, 177 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index a85e7b9a2e49..b1ea48f38248 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -157,6 +157,7 @@ struct sci_port {
bool has_rtscts;
bool autorts;
+ bool tx_occurred;
};
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -164,6 +165,8 @@ struct sci_port {
static struct sci_port sci_ports[SCI_NPORTS];
static unsigned long sci_ports_in_use;
static struct uart_driver sci_uart_driver;
+static bool sci_uart_earlycon;
+static bool sci_uart_earlycon_dev_probing;
static inline struct sci_port *
to_sci_port(struct uart_port *uart)
@@ -318,6 +321,37 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
},
/*
+ * The "SCIF" that is in RZ/V2H(P) SoC is similar to one found on RZ/G2L SoC
+ * with below differences,
+ * - Break out of interrupts are different: ERI, BRI, RXI, TXI, TEI, DRI,
+ * TEI-DRI, RXI-EDGE and TXI-EDGE.
+ * - SCSMR register does not have CM bit (BIT(7)) ie it does not support synchronous mode.
+ * - SCFCR register does not have SCFCR_MCE bit.
+ * - SCSPTR register has only bits SCSPTR_SPB2DT and SCSPTR_SPB2IO.
+ */
+ [SCIx_RZV2H_SCIF_REGTYPE] = {
+ .regs = {
+ [SCSMR] = { 0x00, 16 },
+ [SCBRR] = { 0x02, 8 },
+ [SCSCR] = { 0x04, 16 },
+ [SCxTDR] = { 0x06, 8 },
+ [SCxSR] = { 0x08, 16 },
+ [SCxRDR] = { 0x0a, 8 },
+ [SCFCR] = { 0x0c, 16 },
+ [SCFDR] = { 0x0e, 16 },
+ [SCSPTR] = { 0x10, 16 },
+ [SCLSR] = { 0x12, 16 },
+ [SEMR] = { 0x14, 8 },
+ },
+ .fifosize = 16,
+ .overrun_reg = SCLSR,
+ .overrun_mask = SCLSR_ORER,
+ .sampling_rate_mask = SCI_SR(32),
+ .error_mask = SCIF_DEFAULT_ERROR_MASK,
+ .error_clear = SCIF_ERROR_CLEAR,
+ },
+
+ /*
* Common SH-3 SCIF definitions.
*/
[SCIx_SH3_SCIF_REGTYPE] = {
@@ -576,16 +610,16 @@ static void sci_start_tx(struct uart_port *port)
#ifdef CONFIG_SERIAL_SH_SCI_DMA
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
- u16 new, scr = serial_port_in(port, SCSCR);
+ u16 new, scr = sci_serial_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);
+ sci_serial_out(port, SCSCR, new);
}
- if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+ if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) &&
dma_submit_error(s->cookie_tx)) {
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
/* Switch irq from SCIF to DMA */
@@ -599,7 +633,7 @@ static void sci_start_tx(struct uart_port *port)
if (!s->chan_tx || s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE ||
port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
- ctrl = serial_port_in(port, SCSCR);
+ ctrl = sci_serial_in(port, SCSCR);
/*
* For SCI, TE (transmit enable) must be set after setting TIE
@@ -609,7 +643,7 @@ static void sci_start_tx(struct uart_port *port)
if (port->type == PORT_SCI)
ctrl |= SCSCR_TE;
- serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
+ sci_serial_out(port, SCSCR, ctrl | SCSCR_TIE);
}
}
@@ -618,14 +652,14 @@ 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);
+ ctrl = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~SCSCR_TDRQE;
ctrl &= ~SCSCR_TIE;
- serial_port_out(port, SCSCR, ctrl);
+ sci_serial_out(port, SCSCR, ctrl);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
if (to_sci_port(port)->chan_tx &&
@@ -640,41 +674,40 @@ static void sci_start_rx(struct uart_port *port)
{
unsigned short ctrl;
- ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
+ ctrl = sci_serial_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);
+ sci_serial_out(port, SCSCR, ctrl);
}
static void sci_stop_rx(struct uart_port *port)
{
unsigned short ctrl;
- ctrl = serial_port_in(port, SCSCR);
+ ctrl = sci_serial_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);
+ sci_serial_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);
+ sci_serial_out(port, SCxSR, mask);
} else if (to_sci_port(port)->params->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);
+ sci_serial_out(port, SCxSR, sci_serial_in(port, SCxSR) & mask);
} else {
/* Store the mask, clear parity/framing errors */
- serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
+ sci_serial_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
}
}
@@ -688,7 +721,7 @@ static int sci_poll_get_char(struct uart_port *port)
int c;
do {
- status = serial_port_in(port, SCxSR);
+ status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
@@ -699,10 +732,10 @@ static int sci_poll_get_char(struct uart_port *port)
if (!(status & SCxSR_RDxF(port)))
return NO_POLL_CHAR;
- c = serial_port_in(port, SCxRDR);
+ c = sci_serial_in(port, SCxRDR);
/* Dummy read */
- serial_port_in(port, SCxSR);
+ sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
@@ -714,10 +747,10 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
unsigned short status;
do {
- status = serial_port_in(port, SCxSR);
+ status = sci_serial_in(port, SCxSR);
} while (!(status & SCxSR_TDxE(port)));
- serial_port_out(port, SCxTDR, c);
+ sci_serial_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
@@ -736,8 +769,8 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
}
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
- u16 data = serial_port_in(port, SCPDR);
- u16 ctrl = serial_port_in(port, SCPCR);
+ u16 data = sci_serial_in(port, SCPDR);
+ u16 ctrl = sci_serial_in(port, SCPCR);
/* Enable RXD and TXD pin functions */
ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
@@ -756,10 +789,10 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
/* Enable CTS# pin function */
ctrl &= ~SCPCR_CTSC;
}
- serial_port_out(port, SCPDR, data);
- serial_port_out(port, SCPCR, ctrl);
- } else if (sci_getreg(port, SCSPTR)->size) {
- u16 status = serial_port_in(port, SCSPTR);
+ sci_serial_out(port, SCPDR, data);
+ sci_serial_out(port, SCPCR, ctrl);
+ } else if (sci_getreg(port, SCSPTR)->size && s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE) {
+ u16 status = sci_serial_in(port, SCSPTR);
/* RTS# is always output; and active low, unless autorts */
status |= SCSPTR_RTSIO;
@@ -769,7 +802,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
status &= ~SCSPTR_RTSDT;
/* CTS# and SCK are inputs */
status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
- serial_port_out(port, SCSPTR, status);
+ sci_serial_out(port, SCSPTR, status);
}
}
@@ -781,13 +814,13 @@ static int sci_txfill(struct uart_port *port)
reg = sci_getreg(port, SCTFDR);
if (reg->size)
- return serial_port_in(port, SCTFDR) & fifo_mask;
+ return sci_serial_in(port, SCTFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR);
if (reg->size)
- return serial_port_in(port, SCFDR) >> 8;
+ return sci_serial_in(port, SCFDR) >> 8;
- return !(serial_port_in(port, SCxSR) & SCI_TDRE);
+ return !(sci_serial_in(port, SCxSR) & SCI_TDRE);
}
static int sci_txroom(struct uart_port *port)
@@ -803,13 +836,13 @@ static int sci_rxfill(struct uart_port *port)
reg = sci_getreg(port, SCRFDR);
if (reg->size)
- return serial_port_in(port, SCRFDR) & fifo_mask;
+ return sci_serial_in(port, SCRFDR) & fifo_mask;
reg = sci_getreg(port, SCFDR);
if (reg->size)
- return serial_port_in(port, SCFDR) & fifo_mask;
+ return sci_serial_in(port, SCFDR) & fifo_mask;
- return (serial_port_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+ return (sci_serial_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
}
/* ********************************************************************** *
@@ -818,20 +851,21 @@ static int sci_rxfill(struct uart_port *port)
static void sci_transmit_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned int stopped = uart_tx_stopped(port);
+ struct sci_port *s = to_sci_port(port);
unsigned short status;
unsigned short ctrl;
int count;
- status = serial_port_in(port, SCxSR);
+ status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
- ctrl = serial_port_in(port, SCSCR);
- if (uart_circ_empty(xmit))
+ ctrl = sci_serial_in(port, SCSCR);
+ if (kfifo_is_empty(&tport->xmit_fifo))
ctrl &= ~SCSCR_TIE;
else
ctrl |= SCSCR_TIE;
- serial_port_out(port, SCSCR, ctrl);
+ sci_serial_out(port, SCSCR, ctrl);
return;
}
@@ -843,33 +877,33 @@ static void sci_transmit_chars(struct uart_port *port)
if (port->x_char) {
c = port->x_char;
port->x_char = 0;
- } else if (!uart_circ_empty(xmit) && !stopped) {
- c = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
- ctrl = serial_port_in(port, SCSCR);
- ctrl &= ~SCSCR_TE;
- serial_port_out(port, SCSCR, ctrl);
- return;
- } else {
+ } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
+ if (port->type == PORT_SCI &&
+ kfifo_is_empty(&tport->xmit_fifo)) {
+ ctrl = sci_serial_in(port, SCSCR);
+ ctrl &= ~SCSCR_TE;
+ sci_serial_out(port, SCSCR, ctrl);
+ return;
+ }
break;
}
- serial_port_out(port, SCxTDR, c);
+ sci_serial_out(port, SCxTDR, c);
+ s->tx_occurred = true;
port->icount.tx++;
} while (--count > 0);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
if (port->type == PORT_SCI) {
- ctrl = serial_port_in(port, SCSCR);
+ ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE;
ctrl |= SCSCR_TEIE;
- serial_port_out(port, SCSCR, ctrl);
+ sci_serial_out(port, SCSCR, ctrl);
}
sci_stop_tx(port);
@@ -883,7 +917,7 @@ static void sci_receive_chars(struct uart_port *port)
unsigned short status;
unsigned char flag;
- status = serial_port_in(port, SCxSR);
+ status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_RDxF(port)))
return;
@@ -896,7 +930,7 @@ static void sci_receive_chars(struct uart_port *port)
break;
if (port->type == PORT_SCI) {
- char c = serial_port_in(port, SCxRDR);
+ char c = sci_serial_in(port, SCxRDR);
if (uart_handle_sysrq_char(port, c))
count = 0;
else
@@ -907,11 +941,11 @@ static void sci_receive_chars(struct uart_port *port)
if (port->type == PORT_SCIF ||
port->type == PORT_HSCIF) {
- status = serial_port_in(port, SCxSR);
- c = serial_port_in(port, SCxRDR);
+ status = sci_serial_in(port, SCxSR);
+ c = sci_serial_in(port, SCxRDR);
} else {
- c = serial_port_in(port, SCxRDR);
- status = serial_port_in(port, SCxSR);
+ c = sci_serial_in(port, SCxRDR);
+ status = sci_serial_in(port, SCxSR);
}
if (uart_handle_sysrq_char(port, c)) {
count--; i--;
@@ -932,7 +966,7 @@ static void sci_receive_chars(struct uart_port *port)
}
}
- serial_port_in(port, SCxSR); /* dummy read */
+ sci_serial_in(port, SCxSR); /* dummy read */
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count;
@@ -944,8 +978,8 @@ static void sci_receive_chars(struct uart_port *port)
tty_flip_buffer_push(tport);
} else {
/* TTY buffers full; read from RX reg to prevent lockup */
- serial_port_in(port, SCxRDR);
- serial_port_in(port, SCxSR); /* dummy read */
+ sci_serial_in(port, SCxRDR);
+ sci_serial_in(port, SCxSR); /* dummy read */
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
}
@@ -953,7 +987,7 @@ static void sci_receive_chars(struct uart_port *port)
static int sci_handle_errors(struct uart_port *port)
{
int copied = 0;
- unsigned short status = serial_port_in(port, SCxSR);
+ unsigned short status = sci_serial_in(port, SCxSR);
struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
@@ -1000,10 +1034,10 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
if (!reg->size)
return 0;
- status = serial_port_in(port, s->params->overrun_reg);
+ status = sci_serial_in(port, s->params->overrun_reg);
if (status & s->params->overrun_mask) {
status &= ~s->params->overrun_mask;
- serial_port_out(port, s->params->overrun_reg, status);
+ sci_serial_out(port, s->params->overrun_reg, status);
port->icount.overrun++;
@@ -1018,7 +1052,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
static int sci_handle_breaks(struct uart_port *port)
{
int copied = 0;
- unsigned short status = serial_port_in(port, SCxSR);
+ unsigned short status = sci_serial_in(port, SCxSR);
struct tty_port *tport = &port->state->port;
if (uart_handle_break(port))
@@ -1051,7 +1085,7 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
/* HSCIF can be set to an arbitrary level. */
if (sci_getreg(port, HSRTRGR)->size) {
- serial_port_out(port, HSRTRGR, rx_trig);
+ sci_serial_out(port, HSRTRGR, rx_trig);
return rx_trig;
}
@@ -1092,9 +1126,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
return 1;
}
- serial_port_out(port, SCFCR,
- (serial_port_in(port, SCFCR) &
- ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
+ sci_serial_out(port, SCFCR,
+ (sci_serial_in(port, SCFCR) &
+ ~(SCFCR_RTRG1 | SCFCR_RTRG0)) | bits);
return rx_trig;
}
@@ -1102,9 +1136,9 @@ static int scif_set_rtrg(struct uart_port *port, int rx_trig)
static int scif_rtrg_enabled(struct uart_port *port)
{
if (sci_getreg(port, HSRTRGR)->size)
- return serial_port_in(port, HSRTRGR) != 0;
+ return sci_serial_in(port, HSRTRGR) != 0;
else
- return (serial_port_in(port, SCFCR) &
+ return (sci_serial_in(port, SCFCR) &
(SCFCR_RTRG0 | SCFCR_RTRG1)) != 0;
}
@@ -1200,7 +1234,7 @@ 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;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -1209,18 +1243,20 @@ static void sci_dma_tx_complete(void *arg)
uart_xmit_advance(port, s->tx_dma_len);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (!uart_circ_empty(xmit)) {
+ s->tx_occurred = true;
+
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
s->cookie_tx = 0;
schedule_work(&s->work_tx);
} else {
s->cookie_tx = -EINVAL;
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
- u16 ctrl = serial_port_in(port, SCSCR);
- serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+ u16 ctrl = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR, ctrl & ~SCSCR_TIE);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
/* Switch irq from DMA to SCIF */
dmaengine_pause(s->chan_tx_saved);
@@ -1259,6 +1295,7 @@ static int sci_dma_rx_find_active(struct sci_port *s)
return -1;
}
+/* Must only be called with uart_port_lock taken */
static void sci_dma_rx_chan_invalidate(struct sci_port *s)
{
unsigned int i;
@@ -1272,9 +1309,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s)
static void sci_dma_rx_release(struct sci_port *s)
{
struct dma_chan *chan = s->chan_rx_saved;
+ struct uart_port *port = &s->port;
+ unsigned long flags;
+ uart_port_lock_irqsave(port, &flags);
s->chan_rx_saved = NULL;
sci_dma_rx_chan_invalidate(s);
+ uart_port_unlock_irqrestore(port, flags);
+
dmaengine_terminate_sync(chan);
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
sg_dma_address(&s->sg_rx[0]));
@@ -1296,7 +1338,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
u16 scr;
/* Direct new serial port interrupts back to CPU */
- scr = serial_port_in(port, SCSCR);
+ scr = sci_serial_in(port, SCSCR);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
@@ -1305,7 +1347,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
else
scr &= ~SCSCR_RDRQE;
}
- serial_port_out(port, SCSCR, scr | SCSCR_RIE);
+ sci_serial_out(port, SCSCR, scr | SCSCR_RIE);
}
static void sci_dma_rx_complete(void *arg)
@@ -1320,14 +1362,14 @@ static void sci_dma_rx_complete(void *arg)
dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
s->active_rx);
+ hrtimer_cancel(&s->rx_timer);
+
uart_port_lock_irqsave(port, &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);
- start_hrtimer_us(&s->rx_timer, s->rx_timeout);
-
if (count)
tty_flip_buffer_push(&port->state->port);
@@ -1350,17 +1392,18 @@ static void sci_dma_rx_complete(void *arg)
uart_port_unlock_irqrestore(port, flags);
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
__func__, s->cookie_rx[active], active, s->active_rx);
+
+ start_hrtimer_us(&s->rx_timer, s->rx_timeout);
+
return;
fail:
- uart_port_unlock_irqrestore(port, flags);
- dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
/* Switch to PIO */
- uart_port_lock_irqsave(port, &flags);
dmaengine_terminate_async(chan);
sci_dma_rx_chan_invalidate(s);
sci_dma_rx_reenable_irq(s);
uart_port_unlock_irqrestore(port, flags);
+ dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
}
static void sci_dma_tx_release(struct sci_port *s)
@@ -1425,10 +1468,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
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 tty_port *tport = &port->state->port;
unsigned long flags;
+ unsigned int tail;
dma_addr_t buf;
- int head, tail;
/*
* DMA is idle now.
@@ -1438,10 +1481,9 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
* consistent xmit buffer state.
*/
uart_port_lock_irq(port);
- head = xmit->head;
- tail = xmit->tail;
+ s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
buf = s->tx_dma_addr + tail;
- s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
if (!s->tx_dma_len) {
/* Transmit buffer has been flushed */
uart_port_unlock_irq(port);
@@ -1470,8 +1512,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
}
uart_port_unlock_irq(port);
- dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
- __func__, xmit->buf, tail, head, s->cookie_tx);
+ dev_dbg(port->dev, "%s: %p: %u, cookie %d\n",
+ __func__, tport->xmit_buf, tail, s->cookie_tx);
dma_async_issue_pending(chan);
return;
@@ -1586,6 +1628,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
static void sci_request_dma(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ struct tty_port *tport = &port->state->port;
struct dma_chan *chan;
dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
@@ -1614,7 +1657,7 @@ static void sci_request_dma(struct uart_port *port)
if (chan) {
/* UART circular tx buffer is an aligned page. */
s->tx_dma_addr = dma_map_single(chan->device->dev,
- port->state->xmit.buf,
+ tport->xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
@@ -1623,7 +1666,7 @@ static void sci_request_dma(struct uart_port *port)
} else {
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
__func__, UART_XMIT_SIZE,
- port->state->xmit.buf, &s->tx_dma_addr);
+ tport->xmit_buf, &s->tx_dma_addr);
INIT_WORK(&s->work_tx, sci_dma_tx_work_fn);
s->chan_tx_saved = s->chan_tx = chan;
@@ -1695,6 +1738,19 @@ static void sci_flush_buffer(struct uart_port *port)
s->cookie_tx = -EINVAL;
}
}
+
+static void sci_dma_check_tx_occurred(struct sci_port *s)
+{
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ if (!s->chan_tx)
+ return;
+
+ status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state);
+ if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS)
+ s->tx_occurred = true;
+}
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
static inline void sci_request_dma(struct uart_port *port)
{
@@ -1704,6 +1760,10 @@ static inline void sci_free_dma(struct uart_port *port)
{
}
+static void sci_dma_check_tx_occurred(struct sci_port *s)
+{
+}
+
#define sci_flush_buffer NULL
#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
@@ -1714,8 +1774,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
#ifdef CONFIG_SERIAL_SH_SCI_DMA
if (s->chan_rx) {
- u16 scr = serial_port_in(port, SCSCR);
- u16 ssr = serial_port_in(port, SCxSR);
+ u16 scr = sci_serial_in(port, SCSCR);
+ u16 ssr = sci_serial_in(port, SCxSR);
/* Disable future Rx interrupts */
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB ||
@@ -1733,10 +1793,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
scr &= ~SCSCR_RIE;
}
- serial_port_out(port, SCSCR, scr);
+ sci_serial_out(port, SCSCR, scr);
/* Clear current interrupt */
- serial_port_out(port, SCxSR,
- ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
+ sci_serial_out(port, SCxSR,
+ ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n",
jiffies, s->rx_timeout);
start_hrtimer_us(&s->rx_timer, s->rx_timeout);
@@ -1786,9 +1846,9 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
- ctrl = serial_port_in(port, SCSCR);
+ ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
- serial_port_out(port, SCSCR, ctrl);
+ sci_serial_out(port, SCSCR, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1802,7 +1862,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
sci_handle_breaks(port);
/* drop invalid character received before break was detected */
- serial_port_in(port, SCxRDR);
+ sci_serial_in(port, SCxRDR);
sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
@@ -1816,7 +1876,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (s->irqs[SCIx_ERI_IRQ] == s->irqs[SCIx_BRI_IRQ]) {
/* Break and Error interrupts are muxed */
- unsigned short ssr_status = serial_port_in(port, SCxSR);
+ unsigned short ssr_status = sci_serial_in(port, SCxSR);
/* Break Interrupt */
if (ssr_status & SCxSR_BRK(port))
@@ -1831,7 +1891,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (port->type == PORT_SCI) {
if (sci_handle_errors(port)) {
/* discard character in rx buffer */
- serial_port_in(port, SCxSR);
+ sci_serial_in(port, SCxSR);
sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
@@ -1856,12 +1916,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *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);
+ ssr_status = sci_serial_in(port, SCxSR);
+ scr_status = sci_serial_in(port, SCSCR);
if (s->params->overrun_reg == SCxSR)
orer_status = ssr_status;
else if (sci_getreg(port, s->params->overrun_reg)->size)
- orer_status = serial_port_in(port, s->params->overrun_reg);
+ orer_status = sci_serial_in(port, s->params->overrun_reg);
err_enabled = scr_status & port_rx_irq_mask(port);
@@ -2038,8 +2098,14 @@ static void sci_free_irq(struct sci_port *port)
static unsigned int sci_tx_empty(struct uart_port *port)
{
- unsigned short status = serial_port_in(port, SCxSR);
+ unsigned short status = sci_serial_in(port, SCxSR);
unsigned short in_tx_fifo = sci_txfill(port);
+ struct sci_port *s = to_sci_port(port);
+
+ sci_dma_check_tx_occurred(s);
+
+ if (!s->tx_occurred)
+ return TIOCSER_TEMT;
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
}
@@ -2047,27 +2113,27 @@ static unsigned int sci_tx_empty(struct uart_port *port)
static void sci_set_rts(struct uart_port *port, bool state)
{
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
- u16 data = serial_port_in(port, SCPDR);
+ u16 data = sci_serial_in(port, SCPDR);
/* Active low */
if (state)
data &= ~SCPDR_RTSD;
else
data |= SCPDR_RTSD;
- serial_port_out(port, SCPDR, data);
+ sci_serial_out(port, SCPDR, data);
/* RTS# is output */
- serial_port_out(port, SCPCR,
- serial_port_in(port, SCPCR) | SCPCR_RTSC);
+ sci_serial_out(port, SCPCR,
+ sci_serial_in(port, SCPCR) | SCPCR_RTSC);
} else if (sci_getreg(port, SCSPTR)->size) {
- u16 ctrl = serial_port_in(port, SCSPTR);
+ u16 ctrl = sci_serial_in(port, SCSPTR);
/* Active low */
if (state)
ctrl &= ~SCSPTR_RTSDT;
else
ctrl |= SCSPTR_RTSDT;
- serial_port_out(port, SCSPTR, ctrl);
+ sci_serial_out(port, SCSPTR, ctrl);
}
}
@@ -2075,10 +2141,10 @@ static bool sci_get_cts(struct uart_port *port)
{
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Active low */
- return !(serial_port_in(port, SCPDR) & SCPDR_CTSD);
+ return !(sci_serial_in(port, SCPDR) & SCPDR_CTSD);
} else if (sci_getreg(port, SCSPTR)->size) {
/* Active low */
- return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT);
+ return !(sci_serial_in(port, SCSPTR) & SCSPTR_CTSDT);
}
return true;
@@ -2108,9 +2174,8 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/
reg = sci_getreg(port, SCFCR);
if (reg->size)
- serial_port_out(port, SCFCR,
- serial_port_in(port, SCFCR) |
- SCFCR_LOOP);
+ sci_serial_out(port, SCFCR,
+ sci_serial_in(port, SCFCR) | SCFCR_LOOP);
}
mctrl_gpio_set(s->gpios, mctrl);
@@ -2120,21 +2185,23 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */
- serial_port_out(port, SCFCR,
- serial_port_in(port, SCFCR) & ~SCFCR_MCE);
+ if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ sci_serial_out(port, SCFCR,
+ sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */
sci_set_rts(port, 0);
} else if (s->autorts) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Enable RTS# pin function */
- serial_port_out(port, SCPCR,
- serial_port_in(port, SCPCR) & ~SCPCR_RTSC);
+ sci_serial_out(port, SCPCR,
+ sci_serial_in(port, SCPCR) & ~SCPCR_RTSC);
}
/* Enable Auto RTS */
- serial_port_out(port, SCFCR,
- serial_port_in(port, SCFCR) | SCFCR_MCE);
+ if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ sci_serial_out(port, SCFCR,
+ sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else {
/* Set RTS */
sci_set_rts(port, 1);
@@ -2187,8 +2254,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
}
uart_port_lock_irqsave(port, &flags);
- scsptr = serial_port_in(port, SCSPTR);
- scscr = serial_port_in(port, SCSCR);
+ scsptr = sci_serial_in(port, SCSPTR);
+ scscr = sci_serial_in(port, SCSCR);
if (break_state == -1) {
scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
@@ -2198,8 +2265,8 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
scscr |= SCSCR_TE;
}
- serial_port_out(port, SCSPTR, scsptr);
- serial_port_out(port, SCSCR, scscr);
+ sci_serial_out(port, SCSPTR, scsptr);
+ sci_serial_out(port, SCSCR, scscr);
uart_port_unlock_irqrestore(port, flags);
}
@@ -2210,6 +2277,7 @@ static int sci_startup(struct uart_port *port)
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ s->tx_occurred = false;
sci_request_dma(port);
ret = sci_request_irq(s);
@@ -2239,9 +2307,9 @@ static void sci_shutdown(struct uart_port *port)
* Stop RX and TX, disable related interrupts, keep clock source
* and HSCIF TOT bits
*/
- scr = serial_port_in(port, SCSCR);
- serial_port_out(port, SCSCR, scr &
- (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+ scr = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR,
+ scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2390,19 +2458,19 @@ static void sci_reset(struct uart_port *port)
unsigned int status;
struct sci_port *s = to_sci_port(port);
- serial_port_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */
+ sci_serial_out(port, SCSCR, s->hscif_tot); /* TE=0, RE=0, CKE1=0 */
reg = sci_getreg(port, SCFCR);
if (reg->size)
- serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+ sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
sci_clear_SCxSR(port,
SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
- status = serial_port_in(port, SCLSR);
+ status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
- serial_port_out(port, SCLSR, status);
+ sci_serial_out(port, SCLSR, status);
}
if (s->rx_trigger > 1) {
@@ -2540,8 +2608,8 @@ done:
* It controls the mux to select (H)SCK or frequency divided clock.
*/
if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) {
- serial_port_out(port, SCDL, dl);
- serial_port_out(port, SCCKS, sccks);
+ sci_serial_out(port, SCDL, dl);
+ sci_serial_out(port, SCCKS, sccks);
}
uart_port_lock_irqsave(port, &flags);
@@ -2554,7 +2622,7 @@ done:
bits = tty_get_frame_size(termios->c_cflag);
if (sci_getreg(port, SEMR)->size)
- serial_port_out(port, SEMR, 0);
+ sci_serial_out(port, SEMR, 0);
if (best_clk >= 0) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
@@ -2569,9 +2637,9 @@ done:
case 27: smr_val |= SCSMR_SRC_27; break;
}
smr_val |= cks;
- serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
- serial_port_out(port, SCSMR, smr_val);
- serial_port_out(port, SCBRR, brr);
+ sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
+ sci_serial_out(port, SCSMR, smr_val);
+ sci_serial_out(port, SCBRR, brr);
if (sci_getreg(port, HSSRR)->size) {
unsigned int hssrr = srr | HSCIF_SRE;
/* Calculate deviation from intended rate at the
@@ -2593,7 +2661,7 @@ done:
HSCIF_SRHP_MASK;
hssrr |= HSCIF_SRDE;
}
- serial_port_out(port, HSSRR, hssrr);
+ sci_serial_out(port, HSSRR, hssrr);
}
/* Wait one bit interval */
@@ -2601,10 +2669,10 @@ done:
} else {
/* Don't touch the bit rate configuration */
scr_val = s->cfg->scscr & (SCSCR_CKE1 | SCSCR_CKE0);
- smr_val |= serial_port_in(port, SCSMR) &
+ smr_val |= sci_serial_in(port, SCSMR) &
(SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
- serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
- serial_port_out(port, SCSMR, smr_val);
+ sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
+ sci_serial_out(port, SCSMR, smr_val);
}
sci_init_pins(port, termios->c_cflag);
@@ -2613,7 +2681,7 @@ done:
s->autorts = false;
reg = sci_getreg(port, SCFCR);
if (reg->size) {
- unsigned short ctrl = serial_port_in(port, SCFCR);
+ unsigned short ctrl = sci_serial_in(port, SCFCR);
if ((port->flags & UPF_HARD_FLOW) &&
(termios->c_cflag & CRTSCTS)) {
@@ -2630,7 +2698,7 @@ done:
*/
ctrl &= ~(SCFCR_RFRST | SCFCR_TFRST);
- serial_port_out(port, SCFCR, ctrl);
+ sci_serial_out(port, SCFCR, ctrl);
}
if (port->flags & UPF_HARD_FLOW) {
/* Refresh (Auto) RTS */
@@ -2645,7 +2713,7 @@ done:
if (port->type != PORT_SCI)
scr_val |= SCSCR_TE;
scr_val |= SCSCR_RE | (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0));
- serial_port_out(port, SCSCR, scr_val | s->hscif_tot);
+ sci_serial_out(port, SCSCR, scr_val | s->hscif_tot);
if ((srr + 1 == 5) &&
(port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
/*
@@ -2990,10 +3058,6 @@ static int sci_init_single(struct platform_device *dev,
ret = sci_init_clocks(sci_port, &dev->dev);
if (ret < 0)
return ret;
-
- port->dev = &dev->dev;
-
- pm_runtime_enable(&dev->dev);
}
port->type = p->type;
@@ -3017,17 +3081,9 @@ static int sci_init_single(struct platform_device *dev,
port->irq = sci_port->irqs[SCIx_RXI_IRQ];
port->irqflags = 0;
- port->serial_in = sci_serial_in;
- port->serial_out = sci_serial_out;
-
return 0;
}
-static void sci_cleanup_single(struct sci_port *port)
-{
- pm_runtime_disable(port->port.dev);
-}
-
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3056,21 +3112,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags);
/* first save SCSCR then disable interrupts, keep clock source */
- ctrl = serial_port_in(port, SCSCR);
+ ctrl = sci_serial_in(port, SCSCR);
ctrl_temp = SCSCR_RE | SCSCR_TE |
(sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
(ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
- serial_port_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+ sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
uart_console_write(port, s, count, serial_console_putchar);
/* wait until fifo is empty and last bit has been transmitted */
bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
- while ((serial_port_in(port, SCxSR) & bits) != bits)
+ while ((sci_serial_in(port, SCxSR) & bits) != bits)
cpu_relax();
/* restore the SCSCR */
- serial_port_out(port, SCSCR, ctrl);
+ sci_serial_out(port, SCSCR, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3197,8 +3253,6 @@ static void sci_remove(struct platform_device *dev)
sci_ports_in_use &= ~BIT(port->port.line);
uart_remove_one_port(&sci_uart_driver, &port->port);
- sci_cleanup_single(port);
-
if (port->port.fifosize > 1)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF)
@@ -3224,6 +3278,10 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
.compatible = "renesas,scif-r9a07g044",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
},
+ {
+ .compatible = "renesas,scif-r9a09g057",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ },
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
@@ -3329,7 +3387,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
static int sci_probe_single(struct platform_device *dev,
unsigned int index,
struct plat_sci_port *p,
- struct sci_port *sciport)
+ struct sci_port *sciport,
+ struct resource *sci_res)
{
int ret;
@@ -3358,6 +3417,11 @@ static int sci_probe_single(struct platform_device *dev,
if (ret)
return ret;
+ sciport->port.dev = &dev->dev;
+ ret = devm_pm_runtime_enable(&dev->dev);
+ if (ret)
+ return ret;
+
sciport->gpios = mctrl_gpio_init(&sciport->port, 0);
if (IS_ERR(sciport->gpios))
return PTR_ERR(sciport->gpios);
@@ -3371,18 +3435,37 @@ static int sci_probe_single(struct platform_device *dev,
sciport->port.flags |= UPF_HARD_FLOW;
}
- ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
- if (ret) {
- sci_cleanup_single(sciport);
- return ret;
+ if (sci_uart_earlycon && sci_ports[0].port.mapbase == sci_res->start) {
+ /*
+ * In case:
+ * - this is the earlycon port (mapped on index 0 in sci_ports[]) and
+ * - it now maps to an alias other than zero and
+ * - the earlycon is still alive (e.g., "earlycon keep_bootcon" is
+ * available in bootargs)
+ *
+ * we need to avoid disabling clocks and PM domains through the runtime
+ * PM APIs called in __device_attach(). For this, increment the runtime
+ * PM reference counter (the clocks and PM domains were already enabled
+ * by the bootloader). Otherwise the earlycon may access the HW when it
+ * has no clocks enabled leading to failures (infinite loop in
+ * sci_poll_put_char()).
+ */
+ pm_runtime_get_noresume(&dev->dev);
+
+ /*
+ * Skip cleanup the sci_port[0] in early_console_exit(), this
+ * port is the same as the earlycon one.
+ */
+ sci_uart_earlycon_dev_probing = true;
}
- return 0;
+ return uart_add_one_port(&sci_uart_driver, &sciport->port);
}
static int sci_probe(struct platform_device *dev)
{
struct plat_sci_port *p;
+ struct resource *res;
struct sci_port *sp;
unsigned int dev_id;
int ret;
@@ -3412,9 +3495,29 @@ static int sci_probe(struct platform_device *dev)
}
sp = &sci_ports[dev_id];
+
+ /*
+ * In case:
+ * - the probed port alias is zero (as the one used by earlycon), and
+ * - the earlycon is still active (e.g., "earlycon keep_bootcon" in
+ * bootargs)
+ *
+ * defer the probe of this serial. This is a debug scenario and the user
+ * must be aware of it.
+ *
+ * Except when the probed port is the same as the earlycon port.
+ */
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (sci_uart_earlycon && sp == &sci_ports[0] && sp->port.mapbase != res->start)
+ return dev_err_probe(&dev->dev, -EBUSY, "sci_port[0] is used by earlycon!\n");
+
platform_set_drvdata(dev, sp);
- ret = sci_probe_single(dev, dev_id, p, sp);
+ ret = sci_probe_single(dev, dev_id, p, sp, res);
if (ret)
return ret;
@@ -3467,7 +3570,7 @@ static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
static struct platform_driver sci_driver = {
.probe = sci_probe,
- .remove_new = sci_remove,
+ .remove = sci_remove,
.driver = {
.name = "sh-sci",
.pm = &sci_dev_pm_ops,
@@ -3495,7 +3598,23 @@ sh_early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
-static struct plat_sci_port port_cfg __initdata;
+static struct plat_sci_port port_cfg;
+
+static int early_console_exit(struct console *co)
+{
+ struct sci_port *sci_port = &sci_ports[0];
+
+ /*
+ * Clean the slot used by earlycon. A new SCI device might
+ * map to this slot.
+ */
+ if (!sci_uart_earlycon_dev_probing) {
+ memset(sci_port, 0, sizeof(*sci_port));
+ sci_uart_earlycon = false;
+ }
+
+ return 0;
+}
static int __init early_console_setup(struct earlycon_device *device,
int type)
@@ -3503,18 +3622,19 @@ static int __init early_console_setup(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
- device->port.serial_in = sci_serial_in;
- device->port.serial_out = sci_serial_out;
device->port.type = type;
- memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
+ sci_ports[0].port = device->port;
port_cfg.type = type;
sci_ports[0].cfg = &port_cfg;
sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_uart_earlycon = true;
port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
sci_serial_out(&sci_ports[0].port, SCSCR,
SCSCR_RE | SCSCR_TE | port_cfg.scscr);
device->con->write = serial_console_write;
+ device->con->exit = early_console_exit;
+
return 0;
}
static int __init sci_early_console_setup(struct earlycon_device *device,
@@ -3534,6 +3654,13 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device,
return early_console_setup(device, PORT_SCIF);
}
+static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
+ return early_console_setup(device, PORT_SCIF);
+}
+
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
@@ -3554,6 +3681,7 @@ OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a09g057", rzv2hscif_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);