summaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/sh-sci.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 21:53:25 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-17 21:53:25 +0100
commit96b9b1c95660d4bc5510c5d798d3817ae9f0b391 (patch)
treec34e96557f5c2350e32bb418f5548d4b477940cd /drivers/tty/serial/sh-sci.c
parentMerge tag 'char-misc-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/gi... (diff)
parentserial: 8250: describe CONFIG_SERIAL_8250_RSA (diff)
downloadlinux-96b9b1c95660d4bc5510c5d798d3817ae9f0b391.tar.xz
linux-96b9b1c95660d4bc5510c5d798d3817ae9f0b391.zip
Merge tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH: "Here's the big tty/serial driver pull request for 4.6-rc1. Lots of changes in here, Peter has been on a tear again, with lots of refactoring and bugs fixes, many thanks to the great work he has been doing. Lots of driver updates and fixes as well, full details in the shortlog. All have been in linux-next for a while with no reported issues" * tag 'tty-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (220 commits) serial: 8250: describe CONFIG_SERIAL_8250_RSA serial: samsung: optimize UART rx fifo access routine serial: pl011: add mark/space parity support serial: sa1100: make sa1100_register_uart_fns a function tty: serial: 8250: add MOXA Smartio MUE boards support serial: 8250: convert drivers to use up_to_u8250p() serial: 8250/mediatek: fix building with SERIAL_8250=m serial: 8250/ingenic: fix building with SERIAL_8250=m serial: 8250/uniphier: fix modular build Revert "drivers/tty/serial: make 8250/8250_ingenic.c explicitly non-modular" Revert "drivers/tty/serial: make 8250/8250_mtk.c explicitly non-modular" serial: mvebu-uart: initial support for Armada-3700 serial port serial: mctrl_gpio: Add missing module license serial: ifx6x60: avoid uninitialized variable use tty/serial: at91: fix bad offset for UART timeout register tty/serial: at91: restore dynamic driver binding serial: 8250: Add hardware dependency to RT288X option TTY, devpts: document pty count limiting tty: goldfish: support platform_device with id -1 drivers: tty: goldfish: Add device tree bindings ...
Diffstat (limited to 'drivers/tty/serial/sh-sci.c')
-rw-r--r--drivers/tty/serial/sh-sci.c178
1 files changed, 129 insertions, 49 deletions
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 4646a9f531ad..0130feb069ae 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -84,6 +84,22 @@ enum SCI_CLKS {
SCI_NUM_CLKS
};
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
+ SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
+ SCI_SR(19) | SCI_SR(27)
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+/* Iterate over all supported sampling rates, from high to low */
+#define for_each_sr(_sr, _port) \
+ for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
+ if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
+
struct sci_port {
struct uart_port port;
@@ -93,7 +109,7 @@ struct sci_port {
unsigned int overrun_mask;
unsigned int error_mask;
unsigned int error_clear;
- unsigned int sampling_rate;
+ unsigned int sampling_rate_mask;
resource_size_t reg_size;
/* Break timer */
@@ -637,7 +653,8 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
}
}
-#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
#ifdef CONFIG_CONSOLE_POLL
static int sci_poll_get_char(struct uart_port *port)
@@ -678,7 +695,8 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
serial_port_out(port, SCxTDR, c);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
-#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
+ CONFIG_SERIAL_SH_SCI_EARLYCON */
static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{
@@ -1902,19 +1920,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
unsigned int *srr)
{
unsigned long freq = s->clk_rates[SCI_SCK];
- unsigned int min_sr, max_sr, sr;
int err, min_err = INT_MAX;
+ unsigned int sr;
- if (s->sampling_rate) {
- /* SCI(F) has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
err = DIV_ROUND_CLOSEST(freq, sr) - bps;
if (abs(err) >= abs(min_err))
continue;
@@ -1935,19 +1947,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
unsigned long freq, unsigned int *dlr,
unsigned int *srr)
{
- unsigned int min_sr, max_sr, sr, dl;
int err, min_err = INT_MAX;
+ unsigned int sr, dl;
- if (s->sampling_rate) {
- /* SCIF has a fixed sampling rate */
- min_sr = max_sr = s->sampling_rate / 2;
- } else {
- /* HSCIF has a variable 1/(8..32) sampling rate */
- min_sr = 8;
- max_sr = 32;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
dl = DIV_ROUND_CLOSEST(freq, sr * bps);
dl = clamp(dl, 1U, 65535U);
@@ -1973,19 +1979,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
unsigned int *brr, unsigned int *srr,
unsigned int *cks)
{
- unsigned int min_sr, max_sr, shift, sr, br, prediv, scrate, c;
unsigned long freq = s->clk_rates[SCI_FCK];
+ unsigned int sr, br, prediv, scrate, c;
int err, min_err = INT_MAX;
- if (s->sampling_rate) {
- min_sr = max_sr = s->sampling_rate;
- shift = 0;
- } else {
- /* HSCIF has a variable sample rate */
- min_sr = 8;
- max_sr = 32;
- shift = 1;
- }
+ if (s->port.type != PORT_HSCIF)
+ freq *= 2;
/*
* Find the combination of sample rate and clock select with the
@@ -2002,10 +2001,10 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
* (|D - 0.5| / N * (1 + F))|
* NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
*/
- for (sr = max_sr; sr >= min_sr; sr--) {
+ for_each_sr(sr, s) {
for (c = 0; c <= 3; c++) {
/* integerized formulas from HSCIF documentation */
- prediv = sr * (1 << (2 * c + shift));
+ prediv = sr * (1 << (2 * c + 1));
/*
* We need to calculate:
@@ -2062,7 +2061,7 @@ static void sci_reset(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- unsigned int baud, smr_val = 0, scr_val = 0, i;
+ unsigned int baud, smr_val = SCSMR_ASYNC, scr_val = 0, i;
unsigned int brr = 255, cks = 0, srr = 15, dl = 0, sccks = 0;
unsigned int brr1 = 255, cks1 = 0, srr1 = 15, dl1 = 0;
struct sci_port *s = to_sci_port(port);
@@ -2096,8 +2095,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
for (i = 0; i < SCI_NUM_CLKS; i++)
max_freq = max(max_freq, s->clk_rates[i]);
- baud = uart_get_baud_rate(port, termios, old, 0,
- max_freq / max(s->sampling_rate, 8U));
+ baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
if (!baud)
goto done;
@@ -2185,6 +2183,17 @@ done:
uart_update_timeout(port, termios->c_cflag, baud);
if (best_clk >= 0) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+ switch (srr + 1) {
+ case 5: smr_val |= SCSMR_SRC_5; break;
+ case 7: smr_val |= SCSMR_SRC_7; break;
+ case 11: smr_val |= SCSMR_SRC_11; break;
+ case 13: smr_val |= SCSMR_SRC_13; break;
+ case 16: smr_val |= SCSMR_SRC_16; break;
+ case 17: smr_val |= SCSMR_SRC_17; break;
+ case 19: smr_val |= SCSMR_SRC_19; break;
+ case 27: smr_val |= SCSMR_SRC_27; break;
+ }
smr_val |= cks;
dev_dbg(port->dev,
"SCR 0x%x SMR 0x%x BRR %u CKS 0x%x DL %u SRR %u\n",
@@ -2200,7 +2209,8 @@ 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) & SCSMR_CKS;
+ smr_val |= serial_port_in(port, SCSMR) &
+ (SCSMR_CKEDG | SCSMR_SRC_MASK | SCSMR_CKS);
dev_dbg(port->dev, "SCR 0x%x SMR 0x%x\n", scr_val, smr_val);
serial_port_out(port, SCSCR, scr_val);
serial_port_out(port, SCSMR, smr_val);
@@ -2232,6 +2242,16 @@ done:
scr_val |= s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0);
dev_dbg(port->dev, "SCSCR 0x%x\n", scr_val);
serial_port_out(port, SCSCR, scr_val);
+ if ((srr + 1 == 5) &&
+ (port->type == PORT_SCIFA || port->type == PORT_SCIFB)) {
+ /*
+ * In asynchronous mode, when the sampling rate is 1/5, first
+ * received data may become invalid on some SCIFA and SCIFB.
+ * To avoid this problem wait more than 1 serial data time (1
+ * bit time x serial data number) after setting SCSCR.RE = 1.
+ */
+ udelay(DIV_ROUND_UP(10 * 1000000, baud));
+ }
#ifdef CONFIG_SERIAL_SH_SCI_DMA
/*
@@ -2528,37 +2548,37 @@ static int sci_init_single(struct platform_device *dev,
port->fifosize = 256;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
break;
case PORT_HSCIF:
port->fifosize = 128;
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 0;
+ sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
break;
case PORT_SCIFA:
port->fifosize = 64;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCIFA_ORER;
- sci_port->sampling_rate = 16;
+ sci_port->sampling_rate_mask = SCI_SR_SCIFAB;
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;
+ sci_port->sampling_rate_mask = SCI_SR(16);
} else {
sci_port->overrun_reg = SCLSR;
sci_port->overrun_mask = SCLSR_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
}
break;
default:
port->fifosize = 1;
sci_port->overrun_reg = SCxSR;
sci_port->overrun_mask = SCI_ORER;
- sci_port->sampling_rate = 32;
+ sci_port->sampling_rate_mask = SCI_SR(32);
break;
}
@@ -2567,7 +2587,7 @@ static int sci_init_single(struct platform_device *dev,
* data override the sampling rate for now.
*/
if (p->sampling_rate)
- sci_port->sampling_rate = p->sampling_rate;
+ sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
if (!early) {
ret = sci_init_clocks(sci_port, &dev->dev);
@@ -2632,7 +2652,8 @@ static void sci_cleanup_single(struct sci_port *port)
pm_runtime_disable(port->port.dev);
}
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, int ch)
{
sci_poll_put_char(port, ch);
@@ -2652,9 +2673,12 @@ static void serial_console_write(struct console *co, const char *s,
int locked = 1;
local_irq_save(flags);
+#if defined(SUPPORT_SYSRQ)
if (port->sysrq)
locked = 0;
- else if (oops_in_progress)
+ else
+#endif
+ if (oops_in_progress)
locked = spin_trylock(&port->lock);
else
spin_lock(&port->lock);
@@ -2764,7 +2788,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
#define SCI_CONSOLE NULL
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE || CONFIG_SERIAL_SH_SCI_EARLYCON */
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
@@ -2998,6 +3022,62 @@ static void __exit sci_exit(void)
early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+static struct __init plat_sci_port port_cfg;
+
+static int __init early_console_setup(struct earlycon_device *device,
+ int type)
+{
+ 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].cfg = &port_cfg;
+ sci_ports[0].cfg->type = type;
+ sci_probe_regmap(sci_ports[0].cfg);
+ port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR) |
+ SCSCR_RE | SCSCR_TE;
+ sci_serial_out(&sci_ports[0].port, SCSCR, port_cfg.scscr);
+
+ device->con->write = serial_console_write;
+ return 0;
+}
+static int __init sci_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCI);
+}
+static int __init scif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIF);
+}
+static int __init scifa_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFA);
+}
+static int __init scifb_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_SCIFB);
+}
+static int __init hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ return early_console_setup(device, PORT_HSCIF);
+}
+
+OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_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);
+#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
+
module_init(sci_init);
module_exit(sci_exit);