serial: sh-sci: Use a bitmask to indicate supported sampling rates
[deliverable/linux.git] / drivers / tty / serial / sh-sci.c
index 4646a9f531ad86d654039feda089cdbaf9c5372b..dbf488b9ae27923a523c2450925f846968359227 100644 (file)
@@ -84,6 +84,18 @@ 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 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 +105,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 +649,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 +691,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 +1916,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 +1943,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 +1975,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 +1997,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 +2057,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 +2091,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;
 
@@ -2200,7 +2194,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);
@@ -2528,37 +2523,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(16);
                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(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;
+                       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 +2562,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 +2627,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 +2648,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 +2763,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 +2997,67 @@ 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);
+}
+
+EARLYCON_DECLARE(sci, sci_early_console_setup);
+OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
+EARLYCON_DECLARE(scif, scif_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
+EARLYCON_DECLARE(scifa, scifa_early_console_setup);
+OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
+EARLYCON_DECLARE(scifb, scifb_early_console_setup);
+OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
+EARLYCON_DECLARE(hscif, hscif_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);
 
This page took 0.029568 seconds and 5 git commands to generate.